Skip to content

Commit 56e241a

Browse files
haoNoQsteakhal
andauthored
[analyzer] Unbreak [[clang::suppress]] on checkers without decl-with-issue. (#79398)
There are currently a few checkers that don't fill in the bug report's "decl-with-issue" field (typically a function in which the bug is found). The new attribute `[[clang::suppress]]` uses decl-with-issue to reduce the size of the suppression source range map so that it didn't need to do that for the entire translation unit. I'm already seeing a few problems with this approach so I'll probably redesign it in some point as it looks like a premature optimization. Not only checkers shouldn't be required to pass decl-with-issue (consider clang-tidy checkers that never had such notion), but also it's not necessarily uniquely determined (consider leak suppressions at allocation site). For now I'm adding a simple stop-gap solution that falls back to building the suppression map for the entire TU whenever decl-with-issue isn't specified. Which won't happen in the default setup because luckily all default checkers do provide decl-with-issue. --------- Co-authored-by: Balazs Benics <[email protected]>
1 parent a03a6e9 commit 56e241a

File tree

5 files changed

+47
-2
lines changed

5 files changed

+47
-2
lines changed

clang/include/clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/SmallVector.h"
2020

2121
namespace clang {
22+
class ASTContext;
2223
class Decl;
2324

2425
namespace ento {
@@ -27,6 +28,8 @@ class PathDiagnosticLocation;
2728

2829
class BugSuppression {
2930
public:
31+
explicit BugSuppression(const ASTContext &ACtx) : ACtx(ACtx) {}
32+
3033
using DiagnosticIdentifierList = llvm::ArrayRef<llvm::StringRef>;
3134

3235
/// Return true if the given bug report was explicitly suppressed by the user.
@@ -45,6 +48,8 @@ class BugSuppression {
4548
llvm::SmallVector<SourceRange, EXPECTED_NUMBER_OF_SUPPRESSIONS>;
4649

4750
llvm::DenseMap<const Decl *, CachedRanges> CachedSuppressionLocations;
51+
52+
const ASTContext &ACtx;
4853
};
4954

5055
} // end namespace ento

clang/lib/StaticAnalyzer/Core/BugReporter.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2467,7 +2467,9 @@ ProgramStateManager &PathSensitiveBugReporter::getStateManager() const {
24672467
return Eng.getStateManager();
24682468
}
24692469

2470-
BugReporter::BugReporter(BugReporterData &d) : D(d) {}
2470+
BugReporter::BugReporter(BugReporterData &D)
2471+
: D(D), UserSuppressions(D.getASTContext()) {}
2472+
24712473
BugReporter::~BugReporter() {
24722474
// Make sure reports are flushed.
24732475
assert(StrBugTypes.empty() &&

clang/lib/StaticAnalyzer/Core/BugSuppression.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,17 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
138138
bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
139139
const Decl *DeclWithIssue,
140140
DiagnosticIdentifierList Hashtags) {
141-
if (!Location.isValid() || DeclWithIssue == nullptr)
141+
if (!Location.isValid())
142142
return false;
143143

144+
if (!DeclWithIssue) {
145+
// FIXME: This defeats the purpose of passing DeclWithIssue to begin with.
146+
// If this branch is ever hit, we're re-doing all the work we've already
147+
// done as well as perform a lot of work we'll never need.
148+
// Gladly, none of our on-by-default checkers currently need it.
149+
DeclWithIssue = ACtx.getTranslationUnitDecl();
150+
}
151+
144152
// While some warnings are attached to AST nodes (mostly path-sensitive
145153
// checks), others are simply associated with a plain source location
146154
// or range. Figuring out the node based on locations can be tricky,

clang/test/Analysis/Checkers/WebKit/call-args.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ namespace simple {
1010
consume_refcntbl(provide());
1111
// expected-warning@-1{{Call argument is uncounted and unsafe}}
1212
}
13+
14+
// Test that the checker works with [[clang::suppress]].
15+
void foo_suppressed() {
16+
[[clang::suppress]]
17+
consume_refcntbl(provide()); // no-warning
18+
}
1319
}
1420

1521
namespace multi_arg {

clang/test/Analysis/copypaste/suspicious-clones.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@ int maxClone(int x, int y, int z) {
2121
return z; // expected-warning{{Potential copy-paste error; did you really mean to use 'z' here?}}
2222
}
2323

24+
// Test that the checker works with [[clang::suppress]].
25+
int max_suppressed(int a, int b) {
26+
log();
27+
if (a > b)
28+
return a;
29+
30+
// This [[clang::suppress]] doesn't suppress anything but we need it here
31+
// because otherwise the other function won't count as a perfect clone.
32+
// FIXME: The checker should probably skip the attribute entirely
33+
// when detecting clones. Otherwise warnings will still get suppressed,
34+
// but for a completely wrong reason.
35+
[[clang::suppress]]
36+
return b; // no-note
37+
}
38+
39+
int maxClone_suppressed(int x, int y, int z) {
40+
log();
41+
if (x > y)
42+
return x;
43+
[[clang::suppress]]
44+
return z; // no-warning
45+
}
46+
47+
2448
// Tests finding a suspicious clone that references global variables.
2549

2650
struct mutex {

0 commit comments

Comments
 (0)