Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -141,7 +141,7 @@ 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 @@ /// \sa reportIssuesInMainSourceFile Optional ReportIssuesInMainSourceFile; + /// \sa StableReportFilename + Optional StableReportFilename; + /// \sa getGraphTrimInterval Optional GraphTrimInterval; @@ -359,6 +362,12 @@ /// 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. /// Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -189,6 +189,13 @@ /* 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); Index: lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ 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 @@ 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 @@ } // 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::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { - + // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; @@ -126,11 +129,30 @@ // Create a new rewriter to generate HTML. Rewriter R(const_cast(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(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 @@ DirName += '/'; } + int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber(); + int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber(); + // Add the name of the file as an

tag. { @@ -176,9 +201,9 @@ << html::EscapeText(Entry->getName()) << "\nLocation:" "line " - << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber() + << LineNumber << ", column " - << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber() + << ColumnNumber << "\n" "Description:" << D.getVerboseDescription() << "\n"; @@ -216,11 +241,11 @@ os << "\n\n"; os << "\n\n"; os << "\n\n"; os << "\n\n"; @@ -247,13 +272,34 @@ // 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; + 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") ; + i++; + } while (llvm::sys::fs::exists(Model.str())); + + if (std::error_code EC = + llvm::sys::fs::openFileForWrite(Model.str(), FD, llvm::sys::fs::OpenFlags::F_RW)) { + llvm::errs() << "warning: could not create file '" << Model.str() + << "': " << EC.message() << '\n'; + return; + } + } llvm::raw_fd_ostream os(FD, true); Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -415,7 +415,7 @@ break; } if (!declKind.empty()) { - const std::string &declName = ND->getDeclName().getAsString(); + SmallString<128> declName(ND->getDeclName().getAsString()); o << " issue_context_kind"; EmitString(o, declKind) << '\n'; o << " issue_context"; Index: tools/scan-build/scan-build =================================================================== --- tools/scan-build/scan-build +++ tools/scan-build/scan-build @@ -498,6 +498,8 @@ 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 @@ -analyzer-config 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---.html + instead of report-XXXXXX.html CONTROLLING CHECKERS: