Skip to content

Commit

Permalink
[analyzer] NFC: Move getStmt() and createEndOfPath() out of PathDiagn…
Browse files Browse the repository at this point in the history
…ostic.

These static functions deal with ExplodedNodes which is something we don't want
the PathDiagnostic interface to know anything about, as it's planned to be
moved out of libStaticAnalyzerCore.

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

llvm-svn: 371659
  • Loading branch information
haoNoQ committed Sep 11, 2019
1 parent 8535b8e commit 6b85f8e
Show file tree
Hide file tree
Showing 19 changed files with 204 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ class SourceManager;

namespace ento {

class ExplodedNode;
class SymExpr;

using SymbolRef = const SymExpr *;

//===----------------------------------------------------------------------===https://
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===https://
Expand Down Expand Up @@ -276,18 +271,21 @@ class PathDiagnosticLocation {
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
const SourceManager &SM);

/// Create a location corresponding to the given valid ExplodedNode.
/// Create a location corresponding to the given valid ProgramPoint.
static PathDiagnosticLocation create(const ProgramPoint &P,
const SourceManager &SMng);

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

/// Convert the given location into a single kind location.
static PathDiagnosticLocation createSingleLocation(
const PathDiagnosticLocation &PDL);

/// Construct a source location that corresponds to either the beginning
/// or the end of the given statement, or a nearby valid source location
/// if the statement does not have a valid source location of its own.
static SourceLocation
getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
bool UseEndOfStatement = false);

bool operator==(const PathDiagnosticLocation &X) const {
return K == X.K && Loc == X.Loc && Range == X.Range;
}
Expand Down Expand Up @@ -332,13 +330,6 @@ class PathDiagnosticLocation {
void Profile(llvm::FoldingSetNodeID &ID) const;

void dump() const;

/// Given an exploded node, retrieve the statement that should be used
/// for the diagnostic location.
static const Stmt *getStmt(const ExplodedNode *N);

/// Retrieve the statement corresponding to the successor node.
static const Stmt *getNextStmt(const ExplodedNode *N);
};

