Skip to content

Commit 36c490c

Browse files
committed
csgrep --warning-rate-limit: stop processing a warning
... if the count of its occurrences exceeds the specified limit Resolves: #119
1 parent 7c3e4a1 commit 36c490c

File tree

7 files changed

+5726
-0
lines changed

7 files changed

+5726
-0
lines changed

src/csgrep.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ int main(int argc, char *argv[])
555555
("drop-scan-props", "do not propagate scan properties")
556556
("embed-context,U", po::value<int>(), "embed a number of lines of context from the source file for the key event")
557557
("prune-events", po::value<int>(), "event is preserved if its verbosity level is below the given number")
558+
("warning-rate-limit", po::value<int>(), "stop processing a warning if the count of its occurrences exceeds the specified limit")
558559
("remove-duplicates,u", "remove defects that are not unique by their key event")
559560
("set-scan-prop", po::value<TStringList>(), "NAME:VALUE pair to override the specified scan property")
560561
("strip-path-prefix", po::value<string>(), "string prefix to strip from path (applied after all filters)")
@@ -658,6 +659,7 @@ int main(int argc, char *argv[])
658659
eng = new DuplicateFilter(eng);
659660

660661
if (!chainDecoratorIntArg<EventPrunner>(&eng, vm, "prune-events")
662+
|| !chainDecoratorIntArg<RateLimitter>(&eng, vm, "warning-rate-limit")
661663
|| !chainDecoratorIntArg<CtxEmbedder>(&eng, vm, "embed-context"))
662664
// error message already printed, eng already feeed
663665
return 1;

src/lib/filter.cc

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,78 @@ bool DuplicateFilter::matchDef(const Defect &def)
203203

204204
return d->lookup.insert(evt)./* inserted */second;
205205
}
206+
207+
208+
// /////////////////////////////////////////////////////////////////////////////
209+
// implementation of RateLimitter
210+
211+
struct RateLimitter::Private {
212+
using TKey = std::pair<std::string, std::string>;
213+
using TCnt = int;
214+
using TMap = std::map<TKey, TCnt>;
215+
TMap counter;
216+
TCnt rateLimit;
217+
};
218+
219+
RateLimitter::RateLimitter(AbstractWriter *agent, int rateLimit):
220+
AbstractFilter(agent),
221+
d(new Private)
222+
{
223+
d->rateLimit = rateLimit;
224+
}
225+
226+
bool RateLimitter::matchDef(const Defect &def)
227+
{
228+
// resolve the checker/event pair for the key event
229+
const DefEvent &evt = def.events[def.keyEventIdx];
230+
const Private::TKey key(def.checker, evt.event);
231+
232+
// increment the counter and get the current value
233+
const Private::TCnt cnt = ++d->counter[key];
234+
235+
// check whether the specified limit is exceeded
236+
return (cnt < d->rateLimit);
237+
}
238+
239+
void RateLimitter::flush()
240+
{
241+
for (const auto &item : d->counter) {
242+
const Private::TCnt cnt = item.second;
243+
if (cnt < d->rateLimit)
244+
// limit not exceeded for this checker/event pair
245+
continue;
246+
247+
// resolve the checker/event pair
248+
const Private::TKey &key = item.first;
249+
const std::string &checker = key.first;
250+
const std::string &keyEvtName = key.second;
251+
252+
// construct an error event
253+
std::ostringstream err, note;
254+
err << cnt << " occurrences of " << keyEvtName
255+
<< " exceeded the specified limit "
256+
<< d->rateLimit;
257+
258+
DefEvent evtErr("error[too-many]");
259+
evtErr.msg = err.str();
260+
261+
// construct a note event
262+
note << (cnt - d->rateLimit) << " occurrences of "
263+
<< keyEvtName << " were discarded because of this";
264+
265+
DefEvent evtNote("note");
266+
evtNote.msg = note.str();
267+
evtNote.verbosityLevel = /* info */ 1;
268+
269+
// construct a defect containing the above events
270+
Defect def(checker);
271+
def.events.push_back(evtErr);
272+
def.events.push_back(evtNote);
273+
274+
// process the newly constructed defect by the chain of writers
275+
GenericAbstractFilter::handleDef(def);
276+
}
277+
278+
// forward the call through the chain of writers
279+
AbstractFilter::flush();
280+
}

src/lib/filter.hh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,19 @@ class DuplicateFilter: public AbstractFilter {
162162
std::unique_ptr<Private> d;
163163
};
164164

165+
/// collapses warnings if their count exceeds the specified limit
166+
class RateLimitter: public AbstractFilter {
167+
public:
168+
RateLimitter(AbstractWriter *agent, int rateLimit);
169+
~RateLimitter() override = default;
170+
void flush() override;
171+
172+
protected:
173+
bool matchDef(const Defect &) override;
174+
175+
private:
176+
struct Private;
177+
std::unique_ptr<Private> d;
178+
};
179+
165180
#endif /* H_GUARD_FILTER_H */
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--mode=json --warning-rate-limit=16

0 commit comments

Comments
 (0)