Skip to content

Commit

Permalink
[analyzer] NFC: Introduce sub-classes for path-sensitive and basic re…
Browse files Browse the repository at this point in the history
…ports.

Checkers are now required to specify whether they're creating a
path-sensitive report or a path-insensitive report by constructing an
object of the respective type.

This makes BugReporter more independent from the rest of the Static Analyzer
because all Analyzer-specific code is now in sub-classes.

Differential Revision: https://reviews.llvm.org/D66572

llvm-svn: 371450
  • Loading branch information
haoNoQ committed Sep 9, 2019
1 parent 48453bb commit 2f169e7
Show file tree
Hide file tree
Showing 75 changed files with 784 additions and 590 deletions.
404 changes: 248 additions & 156 deletions clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Stmt;

namespace ento {

class BugReport;
class PathSensitiveBugReport;
class BugReporterContext;
class ExplodedNode;
class MemRegion;
Expand All @@ -60,29 +60,29 @@ class BugReporterVisitor : public llvm::FoldingSetNode {
/// BugReport while processing a node.
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
BugReport &BR) = 0;
PathSensitiveBugReport &BR) = 0;

/// Last function called on the visitor, no further calls to VisitNode
/// would follow.
virtual void finalizeVisitor(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR);
PathSensitiveBugReport &BR);

/// Provide custom definition for the final diagnostic piece on the
/// path - the piece, which is displayed before the path is expanded.
///
/// NOTE that this function can be implemented on at most one used visitor,
/// and otherwise it crahes at runtime.
virtual PathDiagnosticPieceRef
getEndPath(BugReporterContext &BRC, const ExplodedNode *N,
BugReport &BR);
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
PathSensitiveBugReport &BR);

virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;

/// Generates the default final diagnostic piece.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC,
const ExplodedNode *N,
const BugReport &BR);
static PathDiagnosticPieceRef
getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
const PathSensitiveBugReport &BR);
};

namespace bugreporter {
Expand Down Expand Up @@ -111,7 +111,8 @@ enum class TrackingKind {
/// \return Whether or not the function was able to add visitors for this
/// statement. Note that returning \c true does not actually imply
/// that any visitors were added.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
PathSensitiveBugReport &R,
TrackingKind TKind = TrackingKind::Thorough,
bool EnableNullFPSuppression = true);

Expand Down Expand Up @@ -157,7 +158,7 @@ class FindLastStoreBRVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;
};

class TrackConstraintBRVisitor final : public BugReporterVisitor {
Expand All @@ -183,7 +184,7 @@ class TrackConstraintBRVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;

private:
/// Checks if the constraint is valid in the current state.
Expand All @@ -201,7 +202,7 @@ class NilReceiverBRVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;

/// If the statement is a message send expression with nil receiver, returns
/// the receiver expression. Returns NULL otherwise.
Expand All @@ -228,40 +229,42 @@ class ConditionBRVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;

PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
BugReporterContext &BRC, BugReport &BR);
BugReporterContext &BRC,
PathSensitiveBugReport &BR);

PathDiagnosticPieceRef VisitTerminator(const Stmt *Term,
const ExplodedNode *N,
const CFGBlock *SrcBlk,
const CFGBlock *DstBlk, BugReport &R,
BugReporterContext &BRC);
PathDiagnosticPieceRef
VisitTerminator(const Stmt *Term, const ExplodedNode *N,
const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
PathSensitiveBugReport &R, BugReporterContext &BRC);

PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
BugReporterContext &BRC, BugReport &R,
BugReporterContext &BRC,
PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue);

PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
BugReporterContext &BRC, BugReport &R,
BugReporterContext &BRC,
PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue,
bool IsAssuming);

PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
const BinaryOperator *BExpr,
BugReporterContext &BRC, BugReport &R,
const ExplodedNode *N, bool TookTrue,
bool IsAssuming);
PathDiagnosticPieceRef
VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
BugReporterContext &BRC, PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue, bool IsAssuming);

PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
BugReporterContext &BRC, BugReport &R,
BugReporterContext &BRC,
PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue,
bool IsAssuming);

PathDiagnosticPieceRef
VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
BugReporterContext &BRC, BugReport &R,
BugReporterContext &BRC, PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue);

/// Tries to print the value of the given expression.
Expand All @@ -280,7 +283,7 @@ class ConditionBRVisitor final : public BugReporterVisitor {
const Expr *ParentEx,
raw_ostream &Out,
BugReporterContext &BRC,
BugReport &R,
PathSensitiveBugReport &R,
const ExplodedNode *N,
Optional<bool> &prunable,
bool IsSameFieldName);
Expand All @@ -304,12 +307,12 @@ class LikelyFalsePositiveSuppressionBRVisitor final
}

PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
BugReport &) override {
PathSensitiveBugReport &) override {
return nullptr;
}

void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;
};

