Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -54,12 +54,16 @@ def analyzer_output_EQ : Joined<["-"], "analyzer-output=">, Alias; +def analyzer_opt_random_report_filename : Flag<["-"], "analyzer-random-report-filename">, + HelpText<"Force the generation of random filename for the HTML report">; + def analyzer_purge : Separate<["-"], "analyzer-purge">, HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">; def analyzer_purge_EQ : Joined<["-"], "analyzer-purge=">, Alias; def analyzer_opt_analyze_headers : Flag<["-"], "analyzer-opt-analyze-headers">, HelpText<"Force the static analyzer to analyze functions defined in header files">; + def analyzer_opt_analyze_nested_blocks : Flag<["-"], "analyzer-opt-analyze-nested-blocks">, HelpText<"Analyze the definitions of blocks in addition to functions">; def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">, Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -141,7 +141,8 @@ unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; - + unsigned RandomReportFilename : 1; + /// \brief The flag regulates if we should eagerly assume evaluations of /// conditionals, thus, bifurcating the path. /// @@ -415,6 +416,7 @@ AnalyzeAll(0), AnalyzerDisplayProgress(0), AnalyzeNestedBlocks(0), + RandomReportFilename(0), eagerlyAssumeBinOpBifurcation(0), TrimGraph(0), visualizeExplodedGraphWithGraphViz(0), Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -237,6 +237,7 @@ Opts.InlineMaxStackDepth = getLastArgIntValue(Args, OPT_analyzer_inline_max_stack_depth, Opts.InlineMaxStackDepth, Diags); + Opts.RandomReportFilename = Args.hasArg(OPT_analyzer_opt_random_report_filename); Opts.CheckersControlList.clear(); for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, 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; + const AnalyzerOptions &AnalyzerOpts; public: - HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } @@ -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)); } //===----------------------------------------------------------------------===// @@ -126,11 +129,19 @@ // Create a new rewriter to generate HTML. Rewriter R(const_cast(SMgr), PP.getLangOpts()); +// Get the function/method name + std::string declName="unknown"; + if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { + if (const NamedDecl *ND = dyn_cast(DeclWithIssue)) { + declName = ND->getDeclName().getAsString(); + } + } + // 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); @@ -247,13 +258,33 @@ // Create a path for the target HTML file. int FD; SmallString<128> Model, ResultPath; - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (llvm::error_code EC = + if (AnalyzerOpts.RandomReportFilename) { + llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); + + + if (llvm::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 { + Model=""; + llvm::sys::path::append(Model, Directory, "report-" + llvm::sys::path::filename(Entry->getName()) + "-" + declName + "-" + std::to_string(i) + ".html") ; + i++; + } while (llvm::sys::fs::exists(Model.str())); + + if (llvm::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: 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; @@ -997,6 +999,7 @@ my $CCAnalyzer = shift; my $CXXAnalyzer = shift; my $Options = shift; + my $RandomFilename = shift; if ($Cmd =~ /\bxcodebuild$/) { return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options); @@ -1172,6 +1175,12 @@ Provide options to pass through to the analyzer's -analyzer-config flag. + --random-report-filename + + Switch the page naming to report-XXXXXX.html instead of + report---.html. Default behavior before + clang 3.5. + CONTROLLING CHECKERS: A default group of checkers are always run unless explicitly disabled. @@ -1339,6 +1348,7 @@ my $ViewResults = 0; # View results when the build terminates. my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found my $KeepEmpty = 0; # Don't remove output directory even with 0 results. +my $RandomFilename = 0; # Randomize the page name my @AnalysesToRun; my $StoreModel; my $ConstraintsModel; @@ -1373,6 +1383,12 @@ next; } + if ($arg eq "--random-report-filename") { + shift @ARGV; + $RandomFilename = 1; + next; + } + if ($arg eq "-o") { shift @ARGV; @@ -1645,6 +1661,7 @@ if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; } if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } if ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; } +if ($RandomFilename) { push @AnalysesToRun,"-analyzer-random-report-filename"; } # Delay setting up other environment variables in case we can do true # interposition.