Skip to content

Commit 4aca9b1

Browse files
committed
Expose the name of the checker producing each diagnostic message.
Summary: In clang-tidy we'd like to know the name of the checker producing each diagnostic message. PathDiagnostic has BugType and Category fields, which are both arbitrary human-readable strings, but we need to know the exact name of the checker in the form that can be used in the CheckersControlList option to enable/disable the specific checker. This patch adds the CheckName field to the CheckerBase class, and sets it in the CheckerManager::registerChecker() method, which gets them from the CheckerRegistry. Checkers that implement multiple checks have to store the names of each check in the respective registerXXXChecker method. Reviewers: jordan_rose, krememek Reviewed By: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D2557 llvm-svn: 201186
1 parent 6bd395f commit 4aca9b1

File tree

69 files changed

+629
-453
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+629
-453
lines changed

clang/examples/analyzer-plugin/MainCallChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const
3535
return;
3636

3737
if (!BT)
38-
BT.reset(new BugType("call to main", "example analyzer plugin"));
38+
BT.reset(new BugType(this, "call to main", "example analyzer plugin"));
3939

4040
BugReport *report = new BugReport(*BT, BT->getName(), N);
4141
report->addRange(Callee->getSourceRange());

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
2020
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
2121
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
22+
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
2223
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
2324
#include "llvm/ADT/DenseSet.h"
2425
#include "llvm/ADT/FoldingSet.h"
@@ -463,7 +464,12 @@ class BugReporter {
463464
/// reports.
464465
void emitReport(BugReport *R);
465466

466-
void EmitBasicReport(const Decl *DeclWithIssue,
467+
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
468+
StringRef BugName, StringRef BugCategory,
469+
StringRef BugStr, PathDiagnosticLocation Loc,
470+
ArrayRef<SourceRange> Ranges = None);
471+
472+
void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName,
467473
StringRef BugName, StringRef BugCategory,
468474
StringRef BugStr, PathDiagnosticLocation Loc,
469475
ArrayRef<SourceRange> Ranges = None);
@@ -473,7 +479,8 @@ class BugReporter {
473479

474480
/// \brief Returns a BugType that is associated with the given name and
475481
/// category.
476-
BugType *getBugTypeForName(StringRef name, StringRef category);
482+
BugType *getBugTypeForName(CheckName CheckName, StringRef name,
483+
StringRef category);
477484
};
478485

479486
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/Basic/LLVM.h"
1818
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
19+
#include "clang/StaticAnalyzer/Core/Checker.h"
1920
#include "llvm/ADT/FoldingSet.h"
2021
#include <string>
2122

@@ -29,20 +30,25 @@ class ExprEngine;
2930