/// When a region containing undefined value or '0' value is passed
Expand All @@ -332,7 +335,7 @@ class UndefOrNullArgVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;
};

class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
Expand Down Expand Up @@ -361,7 +364,7 @@ class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;
};

/// The bug visitor will walk all the nodes in a path and collect all the
Expand All @@ -379,10 +382,10 @@ class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;

void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
BugReport &BR) override;
PathSensitiveBugReport &BR) override;
};


Expand All @@ -393,7 +396,7 @@ class TagVisitor : public BugReporterVisitor {

PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &R) override;
PathSensitiveBugReport &R) override;
};

} // namespace ento
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,7 @@ class PathDiagnosticLocation {

/// Create a location corresponding to the next valid ExplodedNode as end
/// of path location.
static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
const SourceManager &SM);
static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N);

/// Convert the given location into a single kind location.
static PathDiagnosticLocation createSingleLocation(
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE,
if (!BT)
BT.reset(new BugType(this, "call to main", "example analyzer plugin"));

std::unique_ptr<BugReport> report =
std::make_unique<BugReport>(*BT, BT->getName(), N);
auto report =
std::make_unique<PathSensitiveBugReport>(*BT, BT->getName(), N);
report->addRange(Callee->getSourceRange());
C.emitReport(std::move(report));
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
// reference is outside the range.

// Generate a report for this bug.
auto report = std::make_unique<BugReport>(*BT, BT->getDescription(), N);
auto report =
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);

report->addRange(LoadS->getSourceRange());
C.emitReport(std::move(report));
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ void ArrayBoundCheckerV2::reportOOB(
break;
}

auto BR = std::make_unique<BugReport>(*BT, os.str(), errorNode);
auto BR = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), errorNode);
BR->addVisitor(std::move(Visitor));
checkerContext.emitReport(std::move(BR));
}
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N,
if (!BT)
BT.reset(new APIMisuse(this, "nil argument"));

auto R = std::make_unique<BugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
R->addRange(Range);
bugreporter::trackExpressionValue(N, E, *R);
C.emitReport(std::move(R));
Expand Down Expand Up @@ -520,7 +520,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
if (!BT)
BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));

auto report = std::make_unique<BugReport>(*BT, os.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
C.emitReport(std::move(report));
}
Expand Down Expand Up @@ -575,7 +575,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
OS << "Null pointer argument in call to "
<< cast<FunctionDecl>(Call.getDecl())->getName();

auto report = std::make_unique<BugReport>(BT, OS.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
report->addRange(Call.getArgSourceRange(0));
bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
C.emitReport(std::move(report));
Expand Down Expand Up @@ -635,7 +635,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
"of class '" << Class->getName()
<< "' and not the class directly";

auto report = std::make_unique<BugReport>(*BT, os.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
report->addRange(msg.getSourceRange());
C.emitReport(std::move(report));
}
Expand Down Expand Up @@ -788,7 +788,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ArgTy.print(os, C.getLangOpts());
os << "'";

auto R = std::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
C.emitReport(std::move(R));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
llvm::raw_string_ostream os(msg);
os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
<< "' inside of critical section";
auto R = std::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
auto R = std::make_unique<PathSensitiveBugReport>(*BlockInCritSectionBugType,
os.str(), ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(BlockDescSym);
C.emitReport(std::move(R));
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT)
BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
C.emitReport(std::make_unique<BugReport>(*BT, BT->getDescription(), N));

C.emitReport(
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N));
}
}

Expand Down
12 changes: 7 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
categories::UnixAPI, "Improper arguments"));

// Generate a report for this bug.
auto report = std::make_unique<BugReport>(
auto report = std::make_unique<PathSensitiveBugReport>(
*BT_Overlap, "Arguments must not be overlapping buffers", N);
report->addRange(First->getSourceRange());
report->addRange(Second->getSourceRange());
Expand All @@ -587,7 +587,7 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
"Null pointer argument in call to byte string function"));

BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get());
auto Report = std::make_unique<BugReport>(*BT, WarningMsg, N);
auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
Report->addRange(S->getSourceRange());
if (const auto *Ex = dyn_cast<Expr>(S))
bugreporter::trackExpressionValue(N, Ex, *Report);
Expand All @@ -611,7 +611,7 @@ void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
auto Report = std::make_unique<BugReport>(*BT, WarningMsg, N);
auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
Report->addRange(S->getSourceRange());
C.emitReport(std::move(Report));
}
Expand All @@ -626,7 +626,8 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
"Argument is not a null-terminated string."));

auto Report = std::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);

Report->addRange(S->getSourceRange());
C.emitReport(std::move(Report));
Expand All @@ -648,7 +649,8 @@ void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
"This expression will create a string whose length is too big to "
"be represented as a size_t";

auto Report = std::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
C.emitReport(std::move(Report));
}
}
Expand Down
Loading

0 comments on commit 2f169e7

Please sign in to comment.