diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/AnalyzerOptions.h | 11 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 7 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 85 | ||||
-rwxr-xr-x | tools/scan-build/scan-build | 9 |
4 files changed, 95 insertions, 17 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 42b6ca5586..520fed08e3 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -141,7 +141,7 @@ public: unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; - + /// \brief The flag regulates if we should eagerly assume evaluations of /// conditionals, thus, bifurcating the path. /// @@ -233,6 +233,9 @@ private: /// \sa reportIssuesInMainSourceFile Optional<bool> ReportIssuesInMainSourceFile; + /// \sa StableReportFilename + Optional<bool> StableReportFilename; + /// \sa getGraphTrimInterval Optional<unsigned> GraphTrimInterval; @@ -359,6 +362,12 @@ public: /// which accepts the values "true" and "false". bool shouldReportIssuesInMainSourceFile(); + /// Returns whether or not the report filename should be random or not. + /// + /// This is controlled by the 'stable-report-filename' config option, + /// which accepts the values "true" and "false". Default = false + bool shouldWriteStableReportFilename(); + /// Returns whether irrelevant parts of a bug report path should be pruned /// out of the final output. /// diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 38aac288a1..85d66ba600 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -189,6 +189,13 @@ bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { /* Default = */ false); } + +bool AnalyzerOptions::shouldWriteStableReportFilename() { + return getBooleanOption(StableReportFilename, + "stable-report-filename", + /* Default = */ false); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { SmallString<10> StrBuf; llvm::raw_svector_ostream OS(StrBuf); diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index a7e42291f9..c176ab3f55 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -20,6 +20,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -39,8 +40,9 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { std::string Directory; bool createdDir, noDir; const Preprocessor &PP; + AnalyzerOptions &AnalyzerOpts; public: - HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); } @@ -68,16 +70,17 @@ public: } // end anonymous namespace -HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, +HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& prefix, const Preprocessor &pp) - : Directory(prefix), createdDir(false), noDir(false), PP(pp) { + : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { } void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string& prefix, const Preprocessor &PP) { - C.push_back(new HTMLDiagnostics(prefix, PP)); + C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); } //===----------------------------------------------------------------------===// @@ -95,7 +98,7 @@ void HTMLDiagnostics::FlushDiagnosticsImpl( void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { - + // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; @@ -126,11 +129,30 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a new rewriter to generate HTML. Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts()); + // Get the function/method name + SmallString<128> declName("unknown"); + int offsetDecl = 0; + if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { + declName = ND->getDeclName().getAsString(); + } + + if (const Stmt *Body = DeclWithIssue->getBody()) { + // Retrieve the relative position of the declaration which will be used + // for the file name + FullSourceLoc L( + SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()), + SMgr); + FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr); + offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber(); + } + } + // Process the path. unsigned n = path.size(); unsigned max = n; - for (PathPieces::const_reverse_iterator I = path.rbegin(), + for (PathPieces::const_reverse_iterator I = path.rbegin(), E = path.rend(); I != E; ++I, --n) HandlePiece(R, FID, **I, n, max); @@ -163,6 +185,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, DirName += '/'; } + int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber(); + int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber(); + // Add the name of the file as an <h1> tag. { @@ -176,9 +201,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, << html::EscapeText(Entry->getName()) << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" "<a href=\"#EndPath\">line " - << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << ", column " - << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << "</a></td></tr>\n" "<tr><td class=\"rowname\">Description:</td><td>" << D.getVerboseDescription() << "</td></tr>\n"; @@ -216,11 +241,11 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; os << "\n<!-- BUGLINE " - << path.back()->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << " -->\n"; os << "\n<!-- BUGCOLUMN " - << path.back()->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << " -->\n"; os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n"; @@ -247,13 +272,41 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a path for the target HTML file. int FD; SmallString<128> Model, ResultPath; - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (std::error_code EC = + if (!AnalyzerOpts.shouldWriteStableReportFilename()) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + + if (std::error_code EC = llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + return; + } + + } else { + int i = 1; + std::error_code EC; + do { + // Find a filename which is not already used + Model = ""; + llvm::sys::path::append(Model, Directory, + "report-" + + llvm::sys::path::filename(Entry->getName()) + + "-" + + declName.c_str() + + "-" + std::to_string(offsetDecl) + + "-" + std::to_string(i) + ".html"); + EC = llvm::sys::fs::openFileForWrite(Model.str(), + FD, + llvm::sys::fs::F_RW | + llvm::sys::fs::F_Excl); + if (EC && EC != std::errc::file_exists) { + llvm::errs() << "warning: could not create file '" << Model.str() + << "': " << EC.message() << '\n'; + return; + } + i++; + } while (EC); } llvm::raw_fd_ostream os(FD, true); @@ -458,7 +511,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, << (num + 1) << ")\">→</a></div></td>"; } - + os << "</tr></table>"; } } diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build index 7502a42432..f46f0933c0 100755 --- a/tools/scan-build/scan-build +++ b/tools/scan-build/scan-build @@ -498,6 +498,8 @@ my $baseDir; sub FileWanted { my $baseDirRegEx = quotemeta $baseDir; my $file = $File::Find::name; + + # The name of the file is generated by clang binary (HTMLDiagnostics.cpp) if ($file =~ /report-.*\.html$/) { my $relative_file = $file; $relative_file =~ s/$baseDirRegEx//g; @@ -1175,6 +1177,13 @@ ADVANCED OPTIONS: -analyzer-config <options> Provide options to pass through to the analyzer's -analyzer-config flag. + Several options are separated with comma: 'key1=val1,key2=val2' + + Available options: + * stable-report-filename=true or false (default) + Switch the page naming to: + report-<filename>-<function/method name>-<id>.html + instead of report-XXXXXX.html CONTROLLING CHECKERS: |