diff options
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 35 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 129 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/PlistDiagnostics.cpp | 95 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp | 30 |
4 files changed, 159 insertions, 130 deletions
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 0c4e4277e4..933e15c0de 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -39,15 +39,13 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { llvm::sys::Path Directory, FilePrefix; bool createdDir, noDir; const Preprocessor &PP; - std::vector<const PathDiagnostic*> BatchedDiags; public: HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } - virtual void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); - - virtual void HandlePathDiagnosticImpl(const PathDiagnostic* D); + virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade); virtual StringRef getName() const { return "HTMLDiagnostics"; @@ -88,30 +86,13 @@ ento::createHTMLDiagnosticConsumer(const std::string& prefix, // Report processing. //===----------------------------------------------------------------------===// -void HTMLDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { - if (!D) - return; - - if (D->empty()) { - delete D; - return; +void HTMLDiagnostics::FlushDiagnosticsImpl( + std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade) { + for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), + et = Diags.end(); it != et; ++it) { + ReportDiag(**it, FilesMade); } - - const_cast<PathDiagnostic*>(D)->flattenLocations(); - BatchedDiags.push_back(D); -} - -void -HTMLDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) -{ - while (!BatchedDiags.empty()) { - const PathDiagnostic* D = BatchedDiags.back(); - BatchedDiags.pop_back(); - ReportDiag(*D, FilesMade); - delete D; - } - - BatchedDiags.clear(); } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index e398bae60f..c0bb180c82 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -84,11 +84,122 @@ PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc, void PathDiagnosticConsumer::anchor() { } -void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) { - // For now this simply forwards to HandlePathDiagnosticImpl. In the future - // we can use this indirection to control for multi-threaded access to - // the PathDiagnosticConsumer from multiple bug reporters. - HandlePathDiagnosticImpl(D); +PathDiagnosticConsumer::~PathDiagnosticConsumer() { + // Delete the contents of the FoldingSet if it isn't empty already. + for (llvm::FoldingSet<PathDiagnostic>::iterator it = + Diags.begin(), et = Diags.end() ; it != et ; ++it) { + delete &*it; + } +} + +void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { + if (!D) + return; + + if (D->empty()) { + delete D; + return; + } + + // We need to flatten the locations (convert Stmt* to locations) because + // the referenced statements may be freed by the time the diagnostics + // are emitted. + D->flattenLocations(); + + // Profile the node to see if we already have something matching it + llvm::FoldingSetNodeID profile; + D->Profile(profile); + void *InsertPos = 0; + + if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { + // Keep the PathDiagnostic with the shorter path. + if (orig->size() <= D->size()) { + bool shouldKeepOriginal = true; + if (orig->size() == D->size()) { + // Here we break ties in a fairly arbitrary, but deterministic, way. + llvm::FoldingSetNodeID fullProfile, fullProfileOrig; + D->FullProfile(fullProfile); + orig->FullProfile(fullProfileOrig); + if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash()) + shouldKeepOriginal = false; + } + + if (shouldKeepOriginal) { + delete D; + return; + } + } + Diags.RemoveNode(orig); + delete orig; + } + + Diags.InsertNode(D); +} + + +namespace { +struct CompareDiagnostics { + // Compare if 'X' is "<" than 'Y'. + bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { + // First compare by location + const FullSourceLoc &XLoc = X->getLocation().asLocation(); + const FullSourceLoc &YLoc = Y->getLocation().asLocation(); + if (XLoc < YLoc) + return true; + if (XLoc != YLoc) + return false; + + // Next, compare by bug type. + StringRef XBugType = X->getBugType(); + StringRef YBugType = Y->getBugType(); + if (XBugType < YBugType) + return true; + if (XBugType != YBugType) + return false; + + // Next, compare by bug description. + StringRef XDesc = X->getDescription(); + StringRef YDesc = Y->getDescription(); + if (XDesc < YDesc) + return true; + if (XDesc != YDesc) + return false; + + // FIXME: Further refine by comparing PathDiagnosticPieces? + return false; + } +}; +} + +void +PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) { + if (flushed) + return; + + flushed = true; + + std::vector<const PathDiagnostic *> BatchDiags; + for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), + et = Diags.end(); it != et; ++it) { + BatchDiags.push_back(&*it); + } + + // Clear out the FoldingSet. + Diags.clear(); + + // Sort the diagnostics so that they are always emitted in a deterministic + // order. + if (!BatchDiags.empty()) + std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics()); + + FlushDiagnosticsImpl(BatchDiags, Files); + + // Delete the flushed diagnostics. + for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), + et = BatchDiags.end(); it != et; ++it) { + const PathDiagnostic *D = *it; + delete D; + } } //===----------------------------------------------------------------------===// @@ -366,13 +477,17 @@ void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { } void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(Size); + if (Size) + getLocation().Profile(ID); ID.AddString(BugType); ID.AddString(Desc); ID.AddString(Category); +} + +void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { + Profile(ID); for (const_iterator I = begin(), E = end(); I != E; ++I) ID.Add(*I); - for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) ID.AddString(*I); } diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 22fabbf7ae..18eed8a0f9 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -25,43 +25,9 @@ using namespace ento; typedef llvm::DenseMap<FileID, unsigned> FIDMap; -namespace { -struct CompareDiagnostics { - // Compare if 'X' is "<" than 'Y'. - bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { - // First compare by location - const FullSourceLoc &XLoc = X->getLocation().asLocation(); - const FullSourceLoc &YLoc = Y->getLocation().asLocation(); - if (XLoc < YLoc) - return true; - if (XLoc != YLoc) - return false; - - // Next, compare by bug type. - StringRef XBugType = X->getBugType(); - StringRef YBugType = Y->getBugType(); - if (XBugType < YBugType) - return true; - if (XBugType != YBugType) - return false; - - // Next, compare by bug description. - StringRef XDesc = X->getDescription(); - StringRef YDesc = Y->getDescription(); - if (XDesc < YDesc) - return true; - if (XDesc != YDesc) - return false; - - // FIXME: Further refine by comparing PathDiagnosticPieces? - return false; - } -}; -} namespace { class PlistDiagnostics : public PathDiagnosticConsumer { - std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; const LangOptions &LangOpts; llvm::OwningPtr<PathDiagnosticConsumer> SubPD; @@ -70,11 +36,10 @@ namespace { PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, PathDiagnosticConsumer *subPD); - ~PlistDiagnostics() { FlushDiagnostics(NULL); } + virtual ~PlistDiagnostics() {} - void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); - - void HandlePathDiagnosticImpl(const PathDiagnostic* D); + void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade); virtual StringRef getName() const { return "PlistDiagnostics"; @@ -321,46 +286,20 @@ static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P, } } -void PlistDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { - if (!D) - return; - - if (D->empty()) { - delete D; - return; - } - - // We need to flatten the locations (convert Stmt* to locations) because - // the referenced statements may be freed by the time the diagnostics - // are emitted. - const_cast<PathDiagnostic*>(D)->flattenLocations(); - BatchedDiags.push_back(D); -} - -void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> - *FilesMade) { - - if (flushed) - return; - - flushed = true; - - // Sort the diagnostics so that they are always emitted in a deterministic - // order. - if (!BatchedDiags.empty()) - std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); - +void PlistDiagnostics::FlushDiagnosticsImpl( + std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade) { // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. FIDMap FM; SmallVector<FileID, 10> Fids; const SourceManager* SM = 0; - if (!BatchedDiags.empty()) - SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager(); + if (!Diags.empty()) + SM = &(*Diags.begin())->begin()->getLocation().getManager(); - for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(), - DE = BatchedDiags.end(); DI != DE; ++DI) { + for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(), + DE = Diags.end(); DI != DE; ++DI) { const PathDiagnostic *D = *DI; @@ -406,16 +345,13 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> " <key>diagnostics</key>\n" " <array>\n"; - for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(), - DE = BatchedDiags.end(); DI!=DE; ++DI) { + for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), + DE = Diags.end(); DI!=DE; ++DI) { o << " <dict>\n" " <key>path</key>\n"; const PathDiagnostic *D = *DI; - // Create an owning smart pointer for 'D' just so that we auto-free it - // when we exit this method. - llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D)); o << " <array>\n"; @@ -438,9 +374,10 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> // Output the diagnostic to the sub-diagnostic client, if any. if (SubPD) { - SubPD->HandlePathDiagnostic(OwnedD.take()); + std::vector<const PathDiagnostic *> SubDiags; + SubDiags.push_back(D); SmallVector<std::string, 1> SubFilesMade; - SubPD->FlushDiagnostics(SubFilesMade); + SubPD->FlushDiagnosticsImpl(SubDiags, &SubFilesMade); if (!SubFilesMade.empty()) { o << " <key>" << SubPD->getName() << "_files</key>\n"; @@ -462,6 +399,4 @@ void PlistDiagnostics::FlushDiagnostics(SmallVectorImpl<std::string> if (FilesMade) FilesMade->push_back(OutputFile); - - BatchedDiags.clear(); } diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp index 3543f7ff13..0c6b228274 100644 --- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp @@ -31,9 +31,8 @@ public: TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag) : OutputFile(output), Diag(diag) {} - void HandlePathDiagnosticImpl(const PathDiagnostic* D); - - void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade) { } + void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade); virtual StringRef getName() const { return "TextPathDiagnostics"; @@ -53,18 +52,17 @@ ento::createTextPathDiagnosticConsumer(const std::string& out, return new TextPathDiagnostics(out, PP.getDiagnostics()); } -void TextPathDiagnostics::HandlePathDiagnosticImpl(const PathDiagnostic* D) { - if (!D) - return; - - if (D->empty()) { - delete D; - return; - } - - for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) { - unsigned diagID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, I->getString()); - Diag.Report(I->getLocation().asLocation(), diagID); +void TextPathDiagnostics::FlushDiagnosticsImpl( + std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade) { + for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), + et = Diags.end(); it != et; ++it) { + const PathDiagnostic *D = *it; + for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) { + unsigned diagID = + Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, + I->getString()); + Diag.Report(I->getLocation().asLocation(), diagID); + } } } |