Static Analyzer Diagnostics: Move the responsibility for generating the endOfPath diagnostic piece from BugReport to BugReporterVisitor. Switch CFRefCount to use visitors in order to generate the endOfPath piece.

llvm-svn: 138184
This commit is contained in:
Anna Zaks 2011-08-20 01:27:22 +00:00
parent 417d566775
commit 88255cc533
5 changed files with 118 additions and 71 deletions

View File

@ -85,8 +85,6 @@ protected:
/// for each bug. /// for each bug.
virtual void Profile(llvm::FoldingSetNodeID& hash) const; virtual void Profile(llvm::FoldingSetNodeID& hash) const;
const Stmt *getStmt() const;
public: public:
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
: BT(bt), Description(desc), ErrorNode(errornode), : BT(bt), Description(desc), ErrorNode(errornode),
@ -121,10 +119,6 @@ public:
return std::make_pair((const char**)0,(const char**)0); return std::make_pair((const char**)0,(const char**)0);
} }
/// Provide custom definition for the last diagnostic piece on the path.
virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N);
/// \brief Return the "definitive" location of the reported bug. /// \brief Return the "definitive" location of the reported bug.
/// ///
/// While a bug can span an entire path, usually there is a specific /// While a bug can span an entire path, usually there is a specific
@ -132,6 +126,8 @@ public:
/// This location is used by clients rendering diagnostics. /// This location is used by clients rendering diagnostics.
virtual SourceLocation getLocation() const; virtual SourceLocation getLocation() const;
const Stmt *getStmt() const;
/// \brief Add a range to a bug report. /// \brief Add a range to a bug report.
/// ///
/// Ranges are used to highlight regions of interest in the source code. /// Ranges are used to highlight regions of interest in the source code.

View File

@ -42,7 +42,23 @@ public:
BugReporterContext &BRC, BugReporterContext &BRC,
BugReport &BR) = 0; BugReport &BR) = 0;
/// \brief Provide custom definition for the final diagnostic piece on the
/// path - the piece, which is displayed before the path is expanded.
///
/// If returns NULL the default implementation will be used.
/// Also note that at most one visitor of a BugReport should generate a
/// non-NULL end of path diagnostic piece.
virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR);
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
/// \brief Generates the default final diagnostic piece.
static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR);
}; };
class FindLastStoreBRVisitor : public BugReporterVisitor { class FindLastStoreBRVisitor : public BugReporterVisitor {

View File

@ -1261,45 +1261,6 @@ const Stmt *BugReport::getStmt() const {
return S; return S;
} }
PathDiagnosticPiece*
BugReport::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode) {
const ProgramPoint &PP = EndPathNode->getLocation();
PathDiagnosticLocation L;
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
const CFGBlock *block = BE->getBlock();
if (block->getBlockID() == 0) {
L = PathDiagnosticLocation(
EndPathNode->getLocationContext()->getDecl()->getBodyRBrace(),
BRC.getSourceManager());
}
}
if (!L.isValid()) {
const Stmt *S = getStmt();
if (!S)
return NULL;
L = PathDiagnosticLocation(S, BRC.getSourceManager());
}
BugReport::ranges_iterator Beg, End;
llvm::tie(Beg, End) = getRanges();
// Only add the statement itself as a range if we didn't specify any
// special ranges for this report.
PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L, getDescription(),
Beg == End);
for (; Beg != End; ++Beg)
P->addRange(*Beg);
return P;
}
std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator> std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator>
BugReport::getRanges() { BugReport::getRanges() {
// If no custom ranges, add the range of the statement corresponding to // If no custom ranges, add the range of the statement corresponding to
@ -1657,15 +1618,28 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
// Start building the path diagnostic... // Start building the path diagnostic...
PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient()); PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient());
if (PathDiagnosticPiece *Piece = R->getEndPath(PDB, N))
PD.push_back(Piece);
else
return;
// Register additional node visitors. // Register additional node visitors.
R->addVisitor(new NilReceiverBRVisitor()); R->addVisitor(new NilReceiverBRVisitor());
R->addVisitor(new ConditionBRVisitor()); R->addVisitor(new ConditionBRVisitor());
// Generate the very last diagnostic piece - the piece is visible before
// the trace is expanded.
PathDiagnosticPiece *LastPiece = 0;
for (BugReport::visitor_iterator I = R->visitor_begin(),
E = R->visitor_end(); I!=E; ++I) {
if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
"There can only be one final piece in a diagnostic.");
LastPiece = Piece;
}
}
if (!LastPiece)
LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
if (LastPiece)
PD.push_back(LastPiece);
else
return;
switch (PDB.getGenerationScheme()) { switch (PDB.getGenerationScheme()) {
case PathDiagnosticClient::Extensive: case PathDiagnosticClient::Extensive:
GenerateExtensivePathDiagnostic(PD, PDB, N); GenerateExtensivePathDiagnostic(PD, PDB, N);

View File

@ -72,6 +72,54 @@ const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Definitions for bug reporter visitors. // Definitions for bug reporter visitors.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
PathDiagnosticPiece*
BugReporterVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
return 0;
}
PathDiagnosticPiece*
BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
const ProgramPoint &PP = EndPathNode->getLocation();
PathDiagnosticLocation L;
if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
const CFGBlock *block = BE->getBlock();
if (block->getBlockID() == 0) {
L = PathDiagnosticLocation(
EndPathNode->getLocationContext()->getDecl()->getBodyRBrace(),
BRC.getSourceManager());
}
}
if (!L.isValid()) {
const Stmt *S = BR.getStmt();
if (!S)
return NULL;
L = PathDiagnosticLocation(S, BRC.getSourceManager());
}
BugReport::ranges_iterator Beg, End;
llvm::tie(Beg, End) = BR.getRanges();
// Only add the statement itself as a range if we didn't specify any
// special ranges for this report.
PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L,
BR.getDescription(),
Beg == End);
for (; Beg != End; ++Beg)
P->addRange(*Beg);
return P;
}
void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0; static int tag = 0;
ID.AddPointer(&tag); ID.AddPointer(&tag);

View File

@ -1960,23 +1960,38 @@ namespace {
//===---------===// //===---------===//
class CFRefReportVisitor : public BugReporterVisitor { class CFRefReportVisitor : public BugReporterVisitor {
protected:
SymbolRef Sym; SymbolRef Sym;
const CFRefCount &TF; const CFRefCount &TF;
public: public:
CFRefReportVisitor(SymbolRef sym, const CFRefCount &tf) CFRefReportVisitor(SymbolRef sym, const CFRefCount &tf)
: Sym(sym), TF(tf) {} : Sym(sym), TF(tf) {}
void Profile(llvm::FoldingSetNodeID &ID) const { virtual void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0; static int x = 0;
ID.AddPointer(&x); ID.AddPointer(&x);
ID.AddPointer(Sym); ID.AddPointer(Sym);
} }
PathDiagnosticPiece *VisitNode(const ExplodedNode *N, virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN, const ExplodedNode *PrevN,
BugReporterContext &BRC, BugReporterContext &BRC,
BugReport &BR); BugReport &BR);
virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR);
};
class CFRefLeakReportVisitor : public CFRefReportVisitor {
public:
CFRefLeakReportVisitor(SymbolRef sym, const CFRefCount &tf)
: CFRefReportVisitor(sym, tf) {}
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR);
}; };
class CFRefReport : public BugReport { class CFRefReport : public BugReport {
@ -1985,9 +2000,10 @@ namespace {
const CFRefCount &TF; const CFRefCount &TF;
public: public:
CFRefReport(CFRefBug& D, const CFRefCount &tf, CFRefReport(CFRefBug& D, const CFRefCount &tf,
ExplodedNode *n, SymbolRef sym) ExplodedNode *n, SymbolRef sym, bool registerVisitor = true)
: BugReport(D, D.getDescription(), n), Sym(sym), TF(tf) { : BugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {
addVisitor(new CFRefReportVisitor(sym, tf)); if (registerVisitor)
addVisitor(new CFRefReportVisitor(sym, tf));
} }
CFRefReport(CFRefBug& D, const CFRefCount &tf, CFRefReport(CFRefBug& D, const CFRefCount &tf,
@ -2011,23 +2027,18 @@ namespace {
SymbolRef getSymbol() const { return Sym; } SymbolRef getSymbol() const { return Sym; }
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N);
std::pair<const char**,const char**> getExtraDescriptiveText(); std::pair<const char**,const char**> getExtraDescriptiveText();
}; };
class CFRefLeakReport : public CFRefReport { class CFRefLeakReport : public CFRefReport {
SourceLocation AllocSite; SourceLocation AllocSite;
const MemRegion* AllocBinding; const MemRegion* AllocBinding;
public: public:
CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
ExplodedNode *n, SymbolRef sym, ExplodedNode *n, SymbolRef sym,
ExprEngine& Eng); ExprEngine& Eng);
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N);
SourceLocation getLocation() const { return AllocSite; } SourceLocation getLocation() const { return AllocSite; }
}; };
} // end anonymous namespace } // end anonymous namespace
@ -2384,17 +2395,19 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
} }
PathDiagnosticPiece* PathDiagnosticPiece*
CFRefReport::getEndPath(BugReporterContext &BRC, CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndN) { const ExplodedNode *EndN,
BugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is // Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc. // assigned to different variables, etc.
BRC.addNotableSymbol(Sym); BRC.addNotableSymbol(Sym);
return BugReport::getEndPath(BRC, EndN); return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
} }
PathDiagnosticPiece* PathDiagnosticPiece*
CFRefLeakReport::getEndPath(BugReporterContext &BRC, CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndN){ const ExplodedNode *EndN,
BugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is // Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc. // assigned to different variables, etc.
@ -2493,7 +2506,7 @@ CFRefLeakReport::getEndPath(BugReporterContext &BRC,
CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
ExplodedNode *n, ExplodedNode *n,
SymbolRef sym, ExprEngine& Eng) SymbolRef sym, ExprEngine& Eng)
: CFRefReport(D, tf, n, sym) { : CFRefReport(D, tf, n, sym, false) {
// Most bug reports are cached at the location where they occurred. // Most bug reports are cached at the location where they occurred.
// With leaks, we want to unique them by the location where they were // With leaks, we want to unique them by the location where they were
@ -2527,7 +2540,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
if (AllocBinding) if (AllocBinding)
os << " and stored into '" << AllocBinding->getString() << '\''; os << " and stored into '" << AllocBinding->getString() << '\'';
addVisitor(new CFRefReportVisitor(sym, tf)); addVisitor(new CFRefLeakReportVisitor(sym, tf));
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//