diff --git a/clang/include/clang/Analysis/PathDiagnostic.h b/clang/include/clang/Analysis/PathDiagnostic.h --- a/clang/include/clang/Analysis/PathDiagnostic.h +++ b/clang/include/clang/Analysis/PathDiagnostic.h @@ -58,6 +58,47 @@ class PathDiagnostic; +/// These options tweak the behavior of path diangostic consumers. +/// Most of these options are currently supported by very few consumers. +struct PathDiagnosticConsumerOptions { + /// Run-line of the tool that produced the diagnostic. + /// It can be included with the diagnostic for debugging purposes. + std::string ToolInvocation; + + /// Whether to include additional information about macro expansions + /// with the diagnostics, because otherwise they can be hard to obtain + /// without re-compiling the program under analysis. + bool ShouldDisplayMacroExpansions; + + /// Whether to include LLVM statistics of the process in the diagnostic. + /// Useful for profiling the tool on large real-world codebases. + bool ShouldSerializeStats; + + /// If the consumer intends to produce multiple output files, should it + /// use randomly generated file names for these files (with the tiny risk of + /// having random collisions) or deterministic human-readable file names + /// (with a larger risk of deterministic collisions or invalid characters + /// in the file name). We should not really give this choice to the users + /// because deterministic mode is always superior when done right, but + /// for some consumers this mode is experimental and needs to be + /// off by default. + bool ShouldWriteStableReportFilename; + + /// Whether the consumer should treat consumed diagnostics as hard errors. + /// Useful for breaking your build when issues are found. + bool ShouldDisplayWarningsAsErrors; + + /// Whether the consumer should attempt to rewrite the source file + /// with fix-it hints attached to the diagnostics it consumes. + bool ShouldApplyFixIts; + + /// Whether the consumer should present the name of the entity that emitted + /// the diagnostic (eg., a checker) so that the user knew how to disable it. + bool ShouldDisplayDiagnosticName; + + PathDiagnosticConsumerOptions() = delete; +}; + class PathDiagnosticConsumer { public: class PDFileEntry : public llvm::FoldingSetNode { diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H #define LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H +#include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" @@ -255,7 +256,7 @@ unsigned NoRetryExhausted : 1; /// Emit analyzer warnings as errors. - unsigned AnalyzerWerror : 1; + bool AnalyzerWerror : 1; /// The inlining stack depth limit. // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). @@ -390,6 +391,16 @@ /// /// \sa CXXMemberInliningMode bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const; + + ento::PathDiagnosticConsumerOptions getDiagOpts() const { + return {FullCompilerInvocation, + ShouldDisplayMacroExpansions, + ShouldSerializeStats, + ShouldWriteStableReportFilename, + AnalyzerWerror, + ShouldApplyFixIts, + ShouldDisplayCheckerNameForText}; + } }; using AnalyzerOptionsRef = IntrusiveRefCntPtr; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h --- a/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -30,8 +30,9 @@ typedef std::vector PathDiagnosticConsumers; #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ - void CREATEFN(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, \ - const std::string &Prefix, const Preprocessor &PP, \ + void CREATEFN(PathDiagnosticConsumerOptions Diagopts, \ + PathDiagnosticConsumers &C, const std::string &Prefix, \ + const Preprocessor &PP, \ const cross_tu::CrossTranslationUnitContext &CTU); #include "clang/StaticAnalyzer/Core/Analyses.def" diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -23,7 +23,6 @@ #include "clang/Lex/Token.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/IssueHash.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "llvm/ADT/ArrayRef.h" @@ -58,17 +57,18 @@ namespace { class HTMLDiagnostics : public PathDiagnosticConsumer { + PathDiagnosticConsumerOptions DiagOpts; std::string Directory; bool createdDir = false; bool noDir = false; const Preprocessor &PP; - AnalyzerOptions &AnalyzerOpts; const bool SupportsCrossFileDiagnostics; public: - HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &OutputDir, - const Preprocessor &pp, bool supportsMultipleFiles) - : Directory(OutputDir), PP(pp), AnalyzerOpts(AnalyzerOpts), + HTMLDiagnostics(PathDiagnosticConsumerOptions DiagOpts, + const std::string &OutputDir, const Preprocessor &pp, + bool supportsMultipleFiles) + : DiagOpts(std::move(DiagOpts)), Directory(OutputDir), PP(pp), SupportsCrossFileDiagnostics(supportsMultipleFiles) {} ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } @@ -133,7 +133,7 @@ } // namespace void ento::createHTMLDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, const std::string &OutputDir, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { @@ -142,37 +142,38 @@ // output mode. This doesn't make much sense, we should have the minimal text // as our default. In the case of backward compatibility concerns, this could // be preserved with -analyzer-config-compatibility-mode=true. - createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); + createTextMinimalPathDiagnosticConsumer(DiagOpts, C, OutputDir, PP, CTU); // TODO: Emit an error here. if (OutputDir.empty()) return; - C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, true)); + C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, true)); } void ento::createHTMLSingleFileDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, const std::string &OutputDir, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { + createTextMinimalPathDiagnosticConsumer(DiagOpts, C, OutputDir, PP, CTU); // TODO: Emit an error here. if (OutputDir.empty()) return; - C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, false)); - createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); + C.push_back(new HTMLDiagnostics(std::move(DiagOpts), OutputDir, PP, false)); } void ento::createPlistHTMLDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, const std::string &prefix, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { createHTMLDiagnosticConsumer( - AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, + DiagOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, CTU); - createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); - createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); + createPlistMultiFileDiagnosticConsumer(DiagOpts, C, prefix, PP, CTU); + createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, prefix, PP, + CTU); } //===----------------------------------------------------------------------===// @@ -245,7 +246,7 @@ int FD; SmallString<128> Model, ResultPath; - if (!AnalyzerOpts.ShouldWriteStableReportFilename) { + if (!DiagOpts.ShouldWriteStableReportFilename) { llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); if (std::error_code EC = llvm::sys::fs::make_absolute(Model)) { @@ -535,7 +536,7 @@
clang -cc1 )<<<"; - os << html::EscapeText(AnalyzerOpts.FullCompilerInvocation); + os << html::EscapeText(DiagOpts.ToolInvocation); os << R"<<<(