3031
class BugType {
3132
private:
33+
const CheckName CheckName;
3234
const std::string Name;
3335
const std::string Category;
3436
bool SuppressonSink;
3537

3638
virtual void anchor();
3739
public:
38-
BugType(StringRef name, StringRef cat)
39-
: Name(name), Category(cat), SuppressonSink(false) {}
40+
BugType(class CheckName Check, StringRef name, StringRef cat)
41+
: CheckName(Check), Name(name), Category(cat), SuppressonSink(false) {}
42+
BugType(const CheckerBase *checker, StringRef name, StringRef cat)
43+
: CheckName(checker->getCheckName()), Name(name), Category(cat),
44+
SuppressonSink(false) {}
4045
virtual ~BugType() {}
4146

4247
// FIXME: Should these be made strings as well?
4348
StringRef getName() const { return Name; }
4449
StringRef getCategory() const { return Category; }
45-
50+
StringRef getCheckName() const { return CheckName.getName(); }
51+
4652
/// isSuppressOnSink - Returns true if bug reports associated with this bug
4753
/// type should be suppressed if the end node of the report is post-dominated
4854
/// by a sink node.
@@ -56,12 +62,17 @@ class BuiltinBug : public BugType {
5662
const std::string desc;
5763
virtual void anchor();
5864
public:
59-
BuiltinBug(const char *name, const char *description)
60-
: BugType(name, categories::LogicError), desc(description) {}
61-
62-
BuiltinBug(const char *name)
63-
: BugType(name, categories::LogicError), desc(name) {}
64-
65+
BuiltinBug(class CheckName CheckName, const char *name,
66+
const char *description)
67+
: BugType(CheckName, name, categories::LogicError), desc(description) {}
68+
69+
BuiltinBug(const CheckerBase *checker, const char *name,
70+
const char *description)
71+
: BugType(checker, name, categories::LogicError), desc(description) {}
72+
73+
BuiltinBug(const CheckerBase *checker, const char *name)
74+
: BugType(checker, name, categories::LogicError), desc(name) {}
75+
6576
StringRef getDescription() const { return desc; }
6677
};
6778

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
710710
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
711711
/// each which represent the pieces of the path.
712712
class PathDiagnostic : public llvm::FoldingSetNode {
713+
std::string CheckName;
713714
const Decl *DeclWithIssue;
714715
std::string BugType;
715716
std::string VerboseDesc;
@@ -730,8 +731,8 @@ class PathDiagnostic : public llvm::FoldingSetNode {
730731

731732
PathDiagnostic() LLVM_DELETED_FUNCTION;
732733
public:
733-
PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
734-
StringRef verboseDesc, StringRef shortDesc,
734+
PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
735+
StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
735736
StringRef category, PathDiagnosticLocation LocationToUnique,
736737
const Decl *DeclToUnique);
737738

@@ -788,6 +789,7 @@ class PathDiagnostic : public llvm::FoldingSetNode {
788789
StringRef getShortDescription() const {
789790
return ShortDesc.empty() ? VerboseDesc : ShortDesc;
790791
}
792+
StringRef getCheckName() const { return CheckName; }
791793
StringRef getBugType() const { return BugType; }
792794
StringRef getCategory() const { return Category; }
793795

clang/include/clang/StaticAnalyzer/Core/Checker.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,14 +453,18 @@ class Call {
453453
} // end eval namespace
454454

455455
class CheckerBase : public ProgramPointTag {
456+
CheckName Name;
457+
friend class ::clang::ento::CheckerManager;
458+
456459
public:
457460
StringRef getTagDescription() const;
461+
CheckName getCheckName() const;
458462

459463
/// See CheckerManager::runCheckersForPrintState.
460464
virtual void printState(raw_ostream &Out, ProgramStateRef State,
461465
const char *NL, const char *Sep) const { }
462466
};
463-
467+
464468
template <typename CHECK1, typename CHECK2=check::_VoidCheck,
465469
typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
466470
typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,

clang/include/clang/StaticAnalyzer/Core/CheckerManager.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace clang {
2929

3030
namespace ento {
3131
class CheckerBase;
32+
class CheckerRegistry;
3233
class ExprEngine;
3334
class AnalysisManager;
3435
class BugReporter;
@@ -131,9 +132,26 @@ enum PointerEscapeKind {
131132
PSK_EscapeOther
132133
};
133134

135+
// This wrapper is used to ensure that only StringRefs originating from the
136+
// CheckerRegistry are used as check names. We want to make sure all check
137+
// name strings have a lifetime that keeps them alive at least until the path
138+
// diagnostics have been processed.
139+
class CheckName {
140+
StringRef Name;
141+
friend class ::clang::ento::CheckerRegistry;
142+
explicit CheckName(StringRef Name) : Name(Name) {}
143+
144+
public:
145+
CheckName() {}
146+
CheckName(const CheckName &Other) : Name(Other.Name) {}
147+
StringRef getName() const { return Name; }
148+
};
149+
134150
class CheckerManager {
135151
const LangOptions LangOpts;
136152
AnalyzerOptionsRef AOptions;
153+
CheckName CurrentCheckName;
154+
137155
public:
138156
CheckerManager(const LangOptions &langOpts,
139157
AnalyzerOptionsRef AOptions)
@@ -142,6 +160,9 @@ class CheckerManager {
142160

143161
~CheckerManager();
144162

163+
void setCurrentCheckName(CheckName name) { CurrentCheckName = name; }
164+
CheckName getCurrentCheckName() const { return CurrentCheckName; }
165+
145166
bool hasPathSensitiveCheckers() const;
146167

147168
void finishedCheckerRegistration();
@@ -168,6 +189,7 @@ class CheckerManager {
168189
return static_cast<CHECKER *>(ref); // already registered.
169190

170191
CHECKER *checker = new CHECKER();
192+
checker->Name = CurrentCheckName;
171193
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
172194
CHECKER::_register(checker, *this);
173195
ref = checker;
@@ -182,6 +204,7 @@ class CheckerManager {
182204
return static_cast<CHECKER *>(ref); // already registered.
183205

184206
CHECKER *checker = new CHECKER(AOpts);
207+
checker->Name = CurrentCheckName;
185208
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
186209
CHECKER::_register(checker, *this);
187210
ref = checker;

clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
112112
<< " | Empty WorkList: "
113113
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
114114

115-
B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics",
115+
B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
116116
output.str(), PathDiagnosticLocation(D, SM));
117117

118118
// Emit warning for each block we bailed out on.
@@ -129,7 +129,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
129129
outputI << "(" << NameOfRootFunction << ")" <<
130130
": The analyzer generated a sink at this point";
131131
B.EmitBasicReport(
132-
D, "Sink Point", "Internal Statistics", outputI.str(),
132+
D, this, "Sink Point", "Internal Statistics", outputI.str(),
133133
PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
134134
}
135135
}

clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
6666
return;
6767

6868
if (!BT)
69-
BT.reset(new BuiltinBug("Out-of-bound array access",
70-
"Access out-of-bound array element (buffer overflow)"));
69+
BT.reset(new BuiltinBug(
70+
this, "Out-of-bound array access",
71+
"Access out-of-bound array element (buffer overflow)"));
7172

7273
// FIXME: It would be nice to eventually make this diagnostic more clear,
7374
// e.g., by referencing the original declaration or by saying *why* this

clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
187187
return;
188188

189189
if (!BT)
190-
BT.reset(new BuiltinBug("Out-of-bound access"));
190+
BT.reset(new BuiltinBug(this, "Out-of-bound access"));
191191

192192
// FIXME: This diagnostics are preliminary. We should get far better
193193
// diagnostics for explaining buffer overruns.
@@ -311,7 +311,6 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
311311
return RegionRawOffsetV2();
312312
}
313313

314-
315314
void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) {
316315
mgr.registerChecker<ArrayBoundCheckerV2>();
317316
}

clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ using namespace ento;
3939
namespace {
4040
class APIMisuse : public BugType {
4141
public:
42-
APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
42+
APIMisuse(const CheckerBase *checker, const char *name)
43+
: BugType(checker, name, "API Misuse (Apple)") {}
4344
};
4445
} // end anonymous namespace
4546

@@ -191,7 +192,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N,
191192
const Expr *E,
192193
CheckerContext &C) const {
193194
if (!BT)
194-
BT.reset(new APIMisuse("nil argument"));
195+
BT.reset(new APIMisuse(this, "nil argument"));
195196

196197
BugReport *R = new BugReport(*BT, Msg, N);
197198
R->addRange(Range);
@@ -483,8 +484,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
483484
<< " bits of the input integer will be lost.";
484485

485486
if (!BT)
486-
BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
487-
487+
BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
488+
488489
BugReport *report = new BugReport(*BT, os.str(), N);
489490
report->addRange(CE->getArg(2)->getSourceRange());
490491
C.emitReport(report);
@@ -522,8 +523,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
522523
Retain = &Ctx.Idents.get("CFRetain");
523524
Release = &Ctx.Idents.get("CFRelease");
524525
MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
525-
BT.reset(
526-
new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
526+
BT.reset(new APIMisuse(
527+
this, "null passed to CFRetain/CFRelease/CFMakeCollectable"));
527528
}
528529

529530
// Check if we called CFRetain/CFRelease/CFMakeCollectable.
@@ -600,9 +601,9 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
600601
CheckerContext &C) const {
601602

602603
if (!BT) {
603-
BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
604-
"instance"));
605-
604+
BT.reset(new APIMisuse(
605+
this, "message incorrectly sent to class instead of class instance"));
606+
606607
ASTContext &Ctx = C.getASTContext();
607608
releaseS = GetNullarySelector("release", Ctx);
608609
retainS = GetNullarySelector("retain", Ctx);
@@ -708,7 +709,8 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
708709
void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
709710
CheckerContext &C) const {
710711
if (!BT) {
711-
BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
712+
BT.reset(new APIMisuse(this,
713+
"Arguments passed to variadic method aren't all "
712714
"Objective-C pointer types"));
713715

714716
ASTContext &Ctx = C.getASTContext();
@@ -1263,6 +1265,7 @@ void ento::registerObjCLoopChecker(CheckerManager &mgr) {
12631265
mgr.registerChecker<ObjCLoopChecker>();
12641266
}
12651267

1266-
void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1268+
void
1269+
ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
12671270
mgr.registerChecker<ObjCNonNilReturnValueChecker>();
12681271
}

0 commit comments

Comments
 (0)