class PathDiagnosticLocationPair {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,30 @@ class ExplodedNode : public llvm::FoldingSetNode {
/// Trivial nodes may be skipped while printing exploded graph.
bool isTrivial() const;

/// If the node's program point corresponds to a statement, retrieve that
/// statement. Useful for figuring out where to put a warning or a note.
/// If the statement belongs to a body-farmed definition,
/// retrieve the call site for that definition.
const Stmt *getStmtForDiagnostics() const;

/// Find the next statement that was executed on this node's execution path.
/// Useful for explaining control flow that follows the current node.
/// If the statement belongs to a body-farmed definition, retrieve the
/// call site for that definition.
const Stmt *getNextStmtForDiagnostics() const;

/// Find the statement that was executed immediately before this node.
/// Useful when the node corresponds to a CFG block entrance.
/// If the statement belongs to a body-farmed definition, retrieve the
/// call site for that definition.
const Stmt *getPreviousStmtForDiagnostics() const;

/// Find the statement that was executed at or immediately before this node.
/// Useful when any nearby statement will do.
/// If the statement belongs to a body-farmed definition, retrieve the
/// call site for that definition.
const Stmt *getCurrentOrPreviousStmtForDiagnostics() const;

private:
void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode(
if (Satisfied)
return nullptr;

const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ PathDiagnosticPieceRef DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(
return nullptr;

// Retrieve the associated statement.
const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ PathDiagnosticPieceRef DynamicTypePropagation::GenericsBugVisitor::VisitNode(
return nullptr;

// Retrieve the associated statement.
const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ PathDiagnosticPieceRef InnerPointerChecker::InnerPointerBRVisitor::VisitNode(
isSymbolTracked(N->getFirstPred()->getState(), PtrToBuf))
return nullptr;

const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
const Stmt *AllocStmt = AllocNode->getStmtForDiagnostics();

if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
if (!IsLeak)
return nullptr;

PathDiagnosticLocation L =
PathDiagnosticLocation::createEndOfPath(EndPathNode);
PathDiagnosticLocation L = BR.getLocation();
// Do not add the statement itself as a range in case of leak.
return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
false);
Expand Down Expand Up @@ -2332,7 +2331,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
const MemRegion *Region = nullptr;
std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);

const Stmt *AllocationStmt = PathDiagnosticLocation::getStmt(AllocNode);
const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
if (AllocationStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
C.getSourceManager(),
Expand Down Expand Up @@ -2920,7 +2919,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
const RefState *RS = state->get<RegionState>(Sym);
const RefState *RSPrev = statePrev->get<RegionState>(Sym);

const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
// When dealing with containers, we sometimes want to give a note
// even if the statement is missing.
if (!S && (!RS || RS->getAllocationFamily() != AF_InnerBuffer))
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
return nullptr;

// Retrieve the associated statement.
const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
Found = true;
Expand Down Expand Up @@ -401,7 +401,7 @@ ExplodedNode *MoveChecker::reportBug(const MemRegion *Region,
PathDiagnosticLocation LocUsedForUniqueing;
const ExplodedNode *MoveNode = getMoveLocation(N, Region, C);

if (const Stmt *MoveStmt = PathDiagnosticLocation::getStmt(MoveNode))
if (const Stmt *MoveStmt = MoveNode->getStmtForDiagnostics())
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
MoveStmt, C.getSourceManager(), MoveNode->getLocationContext());

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ PathDiagnosticPieceRef NullabilityChecker::NullabilityBugVisitor::VisitNode(
// Retrieve the associated statement.
const Stmt *S = TrackedNullab->getNullabilitySource();
if (!S || S->getBeginLoc().isInvalid()) {
S = PathDiagnosticLocation::getStmt(N);
S = N->getStmtForDiagnostics();
}

if (!S)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
const MemRegion* FirstBinding = AllocI.R;
BR.markInteresting(AllocI.InterestingMethodContext);

// Compute an actual location for the leak. Sometimes a leak doesn't
// occur at an actual statement (e.g., transition between blocks; end
// of function) so we need to walk the graph and compute a real location.
const ExplodedNode *LeakN = EndN;
PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN);
PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath();

std::string sbuf;
llvm::raw_string_ostream os(sbuf);
Expand Down Expand Up @@ -872,7 +868,7 @@ void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
// FIXME: This will crash the analyzer if an allocation comes from an
// implicit call (ex: a destructor call).
// (Currently there are no such allocations in Cocoa, though.)
AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
AllocStmt = AllocNode->getStmtForDiagnostics();

if (!AllocStmt) {
AllocBinding = nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,14 @@ class RefLeakReport : public RefCountReport {
public:
RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n,
SymbolRef sym, CheckerContext &Ctx);

PathDiagnosticLocation getLocation() const override {
assert(Location.isValid());
return Location;
}

PathDiagnosticLocation getEndOfPath() const {
return PathSensitiveBugReport::getLocation();
}
};

} // end namespace retaincountchecker
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/Taint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ PathDiagnosticPieceRef TaintBugVisitor::VisitNode(const ExplodedNode *N,
isTainted(N->getFirstPred()->getState(), V))
return nullptr;

const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
7 changes: 3 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ class ValistChecker : public Checker<check::PreCall, check::PreStmt<VAArgExpr>,
if (!IsLeak)
return nullptr;

PathDiagnosticLocation L =
PathDiagnosticLocation::createEndOfPath(EndPathNode);
PathDiagnosticLocation L = BR.getLocation();
// Do not add the statement itself as a range in case of leak.
return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
false);
Expand Down Expand Up @@ -285,7 +284,7 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
const ExplodedNode *StartNode = getStartCallSite(N, Reg);
PathDiagnosticLocation LocUsedForUniqueing;

if (const Stmt *StartCallStmt = PathDiagnosticLocation::getStmt(StartNode))
if (const Stmt *StartCallStmt = StartNode->getStmtForDiagnostics())
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
StartCallStmt, C.getSourceManager(), StartNode->getLocationContext());

Expand Down Expand Up @@ -381,7 +380,7 @@ PathDiagnosticPieceRef ValistChecker::ValistBugVisitor::VisitNode(
ProgramStateRef State = N->getState();
ProgramStateRef StatePrev = N->getFirstPred()->getState();

const Stmt *S = PathDiagnosticLocation::getStmt(N);
const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;

Expand Down
77 changes: 49 additions & 28 deletions clang/lib/StaticAnalyzer/Core/BugReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,26 +334,6 @@ std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();
}

//===----------------------------------------------------------------------===https://
// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===https://

static const Stmt *GetPreviousStmt(const ExplodedNode *N) {
for (N = N->getFirstPred(); N; N = N->getFirstPred())
if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
return S;

return nullptr;
}

static inline const Stmt*
GetCurrentOrPreviousStmt(const ExplodedNode *N) {
if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
return S;

return GetPreviousStmt(N);
}

//===----------------------------------------------------------------------===https://
// Diagnostic cleanup.
//===----------------------------------------------------------------------===https://
Expand Down Expand Up @@ -593,7 +573,7 @@ static void removePiecesWithInvalidLocations(PathPieces &Pieces) {

PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
const PathDiagnosticConstruct &C) const {
if (const Stmt *S = PathDiagnosticLocation::getNextStmt(C.getCurrentNode()))
if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
return PathDiagnosticLocation(S, getSourceManager(),
C.getCurrLocationContext());

Expand Down Expand Up @@ -888,7 +868,7 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(

case Stmt::GotoStmtClass:
case Stmt::IndirectGotoStmtClass: {
if (const Stmt *S = PathDiagnosticLocation::getNextStmt(C.getCurrentNode()))
if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));
break;
}
Expand Down Expand Up @@ -2177,8 +2157,11 @@ void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {
if (UL.isValid()) {
UL.Profile(hash);
} else {
assert(ErrorNode);
hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode));
// TODO: The statement may be null if the report was emitted before any
// statements were executed. In particular, some checkers by design
// occasionally emit their reports in empty functions (that have no
// statements in their body). Do we profile correctly in this case?
hash.AddPointer(ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
}

for (SourceRange range : Ranges) {
Expand Down Expand Up @@ -2333,10 +2316,10 @@ const Stmt *PathSensitiveBugReport::getStmt() const {
if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
S = GetPreviousStmt(ErrorNode);
S = ErrorNode->getPreviousStmtForDiagnostics();
}
if (!S)
S = PathDiagnosticLocation::getStmt(ErrorNode);
S = ErrorNode->getStmtForDiagnostics();

return S;
}
Expand All @@ -2353,7 +2336,45 @@ PathSensitiveBugReport::getRanges() const {

PathDiagnosticLocation
PathSensitiveBugReport::getLocation() const {
return PathDiagnosticLocation::createEndOfPath(ErrorNode);
assert(ErrorNode && "Cannot create a location with a null node.");
const Stmt *S = ErrorNode->getStmtForDiagnostics();
ProgramPoint P = ErrorNode->getLocation();
const LocationContext *LC = P.getLocationContext();
SourceManager &SM =
ErrorNode->getState()->getStateManager().getContext().getSourceManager();

if (!S) {
// If this is an implicit call, return the implicit call point location.
if (Optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
return PathDiagnosticLocation(PIE->getLocation(), SM);
if (auto FE = P.getAs<FunctionExitPoint>()) {
if (const ReturnStmt *RS = FE->getStmt())
return PathDiagnosticLocation::createBegin(RS, SM, LC);
}
S = ErrorNode->getNextStmtForDiagnostics();
}

if (S) {
// For member expressions, return the location of the '.' or '->'.
if (const auto *ME = dyn_cast<MemberExpr>(S))
return PathDiagnosticLocation::createMemberLoc(ME, SM);

// For binary operators, return the location of the operator.
if (const auto *B = dyn_cast<BinaryOperator>(S))
return PathDiagnosticLocation::createOperatorLoc(B, SM);

if (P.getAs<PostStmtPurgeDeadSymbols>())
return PathDiagnosticLocation::createEnd(S, SM, LC);

if (S->getBeginLoc().isValid())
return PathDiagnosticLocation(S, SM, LC);

return PathDiagnosticLocation(
PathDiagnosticLocation::getValidSourceLocation(S, LC), SM);
}

return PathDiagnosticLocation::createDeclEnd(ErrorNode->getLocationContext(),
SM);
}

//===----------------------------------------------------------------------===https://
Expand Down Expand Up @@ -3070,7 +3091,7 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {
// Inlined function: show signature.
const Decl* D = CE->getCalleeContext()->getDecl();
populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
} else if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) {
} else if (const Stmt *S = N->getStmtForDiagnostics()) {
populateExecutedLinesWithStmt(S, SM, *ExecutedLines);

// Show extra context for some parent kinds.
Expand Down
Loading

0 comments on commit 6b85f8e

Please sign in to comment.