diff options
24 files changed, 318 insertions, 290 deletions
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 5ee52cc615..48393a379b 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -81,15 +81,19 @@ protected: typedef llvm::DenseSet<SymbolRef> Symbols; typedef llvm::DenseSet<const MemRegion *> Regions; - /// A set of symbols that are registered with this report as being + /// A (stack of) a set of symbols that are registered with this + /// report as being "interesting", and thus used to help decide which + /// diagnostics to include when constructing the final path diagnostic. + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + llvm::SmallVector<Symbols *, 2> interestingSymbols; + + /// A (stack of) set of regions that are registered with this report as being /// "interesting", and thus used to help decide which diagnostics /// to include when constructing the final path diagnostic. - Symbols interestingSymbols; - - /// A set of regions that are registered with this report as being - /// "interesting", and thus used to help decide which diagnostics - /// to include when constructing the final path diagnostic. - Regions interestingRegions; + /// The stack is largely used by BugReporter when generating PathDiagnostics + /// for multiple PathDiagnosticConsumers. + llvm::SmallVector<Regions *, 2> interestingRegions; /// A set of custom visitors which generate "event" diagnostics at /// interesting points in the path. @@ -107,6 +111,15 @@ protected: /// when reporting an issue. bool DoNotPrunePath; +private: + // Used internally by BugReporter. + Symbols &getInterestingSymbols(); + Regions &getInterestingRegions(); + + void lazyInitializeInterestingSets(); + void pushInterestingSymbolsAndRegions(); + void popInterestingSymbolsAndRegions(); + public: BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode), @@ -160,9 +173,9 @@ public: void markInteresting(const MemRegion *R); void markInteresting(SVal V); - bool isInteresting(SymbolRef sym) const; - bool isInteresting(const MemRegion *R) const; - bool isInteresting(SVal V) const; + bool isInteresting(SymbolRef sym); + bool isInteresting(const MemRegion *R); + bool isInteresting(SVal V); unsigned getConfigurationChangeToken() const { return ConfigurationChangeToken; @@ -295,7 +308,7 @@ class BugReporterData { public: virtual ~BugReporterData(); virtual DiagnosticsEngine& getDiagnostic() = 0; - virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0; + virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; virtual ASTContext &getASTContext() = 0; virtual SourceManager& getSourceManager() = 0; }; @@ -318,6 +331,12 @@ private: /// Generate and flush the diagnostics for the given bug report. void FlushReport(BugReportEquivClass& EQ); + /// Generate and flush the diagnostics for the given bug report + /// and PathDiagnosticConsumer. + void FlushReport(BugReport *exampleReport, + PathDiagnosticConsumer &PD, + ArrayRef<BugReport*> BugReports); + /// The set of bug reports tracked by the BugReporter. llvm::FoldingSet<BugReportEquivClass> EQClasses; /// A vector of BugReports for tracking the allocated pointers and cleanup. @@ -341,8 +360,8 @@ public: return D.getDiagnostic(); } - PathDiagnosticConsumer* getPathDiagnosticConsumer() { - return D.getPathDiagnosticConsumer(); + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { + return D.getPathDiagnosticConsumers(); } /// \brief Iterator over the set of BugTypes tracked by the BugReporter. @@ -360,7 +379,8 @@ public: SourceManager& getSourceManager() { return D.getSourceManager(); } virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, - SmallVectorImpl<BugReport *> &bugReports) {} + PathDiagnosticConsumer &PC, + ArrayRef<BugReport *> &bugReports) {} void Register(BugType *BT); @@ -421,7 +441,8 @@ public: ProgramStateManager &getStateManager(); virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, - SmallVectorImpl<BugReport*> &bugReports); + PathDiagnosticConsumer &PC, + ArrayRef<BugReport*> &bugReports); /// classof - Used by isa<>, cast<>, and dyn_cast<>. static bool classof(const BugReporter* R) { diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 2e7abfa5cc..cdc9c8318d 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -51,22 +51,25 @@ typedef const SymExpr* SymbolRef; class PathDiagnostic; class PathDiagnosticConsumer { +public: + typedef std::vector<std::pair<StringRef, std::string> > FilesMade; + +private: virtual void anchor(); public: PathDiagnosticConsumer() : flushed(false) {} virtual ~PathDiagnosticConsumer(); - void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); + void FlushDiagnostics(FilesMade *FilesMade); virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) - = 0; + FilesMade *filesMade) = 0; virtual StringRef getName() const = 0; void HandlePathDiagnostic(PathDiagnostic *D); - enum PathGenerationScheme { Minimal, Extensive }; + enum PathGenerationScheme { None, Minimal, Extensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } virtual bool supportsAllBlockEdges() const { return false; } @@ -334,6 +337,8 @@ public: typedef const SourceRange* range_iterator; + ArrayRef<SourceRange> getRanges() const { return ranges; } + range_iterator ranges_begin() const { return ranges.empty() ? NULL : &ranges[0]; } diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h index 65be3a406b..3aab648dc5 100644 --- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H #include <string> +#include <vector> namespace clang { @@ -23,24 +24,25 @@ class Preprocessor; namespace ento { class PathDiagnosticConsumer; +typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers; -PathDiagnosticConsumer* -createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP); +void createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP, - PathDiagnosticConsumer *SubPD = 0); +void createPlistDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createPlistMultiFileDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP); +void createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -PathDiagnosticConsumer* -createTextPathDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP); +void createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP); -} // end GR namespace - -} // end clang namespace +} // end 'ento' namespace +} // end 'clang' namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 1cc53d4423..876196ba4f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -19,6 +19,7 @@ #include "clang/Frontend/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" namespace clang { @@ -32,8 +33,7 @@ class AnalysisManager : public BugReporterData { ASTContext &Ctx; DiagnosticsEngine &Diags; const LangOptions &LangOpts; - - OwningPtr<PathDiagnosticConsumer> PD; + PathDiagnosticConsumers PathConsumers; // Configurable components creators. StoreManagerCreator CreateStoreMgr; @@ -82,8 +82,9 @@ public: bool NoRetryExhausted; public: - AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - const LangOptions &lang, PathDiagnosticConsumer *pd, + AnalysisManager(ASTContext &ctx,DiagnosticsEngine &diags, + const LangOptions &lang, + const PathDiagnosticConsumers &Consumers, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, @@ -99,12 +100,7 @@ public: AnalysisInliningMode inliningMode, bool NoRetry); - /// Construct a clone of the given AnalysisManager with the given ASTContext - /// and DiagnosticsEngine. - AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - AnalysisManager &ParentAM); - - ~AnalysisManager() { FlushDiagnostics(); } + ~AnalysisManager(); void ClearContexts() { AnaCtxMgr.clear(); @@ -140,15 +136,12 @@ public: return LangOpts; } - virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() { - return PD.get(); - } - - void FlushDiagnostics() { - if (PD.get()) - PD->FlushDiagnostics(0); + ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { + return PathConsumers; } + void FlushDiagnostics(); + unsigned getMaxNodes() const { return MaxNodes; } unsigned getMaxVisit() const { return MaxVisit; } diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 5aac6406f6..efeba17a62 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -16,7 +16,7 @@ void AnalysisManager::anchor() { } AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, const LangOptions &lang, - PathDiagnosticConsumer *pd, + const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, @@ -33,7 +33,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnalysisInliningMode IMode, bool NoRetry) : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, /*addInitializers=*/true), - Ctx(ctx), Diags(diags), LangOpts(lang), PD(pd), + Ctx(ctx), Diags(diags), LangOpts(lang), + PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), MaxNodes(maxnodes), MaxVisit(maxvisit), @@ -49,29 +50,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } -AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - AnalysisManager &ParentAM) - : AnaCtxMgr(ParentAM.AnaCtxMgr.getUseUnoptimizedCFG(), - ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors, - ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers), - Ctx(ctx), Diags(diags), - LangOpts(ParentAM.LangOpts), PD(ParentAM.getPathDiagnosticConsumer()), - CreateStoreMgr(ParentAM.CreateStoreMgr), - CreateConstraintMgr(ParentAM.CreateConstraintMgr), - CheckerMgr(ParentAM.CheckerMgr), - MaxNodes(ParentAM.MaxNodes), - MaxVisit(ParentAM.MaxVisit), - VisualizeEGDot(ParentAM.VisualizeEGDot), - VisualizeEGUbi(ParentAM.VisualizeEGUbi), - PurgeDead(ParentAM.PurgeDead), - EagerlyAssume(ParentAM.EagerlyAssume), - TrimGraph(ParentAM.TrimGraph), - EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph), - IPAMode(ParentAM.IPAMode), - InlineMaxStackDepth(ParentAM.InlineMaxStackDepth), - InlineMaxFunctionSize(ParentAM.InlineMaxFunctionSize), - InliningMode(ParentAM.InliningMode), - NoRetryExhausted(ParentAM.NoRetryExhausted) -{ - AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); +AnalysisManager::~AnalysisManager() { + FlushDiagnostics(); + for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), + E = PathConsumers.end(); I != E; ++I) { + delete *I; + } +} + +void AnalysisManager::FlushDiagnostics() { + PathDiagnosticConsumer::FilesMade filesMade; + for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(), + E = PathConsumers.end(); + I != E; ++I) { + (*I)->FlushDiagnostics(&filesMade); + } } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 7ba2fa7fdd..571baecd72 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1345,6 +1345,9 @@ BugReport::~BugReport() { for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I) { delete *I; } + while (!interestingSymbols.empty()) { + popInterestingSymbolsAndRegions(); + } } const Decl *BugReport::getDeclWithIssue() const { @@ -1386,11 +1389,11 @@ void BugReport::markInteresting(SymbolRef sym) { return; // If the symbol wasn't already in our set, note a configuration change. - if (interestingSymbols.insert(sym).second) + if (getInterestingSymbols().insert(sym).second) ++ConfigurationChangeToken; if (const SymbolMetadata *meta = dyn_cast<SymbolMetadata>(sym)) - interestingRegions.insert(meta->getRegion()); + getInterestingRegions().insert(meta->getRegion()); } void BugReport::markInteresting(const MemRegion *R) { @@ -1399,11 +1402,11 @@ void BugReport::markInteresting(const MemRegion *R) { // If the base region wasn't already in our set, note a configuration change. R = R->getBaseRegion(); - if (interestingRegions.insert(R).second) + if (getInterestingRegions().insert(R).second) ++ConfigurationChangeToken; if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) - interestingSymbols.insert(SR->getSymbol()); + getInterestingSymbols().insert(SR->getSymbol()); } void BugReport::markInteresting(SVal V) { @@ -1411,30 +1414,58 @@ void BugReport::markInteresting(SVal V) { markInteresting(V.getAsSymbol()); } -bool BugReport::isInteresting(SVal V) const { +bool BugReport::isInteresting(SVal V) { return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol()); } -bool BugReport::isInteresting(SymbolRef sym) const { +bool BugReport::isInteresting(SymbolRef sym) { if (!sym) return false; // We don't currently consider metadata symbols to be interesting // even if we know their region is interesting. Is that correct behavior? - return interestingSymbols.count(sym); + return getInterestingSymbols().count(sym); } -bool BugReport::isInteresting(const MemRegion *R) const { +bool BugReport::isInteresting(const MemRegion *R) { if (!R) return false; R = R->getBaseRegion(); - bool b = interestingRegions.count(R); + bool b = getInterestingRegions().count(R); if (b) return true; if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) - return interestingSymbols.count(SR->getSymbol()); + return getInterestingSymbols().count(SR->getSymbol()); return false; } - + +void BugReport::lazyInitializeInterestingSets() { + if (interestingSymbols.empty()) { + interestingSymbols.push_back(new Symbols()); + interestingRegions.push_back(new Regions()); + } +} + +BugReport::Symbols &BugReport::getInterestingSymbols() { + lazyInitializeInterestingSets(); + return *interestingSymbols.back(); +} + +BugReport::Regions &BugReport::getInterestingRegions() { + lazyInitializeInterestingSets(); + return *interestingRegions.back(); +} + +void BugReport::pushInterestingSymbolsAndRegions() { + interestingSymbols.push_back(new Symbols(getInterestingSymbols())); + interestingRegions.push_back(new Regions(getInterestingRegions())); +} + +void BugReport::popInterestingSymbolsAndRegions() { + delete interestingSymbols.back(); + interestingSymbols.pop_back(); + delete interestingRegions.back(); + interestingRegions.pop_back(); +} const Stmt *BugReport::getStmt() const { if (!ErrorNode) @@ -1793,12 +1824,13 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { } void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, - SmallVectorImpl<BugReport *> &bugReports) { + PathDiagnosticConsumer &PC, + ArrayRef<BugReport *> &bugReports) { assert(!bugReports.empty()); SmallVector<const ExplodedNode *, 10> errorNodes; - for (SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(), - E = bugReports.end(); I != E; ++I) { + for (ArrayRef<BugReport*>::iterator I = bugReports.begin(), + E = bugReports.end(); I != E; ++I) { errorNodes.push_back((*I)->getErrorNode()); } @@ -1818,8 +1850,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, const ExplodedNode *N = GPair.second.first; // Start building the path diagnostic... - PathDiagnosticBuilder PDB(*this, R, BackMap.get(), - getPathDiagnosticConsumer()); + PathDiagnosticBuilder PDB(*this, R, BackMap.get(), &PC); // Register additional node visitors. R->addVisitor(new NilReceiverBRVisitor()); @@ -1867,6 +1898,8 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, case PathDiagnosticConsumer::Minimal: GenerateMinimalPathDiagnostic(PD, PDB, N, visitors); break; + case PathDiagnosticConsumer::None: + llvm_unreachable("PathDiagnosticConsumer::None should never appear here"); } // Clean up the visitors we used. @@ -2022,53 +2055,21 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ, return exampleReport; } -//===----------------------------------------------------------------------===// -// DiagnosticCache. This is a hack to cache analyzer diagnostics. It -// uses global state, which eventually should go elsewhere. -//===----------------------------------------------------------------------===// -namespace { -class DiagCacheItem : public llvm::FoldingSetNode { - llvm::FoldingSetNodeID ID; -public: - DiagCacheItem(BugReport *R, PathDiagnostic *PD) { - R->Profile(ID); - PD->Profile(ID); - } - - void Profile(llvm::FoldingSetNodeID &id) { - id = ID; - } - - llvm::FoldingSetNodeID &getID() { return ID; } -}; -} - -static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) { - // FIXME: Eventually this diagnostic cache should reside in something - // like AnalysisManager instead of being a static variable. This is - // really unsafe in the long term. - typedef llvm::FoldingSet<DiagCacheItem> DiagnosticCache; - static DiagnosticCache DC; - - void *InsertPos; - DiagCacheItem *Item = new DiagCacheItem(R, PD); - - if (DC.FindNodeOrInsertPos(Item->getID(), InsertPos)) { - delete Item; - return true; - } - - DC.InsertNode(Item, InsertPos); - return false; -} - void BugReporter::FlushReport(BugReportEquivClass& EQ) { SmallVector<BugReport*, 10> bugReports; BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports); - if (!exampleReport) - return; - - PathDiagnosticConsumer* PD = getPathDiagnosticConsumer(); + if (exampleReport) { + const PathDiagnosticConsumers &C = getPathDiagnosticConsumers(); + for (PathDiagnosticConsumers::const_iterator I=C.begin(), + E=C.end(); I != E; ++I) { + FlushReport(exampleReport, **I, bugReports); + } + } +} + +void BugReporter::FlushReport(BugReport *exampleReport, + PathDiagnosticConsumer &PD, + ArrayRef<BugReport*> bugReports) { // FIXME: Make sure we use the 'R' for the path that was actually used. // Probably doesn't make a difference in practice. @@ -2077,65 +2078,39 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { OwningPtr<PathDiagnostic> D(new PathDiagnostic(exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), - !PD || PD->useVerboseDescription() + PD.useVerboseDescription() ? exampleReport->getDescription() : exampleReport->getShortDescription(), BT.getCategory())); - if (!bugReports.empty()) - GeneratePathDiagnostic(*D.get(), bugReports); - - // Get the meta data. - const BugReport::ExtraTextList &Meta = - exampleReport->getExtraText(); - for (BugReport::ExtraTextList::const_iterator i = Meta.begin(), - e = Meta.end(); i != e; ++i) { - D->addMeta(*i); - } - - // Emit a summary diagnostic to the regular Diagnostics engine. - BugReport::ranges_iterator Beg, End; - llvm::tie(Beg, End) = exampleReport->getRanges(); - DiagnosticsEngine &Diag = getDiagnostic(); - - if (!IsCachedDiagnostic(exampleReport, D.get())) { - // Search the description for '%', as that will be interpretted as a - // format character by FormatDiagnostics. - StringRef desc = exampleReport->getShortDescription(); - - SmallString<512> TmpStr; - llvm::raw_svector_ostream Out(TmpStr); - for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { - if (*I == '%') - Out << "%%"; - else - Out << *I; - } - - Out.flush(); - unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr); - - DiagnosticBuilder diagBuilder = Diag.Report( - exampleReport->getLocation(getSourceManager()).asLocation(), ErrorDiag); - for (BugReport::ranges_iterator I = Beg; I != End; ++I) - diagBuilder << *I; + // Generate the full path diagnostic, using the generation scheme + // specified by the PathDiagnosticConsumer. + if (PD.getGenerationScheme() != PathDiagnosticConsumer::None) { + if (!bugReports.empty()) + GeneratePathDiagnostic(*D.get(), PD, bugReports); } - // Emit a full diagnostic for the path if we have a PathDiagnosticConsumer. - if (!PD) - return; - + // If the path is empty, generate a single step path with the location + // of the issue. if (D->path.empty()) { - PathDiagnosticPiece *piece = new PathDiagnosticEventPiece( - exampleReport->getLocation(getSourceManager()), - exampleReport->getDescription()); + PathDiagnosticLocation L = exampleReport->getLocation(getSourceManager()); + PathDiagnosticPiece *piece = + new PathDiagnosticEventPiece(L, exampleReport->getDescription()); + BugReport::ranges_iterator Beg, End; + llvm::tie(Beg, End) = exampleReport->getRanges(); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); - D->getActivePath().push_back(piece); } - PD->HandlePathDiagnostic(D.take()); + // Get the meta data. + const BugReport::ExtraTextList &Meta = exampleReport->getExtraText(); + for (BugReport::ExtraTextList::const_iterator i = Meta.begin(), + e = Meta.end(); i != e; ++i) { + D->addMeta(*i); + } + + PD.HandlePathDiagnostic(D.take()); } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 0152e328e5..995135f260 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -45,7 +45,7 @@ public: virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); virtual StringRef getName() const { return "HTMLDiagnostics"; @@ -63,7 +63,7 @@ public: const char *HighlightEnd = "</span>"); void ReportDiag(const PathDiagnostic& D, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); }; } // end anonymous namespace @@ -76,10 +76,10 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, FilePrefix.appendComponent("report"); } -PathDiagnosticConsumer* -ento::createHTMLDiagnosticConsumer(const std::string& prefix, - const Preprocessor &PP) { - return new HTMLDiagnostics(prefix, PP); +void ento::createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C, + const std::string& prefix, + const Preprocessor &PP) { + C.push_back(new HTMLDiagnostics(prefix, PP)); } //===----------------------------------------------------------------------===// @@ -88,15 +88,15 @@ ento::createHTMLDiagnosticConsumer(const std::string& prefix, void HTMLDiagnostics::FlushDiagnosticsImpl( std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *filesMade) { for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), et = Diags.end(); it != et; ++it) { - ReportDiag(**it, FilesMade); + ReportDiag(**it, filesMade); } } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, - SmallVectorImpl<std::string> *FilesMade) { + FilesMade *filesMade) { // Create the HTML directory if it is missing. if (!createdDir) { @@ -266,8 +266,10 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, return; } - if (FilesMade) - FilesMade->push_back(llvm::sys::path::filename(H.str())); + if (filesMade) { + filesMade->push_back(std::make_pair(StringRef(getName()), + llvm::sys::path::filename(H.str()))); + } // Emit the HTML to disk. for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 7d52aac71c..e8db9c4122 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -240,8 +240,8 @@ struct CompareDiagnostics { }; } -void -PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) { +void PathDiagnosticConsumer::FlushDiagnostics( + PathDiagnosticConsumer::FilesMade *Files) { if (flushed) return; diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 58a4bba948..d672050a04 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -30,23 +30,21 @@ namespace { class PlistDiagnostics : public PathDiagnosticConsumer { const std::string OutputFile; const LangOptions &LangOpts; - OwningPtr<PathDiagnosticConsumer> SubPD; const bool SupportsCrossFileDiagnostics; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, - bool supportsMultipleFiles, - PathDiagnosticConsumer *subPD); + bool supportsMultipleFiles); virtual ~PlistDiagnostics() {} void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, - SmallVectorImpl<std::string> *FilesMade); + FilesMade *filesMade); virtual StringRef getName() const { return "PlistDiagnostics"; } - PathGenerationScheme getGenerationScheme() const; + PathGenerationScheme getGenerationScheme() const { return Extensive; } bool supportsLogicalOpControlFlow() const { return true; } bool supportsAllBlockEdges() const { return true; } virtual bool useVerboseDescription() const { return false; } @@ -58,29 +56,20 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, - bool supportsMultipleFiles, - PathDiagnosticConsumer *subPD) - |