diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2019-09-09 20:34:40 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2019-09-09 20:34:40 +0000 |
commit | 2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec (patch) | |
tree | 583758bdf33ed6ba3d9780cd37cb30ebf977ee5e /clang/lib/StaticAnalyzer/Core | |
parent | 48453bb8eda3d25b50ab098ebdc33a08724b2e2f (diff) | |
download | bcm5719-llvm-2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec.tar.gz bcm5719-llvm-2f169e7cdd9973d2aa4cba6b0a09126a5e7268ec.zip |
[analyzer] NFC: Introduce sub-classes for path-sensitive and basic reports.
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
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 260 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 135 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 17 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 5 |
4 files changed, 233 insertions, 184 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index f5d747c7fdd..331d7379577 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -71,6 +71,7 @@ using namespace clang; using namespace ento; +using namespace llvm; #define DEBUG_TYPE "BugReporter" @@ -131,7 +132,8 @@ public: public: PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC, - const ExplodedNode *ErrorNode, const BugReport *R); + const ExplodedNode *ErrorNode, + const PathSensitiveBugReport *R); /// \returns the location context associated with the current position in the /// bug path. @@ -202,7 +204,7 @@ class PathDiagnosticBuilder : public BugReporterContext { /// them being the last entities being able to modify it (for example, /// changing interestingness here would cause inconsistencies as to how this /// file and visitors construct diagnostics), hence its const. - const BugReport *R; + const PathSensitiveBugReport *R; /// The leaf of the bug path. This isn't the same as the bug reports error /// node, which refers to the *original* graph, not the bug path. const ExplodedNode *const ErrorNode; @@ -215,12 +217,12 @@ public: /// a PathDiagnosticBuilder able to construct bug reports for different /// consumers. Returns None if no valid report is found. static Optional<PathDiagnosticBuilder> - findValidReport(ArrayRef<BugReport *> &bugReports, + findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports, PathSensitiveBugReporter &Reporter); PathDiagnosticBuilder( BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath, - BugReport *r, const ExplodedNode *ErrorNode, + PathSensitiveBugReport *r, const ExplodedNode *ErrorNode, std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics); /// This function is responsible for generating diagnostic pieces that are @@ -262,7 +264,7 @@ private: ExecutionContinues(llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const; - const BugReport *getBugReport() const { return R; } + const PathSensitiveBugReport *getBugReport() const { return R; } }; } // namespace @@ -369,7 +371,8 @@ static void removeRedundantMsgs(PathPieces &path) { /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it shouldn't be pruned from the parent path. static bool removeUnneededCalls(const PathDiagnosticConstruct &C, - PathPieces &pieces, const BugReport *R, + PathPieces &pieces, + const PathSensitiveBugReport *R, bool IsInteresting = false) { bool containsSomethingInteresting = IsInteresting; const unsigned N = pieces.size(); @@ -1263,13 +1266,23 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode( } static std::unique_ptr<PathDiagnostic> -generateEmptyDiagnosticForReport(const BugReport *R, const SourceManager &SM) { +generateDiagnosticForBasicReport(const BasicBugReport *R) { const BugType &BT = R->getBugType(); return std::make_unique<PathDiagnostic>( - R->getBugType().getCheckName(), R->getDeclWithIssue(), - R->getBugType().getName(), R->getDescription(), - R->getShortDescription(/*UseFallback=*/false), BT.getCategory(), - R->getUniqueingLocation(), R->getUniqueingDecl(), + BT.getCheckName(), R->getDeclWithIssue(), BT.getName(), + R->getDescription(), R->getShortDescription(/*UseFallback=*/false), + BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(), + std::make_unique<FilesToLineNumsMap>()); +} + +static std::unique_ptr<PathDiagnostic> +generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, + const SourceManager &SM) { + const BugType &BT = R->getBugType(); + return std::make_unique<PathDiagnostic>( + BT.getCheckName(), R->getDeclWithIssue(), BT.getName(), + R->getDescription(), R->getShortDescription(/*UseFallback=*/false), + BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(), findExecutedLines(SM, R->getErrorNode())); } @@ -1909,7 +1922,7 @@ static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD) { PathDiagnosticConstruct::PathDiagnosticConstruct( const PathDiagnosticConsumer *PDC, const ExplodedNode *ErrorNode, - const BugReport *R) + const PathSensitiveBugReport *R) : Consumer(PDC), CurrentNode(ErrorNode), SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()), PD(generateEmptyDiagnosticForReport(R, getSourceManager())) { @@ -1918,7 +1931,7 @@ PathDiagnosticConstruct::PathDiagnosticConstruct( PathDiagnosticBuilder::PathDiagnosticBuilder( BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath, - BugReport *r, const ExplodedNode *ErrorNode, + PathSensitiveBugReport *r, const ExplodedNode *ErrorNode, std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics) : BugReporterContext(BRC), BugPath(std::move(BugPath)), R(r), ErrorNode(ErrorNode), @@ -1929,7 +1942,6 @@ PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const { PathDiagnosticConstruct Construct(PDC, ErrorNode, R); const SourceManager &SM = getSourceManager(); - const BugReport *R = getBugReport(); const AnalyzerOptions &Opts = getAnalyzerOptions(); StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription(); @@ -2050,7 +2062,8 @@ void BuiltinBug::anchor() {} // Methods for BugReport and subclasses. //===----------------------------------------------------------------------===// -void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) { +void PathSensitiveBugReport::addVisitor( + std::unique_ptr<BugReporterVisitor> visitor) { if (!visitor) return; @@ -2065,14 +2078,11 @@ void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) { Callbacks.push_back(std::move(visitor)); } -void BugReport::clearVisitors() { +void PathSensitiveBugReport::clearVisitors() { Callbacks.clear(); } -const Decl *BugReport::getDeclWithIssue() const { - if (DeclWithIssue) - return DeclWithIssue; - +const Decl *PathSensitiveBugReport::getDeclWithIssue() const { const ExplodedNode *N = getErrorNode(); if (!N) return nullptr; @@ -2081,14 +2091,28 @@ const Decl *BugReport::getDeclWithIssue() const { return LC->getStackFrame()->getDecl(); } -void BugReport::Profile(llvm::FoldingSetNodeID& hash) const { +void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const { + hash.AddInteger(static_cast<int>(getKind())); + hash.AddPointer(&BT); + hash.AddString(Description); + assert(Location.isValid()); + Location.Profile(hash); + + for (SourceRange range : Ranges) { + if (!range.isValid()) + continue; + hash.AddInteger(range.getBegin().getRawEncoding()); + hash.AddInteger(range.getEnd().getRawEncoding()); + } +} + +void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const { + hash.AddInteger(static_cast<int>(getKind())); hash.AddPointer(&BT); hash.AddString(Description); PathDiagnosticLocation UL = getUniqueingLocation(); if (UL.isValid()) { UL.Profile(hash); - } else if (Location.isValid()) { - Location.Profile(hash); } else { assert(ErrorNode); hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode)); @@ -2131,8 +2155,8 @@ static void insertToInterestingnessMap( "have, if it was already marked as interesting with a different kind!"); } -void BugReport::markInteresting(SymbolRef sym, - bugreporter::TrackingKind TKind) { +void PathSensitiveBugReport::markInteresting(SymbolRef sym, + bugreporter::TrackingKind TKind) { if (!sym) return; @@ -2142,8 +2166,8 @@ void BugReport::markInteresting(SymbolRef sym, markInteresting(meta->getRegion(), TKind); } -void BugReport::markInteresting(const MemRegion *R, - bugreporter::TrackingKind TKind) { +void PathSensitiveBugReport::markInteresting(const MemRegion *R, + bugreporter::TrackingKind TKind) { if (!R) return; @@ -2154,19 +2178,20 @@ void BugReport::markInteresting(const MemRegion *R, markInteresting(SR->getSymbol(), TKind); } -void BugReport::markInteresting(SVal V, bugreporter::TrackingKind TKind) { +void PathSensitiveBugReport::markInteresting(SVal V, + bugreporter::TrackingKind TKind) { markInteresting(V.getAsRegion(), TKind); markInteresting(V.getAsSymbol(), TKind); } -void BugReport::markInteresting(const LocationContext *LC) { +void PathSensitiveBugReport::markInteresting(const LocationContext *LC) { if (!LC) return; InterestingLocationContexts.insert(LC); } Optional<bugreporter::TrackingKind> -BugReport::getInterestingnessKind(SVal V) const { +PathSensitiveBugReport::getInterestingnessKind(SVal V) const { auto RKind = getInterestingnessKind(V.getAsRegion()); auto SKind = getInterestingnessKind(V.getAsSymbol()); if (!RKind) @@ -2191,7 +2216,7 @@ BugReport::getInterestingnessKind(SVal V) const { } Optional<bugreporter::TrackingKind> -BugReport::getInterestingnessKind(SymbolRef sym) const { +PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym) const { if (!sym) return None; // We don't currently consider metadata symbols to be interesting @@ -2203,7 +2228,7 @@ BugReport::getInterestingnessKind(SymbolRef sym) const { } Optional<bugreporter::TrackingKind> -BugReport::getInterestingnessKind(const MemRegion *R) const { +PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const { if (!R) return None; @@ -2217,25 +2242,25 @@ BugReport::getInterestingnessKind(const MemRegion *R) const { return None; } -bool BugReport::isInteresting(SVal V) const { +bool PathSensitiveBugReport::isInteresting(SVal V) const { return getInterestingnessKind(V).hasValue(); } -bool BugReport::isInteresting(SymbolRef sym) const { +bool PathSensitiveBugReport::isInteresting(SymbolRef sym) const { return getInterestingnessKind(sym).hasValue(); } -bool BugReport::isInteresting(const MemRegion *R) const { +bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const { return getInterestingnessKind(R).hasValue(); } -bool BugReport::isInteresting(const LocationContext *LC) const { +bool PathSensitiveBugReport::isInteresting(const LocationContext *LC) const { if (!LC) return false; return InterestingLocationContexts.count(LC); } -const Stmt *BugReport::getStmt() const { +const Stmt *PathSensitiveBugReport::getStmt() const { if (!ErrorNode) return nullptr; @@ -2253,31 +2278,19 @@ const Stmt *BugReport::getStmt() const { return S; } -llvm::iterator_range<BugReport::ranges_iterator> BugReport::getRanges() const { +ArrayRef<SourceRange> +PathSensitiveBugReport::getRanges() const { // If no custom ranges, add the range of the statement corresponding to // the error node. - if (Ranges.empty()) { - if (dyn_cast_or_null<Expr>(getStmt())) - return llvm::make_range(&ErrorNodeRange, &ErrorNodeRange + 1); - return llvm::make_range(ranges_iterator(), ranges_iterator()); - } + if (Ranges.empty() && isa_and_nonnull<Expr>(getStmt())) + return ErrorNodeRange; - // User-specified absence of range info. - if (Ranges.size() == 1 && !Ranges.begin()->isValid()) - return llvm::make_range(ranges_iterator(), ranges_iterator()); - - return llvm::make_range(Ranges.begin(), Ranges.end()); + return Ranges; } -PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { - if (ErrorNode) { - assert(!Location.isValid() && - "Either Location or ErrorNode should be specified but not both."); - return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM); - } - - assert(Location.isValid()); - return Location; +PathDiagnosticLocation +PathSensitiveBugReport::getLocation() const { + return PathDiagnosticLocation::createEndOfPath(ErrorNode); } //===----------------------------------------------------------------------===// @@ -2326,7 +2339,7 @@ namespace { class BugPathInfo { public: std::unique_ptr<ExplodedGraph> BugPath; - BugReport *Report; + PathSensitiveBugReport *Report; const ExplodedNode *ErrorNode; }; @@ -2342,7 +2355,8 @@ class BugPathGetter { /// Since the getErrorNode() or BugReport refers to the original ExplodedGraph, /// we need to pair it to the error node of the constructed trimmed graph. - using ReportNewNodePair = std::pair<BugReport *, const ExplodedNode *>; + using ReportNewNodePair = + std::pair<PathSensitiveBugReport *, const ExplodedNode *>; SmallVector<ReportNewNodePair, 32> ReportNodes; BugPathInfo CurrentBugPath; @@ -2377,7 +2391,7 @@ class BugPathGetter { public: BugPathGetter(const ExplodedGraph *OriginalGraph, - ArrayRef<BugReport *> &bugReports); + ArrayRef<PathSensitiveBugReport *> &bugReports); BugPathInfo *getNextBugPath(); }; @@ -2385,7 +2399,7 @@ public: } // namespace BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, - ArrayRef<BugReport *> &bugReports) { + ArrayRef<PathSensitiveBugReport *> &bugReports) { SmallVector<const ExplodedNode *, 32> Nodes; for (const auto I : bugReports) { assert(I->isValid() && @@ -2404,7 +2418,7 @@ BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph, // in the new graph. llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes; - for (BugReport *Report : bugReports) { + for (PathSensitiveBugReport *Report : bugReports) { const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode()); assert(NewNode && "Failed to construct a trimmed graph that contains this error " @@ -2592,11 +2606,12 @@ static void CompactMacroExpandedPieces(PathPieces &path, /// Notes associated with {@code ErrorNode} are generated using /// {@code getEndPath}, and the rest are generated with {@code VisitNode}. static std::unique_ptr<VisitorsDiagnosticsTy> -generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode, +generateVisitorsDiagnostics(PathSensitiveBugReport *R, + const ExplodedNode *ErrorNode, BugReporterContext &BRC) { std::unique_ptr<VisitorsDiagnosticsTy> Notes = std::make_unique<VisitorsDiagnosticsTy>(); - BugReport::VisitorList visitors; + PathSensitiveBugReport::VisitorList visitors; // Run visitors on all nodes starting from the node *before* the last one. // The last node is reserved for notes generated with {@code getEndPath}. @@ -2646,15 +2661,15 @@ generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode, return Notes; } -Optional<PathDiagnosticBuilder> -PathDiagnosticBuilder::findValidReport(ArrayRef<BugReport *> &bugReports, - PathSensitiveBugReporter &Reporter) { +Optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport( + ArrayRef<PathSensitiveBugReport *> &bugReports, + PathSensitiveBugReporter &Reporter) { BugPathGetter BugGraph(&Reporter.getGraph(), bugReports); while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) { // Find the BugReport with the original location. - BugReport *R = BugPath->Report; + PathSensitiveBugReport *R = BugPath->Report; assert(R && "No original report found for sliced graph."); assert(R->isValid() && "Report selected by trimmed graph marked invalid."); const ExplodedNode *ErrorNode = BugPath->ErrorNode; @@ -2700,7 +2715,7 @@ PathDiagnosticBuilder::findValidReport(ArrayRef<BugReport *> &bugReports, std::unique_ptr<DiagnosticForConsumerMapTy> PathSensitiveBugReporter::generatePathDiagnostics( ArrayRef<PathDiagnosticConsumer *> consumers, - ArrayRef<BugReport *> &bugReports) { + ArrayRef<PathSensitiveBugReport *> &bugReports) { assert(!bugReports.empty()); auto Out = std::make_unique<DiagnosticForConsumerMapTy>(); @@ -2720,24 +2735,7 @@ PathSensitiveBugReporter::generatePathDiagnostics( } void BugReporter::emitReport(std::unique_ptr<BugReport> R) { - if (const ExplodedNode *E = R->getErrorNode()) { - // An error node must either be a sink or have a tag, otherwise - // it could get reclaimed before the path diagnostic is created. - assert((E->isSink() || E->getLocation().getTag()) && - "Error node must either be a sink or have a tag"); - - const AnalysisDeclContext *DeclCtx = - E->getLocationContext()->getAnalysisDeclContext(); - // The source of autosynthesized body can be handcrafted AST or a model - // file. The locations from handcrafted ASTs have no valid source locations - // and have to be discarded. Locations from model files should be preserved - // for processing and reporting. - if (DeclCtx->isBodyAutosynthesized() && - !DeclCtx->isBodyAutosynthesizedFromModelFile()) - return; - } - - bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid(); + bool ValidSourceLoc = R->getLocation().isValid(); assert(ValidSourceLoc); // If we mess up in a release build, we'd still prefer to just drop the bug // instead of trying to go on. @@ -2760,6 +2758,28 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) { EQ->AddReport(std::move(R)); } +void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) { + if (auto PR = dyn_cast<PathSensitiveBugReport>(R.get())) + if (const ExplodedNode *E = PR->getErrorNode()) { + // An error node must either be a sink or have a tag, otherwise + // it could get reclaimed before the path diagnostic is created. + assert((E->isSink() || E->getLocation().getTag()) && + "Error node must either be a sink or have a tag"); + + const AnalysisDeclContext *DeclCtx = + E->getLocationContext()->getAnalysisDeclContext(); + // The source of autosynthesized body can be handcrafted AST or a model + // file. The locations from handcrafted ASTs have no valid source + // locations and have to be discarded. Locations from model files should + // be preserved for processing and reporting. + if (DeclCtx->isBodyAutosynthesized() && + !DeclCtx->isBodyAutosynthesizedFromModelFile()) + return; + } + + BugReporter::emitReport(std::move(R)); +} + //===----------------------------------------------------------------------===// // Emitting reports in equivalence classes. //===----------------------------------------------------------------------===// @@ -2776,9 +2796,8 @@ struct FRIEC_WLItem { } // namespace -static BugReport * -FindReportInEquivalenceClass(BugReportEquivClass& EQ, - SmallVectorImpl<BugReport*> &bugReports) { +BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass( + BugReportEquivClass &EQ, SmallVectorImpl<BugReport *> &bugReports) { BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end(); assert(I != E); const BugType& BT = I->getBugType(); @@ -2789,10 +2808,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, if (!BT.isSuppressOnSink()) { BugReport *R = &*I; for (auto &I : EQ) { - const ExplodedNode *N = I.getErrorNode(); - if (N) { - R = &I; - bugReports.push_back(R); + if (auto *PR = dyn_cast<PathSensitiveBugReport>(&I)) { + R = PR; + bugReports.push_back(PR); } } return R; @@ -2807,19 +2825,20 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, BugReport *exampleReport = nullptr; for (; I != E; ++I) { - const ExplodedNode *errorNode = I->getErrorNode(); - - if (!errorNode) + auto *R = dyn_cast<PathSensitiveBugReport>(&*I); + if (!R) continue; + + const ExplodedNode *errorNode = R->getErrorNode(); if (errorNode->isSink()) { llvm_unreachable( "BugType::isSuppressSink() should not be 'true' for sink end nodes"); } // No successors? By definition this nodes isn't post-dominated by a sink. if (errorNode->succ_empty()) { - bugReports.push_back(&*I); + bugReports.push_back(R); if (!exampleReport) - exampleReport = &*I; + exampleReport = R; continue; } @@ -2852,9 +2871,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, if (Succ->succ_empty()) { // If we found an end-of-path node that is not a sink. if (!Succ->isSink()) { - bugReports.push_back(&*I); + bugReports.push_back(R); if (!exampleReport) - exampleReport = &*I; + exampleReport = R; WL.clear(); break; } @@ -2885,7 +2904,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, void BugReporter::FlushReport(BugReportEquivClass& EQ) { SmallVector<BugReport*, 10> bugReports; - BugReport *report = FindReportInEquivalenceClass(EQ, bugReports); + BugReport *report = findReportInEquivalenceClass(EQ, bugReports); if (!report) return; @@ -2900,7 +2919,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { // If the path is empty, generate a single step path with the location // of the issue. if (PD->path.empty()) { - PathDiagnosticLocation L = report->getLocation(getSourceManager()); + PathDiagnosticLocation L = report->getLocation(); auto piece = std::make_unique<PathDiagnosticEventPiece>( L, report->getDescription()); for (SourceRange Range : report->getRanges()) @@ -3015,16 +3034,24 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) { std::unique_ptr<DiagnosticForConsumerMapTy> BugReporter::generateDiagnosticForConsumerMap( - BugReport *report, ArrayRef<PathDiagnosticConsumer *> consumers, + BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers, ArrayRef<BugReport *> bugReports) { + auto *basicReport = cast<BasicBugReport>(exampleReport); + auto Out = std::make_unique<DiagnosticForConsumerMapTy>(); + for (auto *Consumer : consumers) + (*Out)[Consumer] = generateDiagnosticForBasicReport(basicReport); + return Out; +} - if (!report->isPathSensitive()) { - auto Out = std::make_unique<DiagnosticForConsumerMapTy>(); - for (auto *Consumer : consumers) - (*Out)[Consumer] = generateEmptyDiagnosticForReport(report, - getSourceManager()); - return Out; - } +std::unique_ptr<DiagnosticForConsumerMapTy> +PathSensitiveBugReporter::generateDiagnosticForConsumerMap( + BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers, + ArrayRef<BugReport *> bugReports) { + std::vector<BasicBugReport *> BasicBugReports; + std::vector<PathSensitiveBugReport *> PathSensitiveBugReports; + if (isa<BasicBugReport>(exampleReport)) + return BugReporter::generateDiagnosticForConsumerMap(exampleReport, + consumers, bugReports); // Generate the full path sensitive diagnostic, using the generation scheme // specified by the PathDiagnosticConsumer. Note that we have to generate @@ -3032,8 +3059,13 @@ BugReporter::generateDiagnosticForConsumerMap( // the BugReporterVisitors may mark this bug as a false positive. assert(!bugReports.empty()); MaxBugClassSize.updateMax(bugReports.size()); - std::unique_ptr<DiagnosticForConsumerMapTy> Out = - generatePathDiagnostics(consumers, bugReports); + + // Avoid copying the whole array because there may be a lot of reports. + ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports( + reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()), + reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end())); + std::unique_ptr<DiagnosticForConsumerMapTy> Out = generatePathDiagnostics( + consumers, convertedArrayOfReports); if (Out->empty()) return Out; @@ -3068,7 +3100,7 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, ArrayRef<FixItHint> Fixits) { // 'BT' is owned by BugReporter. BugType *BT = getBugTypeForName(CheckName, name, category); - auto R = std::make_unique<BugReport>(*BT, str, Loc); + auto R = std::make_unique<BasicBugReport>(*BT, str, Loc); R->setDeclWithIssue(DeclWithIssue); for (const auto &SR : Ranges) R->addRange(SR); diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index b223c6fb496..7b26b8fabb9 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -215,7 +215,7 @@ getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) { static bool isVarAnInterestingCondition(const Expr *CondVarExpr, const ExplodedNode *N, - const BugReport *B) { + const PathSensitiveBugReport *B) { // Even if this condition is marked as interesting, it isn't *that* // interesting if it didn't happen in a nested stackframe, the user could just // follow the arrows. @@ -230,7 +230,7 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr, } static bool isInterestingExpr(const Expr *E, const ExplodedNode *N, - const BugReport *B) { + const PathSensitiveBugReport *B) { if (Optional<SVal> V = getSValForVar(E, N)) return B->getInterestingnessKind(*V).hasValue(); return false; @@ -296,19 +296,20 @@ static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest, PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &, const ExplodedNode *, - BugReport &) { + PathSensitiveBugReport &) { return nullptr; } void BugReporterVisitor::finalizeVisitor(BugReporterContext &, - const ExplodedNode *, BugReport &) {} + const ExplodedNode *, + PathSensitiveBugReport &) {} PathDiagnosticPieceRef BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *EndPathNode, - const BugReport &BR) { - PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath( - EndPathNode, BRC.getSourceManager()); + const PathSensitiveBugReport &BR) { + PathDiagnosticLocation L = + PathDiagnosticLocation::createEndOfPath(EndPathNode); const auto &Ranges = BR.getRanges(); @@ -376,7 +377,7 @@ public: PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BR, - BugReport &R) override; + PathSensitiveBugReport &R) override; private: /// Attempts to find the region of interest in a given record decl, @@ -410,10 +411,10 @@ private: /// \return Diagnostics piece for region not modified in the current function, /// if it decides to emit one. PathDiagnosticPieceRef - maybeEmitNote(BugReport &R, const CallEvent &Call, const ExplodedNode *N, - const RegionVector &FieldChain, const MemRegion *MatchedRegion, - StringRef FirstElement, bool FirstIsReferenceType, - unsigned IndirectionLevel); + maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call, + const ExplodedNode *N, const RegionVector &FieldChain, + const MemRegion *MatchedRegion, StringRef FirstElement, + bool FirstIsReferenceType, unsigned IndirectionLevel); /// Pretty-print region \p MatchedRegion to \p os. /// \return Whether printing succeeded. @@ -542,9 +543,9 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord( return None; } -PathDiagnosticPieceRef NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BR, - BugReport &R) { +PathDiagnosticPieceRef +NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BR, + PathSensitiveBugReport &R) { const LocationContext *Ctx = N->getLocationContext(); const StackFrameContext *SCtx = Ctx->getStackFrame(); @@ -656,7 +657,7 @@ static llvm::StringLiteral WillBeUsedForACondition = ", which participates in a condition later"; PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote( - BugReport &R, const CallEvent &Call, const ExplodedNode *N, + PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N, const RegionVector &FieldChain, const MemRegion *MatchedRegion, StringRef FirstElement, bool FirstIsReferenceType, unsigned IndirectionLevel) { @@ -803,7 +804,7 @@ public: PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &BR) override { + PathSensitiveBugReport &BR) override { if (WasModified) return nullptr; @@ -829,7 +830,7 @@ public: static void addMacroVisitorIfNecessary( const ExplodedNode *N, const MemRegion *R, - bool EnableNullFPSuppression, BugReport &BR, + bool EnableNullFPSuppression, PathSensitiveBugReport &BR, const SVal V) { AnalyzerOptions &Options = N->getState()->getAnalysisManager().options; if (EnableNullFPSuppression && @@ -923,7 +924,7 @@ public: /// the statement is a call that was inlined, we add the visitor to the /// bug report, so it can print a note later. static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, - BugReport &BR, + PathSensitiveBugReport &BR, bool InEnableNullFPSuppression, bugreporter::TrackingKind TKind) { if (!CallEvent::isCallStmt(S)) @@ -1003,7 +1004,7 @@ public: PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &BR) { + PathSensitiveBugReport &BR) { // Only print a message at the interesting return statement. if (N->getLocationContext() != CalleeSFC) return nullptr; @@ -1130,10 +1131,8 @@ public: PathDiagnosticPieceRef visitNodeMaybeUnsuppress(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &BR) { -#ifndef NDEBUG + PathSensitiveBugReport &BR) { assert(Options.ShouldAvoidSuppressingNullArgumentPaths); -#endif // Are we at the entry node for this call? Optional<CallEnter> CE = N->getLocationAs<CallEnter>(); @@ -1179,7 +1178,7 @@ public: PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &BR) override { + PathSensitiveBugReport &BR) override { switch (Mode) { case Initial: return visitNodeInitial(N, BRC, BR); @@ -1193,7 +1192,7 @@ public: } void finalizeVisitor(BugReporterContext &, const ExplodedNode *, - BugReport &BR) override { + PathSensitiveBugReport &BR) override { if (EnableNullFPSuppression && ShouldInvalidate) BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC); } @@ -1316,9 +1315,8 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream& os, } /// Show default diagnostics for storing bad region. -static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os, - const MemRegion *R, - SVal V) { +static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &os, + const MemRegion *R, SVal V) { if (V.getAs<loc::ConcreteInt>()) { bool b = false; if (R->isBoundable()) { @@ -1363,7 +1361,8 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os, PathDiagnosticPieceRef FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, - BugReporterContext &BRC, BugReport &BR) { + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { if (Satisfied) return nullptr; @@ -1540,9 +1539,8 @@ bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const { return (bool)N->getState()->assume(Constraint, !Assumption); } -PathDiagnosticPieceRef -TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, BugReport &) { +PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode( + const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) { const ExplodedNode *PrevN = N->getFirstPred(); if (IsSatisfied) return nullptr; @@ -1620,8 +1618,10 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() { return "IDCVisitor"; } -PathDiagnosticPieceRef SuppressInlineDefensiveChecksVisitor::VisitNode( - const ExplodedNode *Succ, BugReporterContext &BRC, BugReport &BR) { +PathDiagnosticPieceRef +SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { const ExplodedNode *Pred = Succ->getFirstPred(); if (IsSatisfied) return nullptr; @@ -1722,7 +1722,7 @@ public: PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &BR) override; + PathSensitiveBugReport &BR) override; }; } // end of anonymous namespace @@ -1778,8 +1778,10 @@ static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) { return false; } -PathDiagnosticPieceRef TrackControlDependencyCondBRVisitor::VisitNode( - const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) { +PathDiagnosticPieceRef +TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { // We can only reason about control dependencies within the same stack frame. if (Origin->getStackFrame() != N->getStackFrame()) return nullptr; @@ -1925,7 +1927,8 @@ static const ExplodedNode* findNodeForExpression(const ExplodedNode *N, } bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode, - const Expr *E, BugReport &report, + const Expr *E, + PathSensitiveBugReport &report, bugreporter::TrackingKind TKind, bool EnableNullFPSuppression) { @@ -2082,9 +2085,9 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S, return nullptr; } -PathDiagnosticPieceRef NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - BugReport &BR) { +PathDiagnosticPieceRef +NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, + PathSensitiveBugReport &BR) { Optional<PreStmt> P = N->getLocationAs<PreStmt>(); if (!P) return nullptr; @@ -2127,9 +2130,9 @@ PathDiagnosticPieceRef NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, /// to make all PathDiagnosticPieces created by this visitor. const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; } -PathDiagnosticPieceRef ConditionBRVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - BugReport &BR) { +PathDiagnosticPieceRef +ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, + PathSensitiveBugReport &BR) { auto piece = VisitNodeImpl(N, BRC, BR); if (piece) { piece->setTag(getTag()); @@ -2141,7 +2144,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitNode(const ExplodedNode *N, PathDiagnosticPieceRef ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, - BugReporterContext &BRC, BugReport &BR) { + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { ProgramPoint ProgPoint = N->getLocation(); const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags = ExprEngine::geteagerlyAssumeBinOpBifurcationTags(); @@ -2179,7 +2183,8 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator( const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk, - const CFGBlock *dstBlk, BugReport &R, BugReporterContext &BRC) { + const CFGBlock *dstBlk, PathSensitiveBugReport &R, + BugReporterContext &BRC) { const Expr *Cond = nullptr; // In the code below, Term is a CFG terminator and Cond is a branch condition @@ -2236,8 +2241,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator( PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, - BugReport &R, const ExplodedNode *N, - bool TookTrue) { + PathSensitiveBugReport &R, + const ExplodedNode *N, bool TookTrue) { ProgramStateRef CurrentState = N->getState(); ProgramStateRef PrevState = N->getFirstPred()->getState(); const LocationContext *LCtx = N->getLocationContext(); @@ -2307,7 +2312,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx, raw_ostream &Out, BugReporterContext &BRC, - BugReport &report, + PathSensitiveBugReport &report, const ExplodedNode *N, Optional<bool> &prunable, bool IsSameFieldName) { @@ -2392,7 +2397,8 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest( const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC, - BugReport &R, const ExplodedNode *N, bool TookTrue, bool IsAssuming) { + PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue, + bool IsAssuming) { bool shouldInvert = false; Optional<bool> shouldPrune; @@ -2511,7 +2517,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest( PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable( StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC, - BugReport &report, const ExplodedNode *N, bool TookTrue) { + PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) { // FIXME: If there's already a constraint tracker for this variable, // we shouldn't emit anything here (c.f. the double note in // test/Analysis/inlining/path-notes.c) @@ -2538,7 +2544,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable( PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest( const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC, - BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) { + PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue, + bool IsAssuming) { const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); if (!VD) return nullptr; @@ -2573,7 +2580,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest( PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest( const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC, - BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) { + PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue, + bool IsAssuming) { SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); @@ -2659,7 +2667,8 @@ bool ConditionBRVisitor::isPieceMessageGeneric( //===----------------------------------------------------------------------===// void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( - BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) { + BugReporterContext &BRC, const ExplodedNode *N, + PathSensitiveBugReport &BR) { // Here we suppress false positives coming from system headers. This list is // based on known issues. const AnalyzerOptions &Options = BRC.getAnalyzerOptions(); @@ -2730,7 +2739,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( // Skip reports within the sys/queue.h macros as we do not have the ability to // reason about data structure shapes. const SourceManager &SM = BRC.getSourceManager(); - FullSourceLoc Loc = BR.getLocation(SM).asLocation(); + FullSourceLoc Loc = BR.getLocation().asLocation(); while (Loc.isMacroID()) { Loc = Loc.getSpellingLoc(); if (SM.getFilename(Loc).endswith("sys/queue.h")) { @@ -2744,9 +2753,9 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( // Implementation of UndefOrNullArgVisitor. //===----------------------------------------------------------------------===// -PathDiagnosticPieceRef UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - BugReport &BR) { +PathDiagnosticPieceRef +UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, + PathSensitiveBugReport &BR) { ProgramStateRef State = N->getState(); ProgramPoint ProgLoc = N->getLocation(); @@ -2802,7 +2811,8 @@ FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor() : Constraints(ConstraintRangeTy::Factory().getEmptyMap()) {} void FalsePositiveRefutationBRVisitor::finalizeVisitor( - BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) { + BugReporterContext &BRC, const ExplodedNode *EndPathNode, + PathSensitiveBugReport &BR) { // Collect new constraints VisitNode(EndPathNode, BRC, BR); @@ -2837,9 +2847,8 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor( BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext()); } -PathDiagnosticPieceRef -FalsePositiveRefutationBRVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &, BugReport &) { +PathDiagnosticPieceRef FalsePositiveRefutationBRVisitor::VisitNode( + const ExplodedNode *N, BugReporterContext &, PathSensitiveBugReport &) { // Collect new constraints const ConstraintRangeTy &NewCs = N->getState()->get<ConstraintRange>(); ConstraintRangeTy::Factory &CF = @@ -2875,7 +2884,7 @@ void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const { PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, - BugReport &R) { + PathSensitiveBugReport &R) { ProgramPoint PP = N->getLocation(); const NoteTag *T = dyn_cast_or_null<NoteTag>(PP.getTag()); if (!T) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index c5a1f9b857e..de23a3ca75f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3004,9 +3004,13 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end()); for (const auto &EQ : EQClasses) { - for (const BugReport &Report : EQ) { - if (Report.getErrorNode()->getState() == N->getState() && - Report.getErrorNode()->getLocation() == N->getLocation()) + for (const BugReport &R : EQ) { + const auto *PR = dyn_cast<PathSensitiveBugReport>(&R); + if (!PR) + continue; + const ExplodedNode *EN = PR->getErrorNode(); + if (EN->getState() == N->getState() && + EN->getLocation() == N->getLocation()) return true; } } @@ -3131,8 +3135,11 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { // Iterate through the reports and get their nodes. for (BugReporter::EQClasses_iterator EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) { - const auto *N = const_cast<ExplodedNode *>(EI->begin()->getErrorNode()); - if (N) Src.push_back(N); + const auto *R = dyn_cast<PathSensitiveBugReport>(&*EI->begin()); + if (!R) + continue; + const auto *N = const_cast<ExplodedNode *>(R->getErrorNode()); + Src.push_back(N); } return DumpGraph(Src, Filename); } else { diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 2d3b50082c7..f049a1c4120 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -850,11 +850,12 @@ const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { } PathDiagnosticLocation - PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, - const SourceManager &SM) { +PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N) { assert(N && "Cannot create a location with a null node."); const Stmt *S = getStmt(N); const LocationContext *LC = N->getLocationContext(); + SourceManager &SM = + N->getState()->getStateManager().getContext().getSourceManager(); if (!S) { // If this is an implicit call, return the implicit call point location. |