From 6f48c076207f49dde437d85dbd5e1bcdd580f973 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 7 Jun 2019 23:34:00 +0000 Subject: [PATCH] [analyzer] Add werror flag for analyzer warnings Summary: We're using the clang static analyzer together with a number of custom analyses in our CI system to ensure that certain invariants are statiesfied for by the code every commit. Unfortunately, there currently doesn't seem to be a good way to determine whether any analyzer warnings were emitted, other than parsing clang's output (or using scan-build, which then in turn parses clang's output). As a simpler mechanism, simply add a `-analyzer-werror` flag to CC1 that causes the analyzer to emit its warnings as errors instead. I briefly tried to have this be `Werror=analyzer` and make it go through that machinery instead, but that seemed more trouble than it was worth in terms of conflicting with options to the actual build and special cases that would be required to circumvent the analyzers usual attempts to quiet non-analyzer warnings. This is simple and it works well. Reviewed-By: NoQ, Szelethusw Differential Revision: https://reviews.llvm.org/D62885 llvm-svn: 362855 --- clang/include/clang/Driver/CC1Options.td | 3 +++ .../include/clang/StaticAnalyzer/Core/AnalyzerOptions.h | 5 ++++- clang/lib/Frontend/CompilerInvocation.cpp | 1 + clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 17 +++++++++++++---- clang/test/Analysis/override-werror.c | 9 ++++++--- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 56ff05d..1aad3b7 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -166,6 +166,9 @@ def analyzer_config_compatibility_mode : Separate<["-"], "analyzer-config-compat def analyzer_config_compatibility_mode_EQ : Joined<["-"], "analyzer-config-compatibility-mode=">, Alias; +def analyzer_werror : Flag<["-"], "analyzer-werror">, + HelpText<"Emit analyzer results as errors rather than warnings">; + //===----------------------------------------------------------------------===// // Migrator Options //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 4d81f90..9630a22 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -245,6 +245,9 @@ public: /// strategy. We get better code coverage when retry is enabled. unsigned NoRetryExhausted : 1; + /// Emit analyzer warnings as errors. + unsigned AnalyzerWerror : 1; + /// The inlining stack depth limit. // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). unsigned InlineMaxStackDepth = 5; @@ -297,7 +300,7 @@ public: AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false), - PrintStats(false), NoRetryExhausted(false) { + PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) { llvm::sort(AnalyzerConfigCmdFlags); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 1b475dc..5596e4b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -309,6 +309,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Args.hasArg(OPT_analyzer_viz_egraph_graphviz); Opts.DumpExplodedGraphTo = Args.getLastArgValue(OPT_analyzer_dump_egraph); Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted); + Opts.AnalyzerWerror = Args.hasArg(OPT_analyzer_werror); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 5c67492..a75ff25 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -83,10 +83,11 @@ void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, namespace { class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { DiagnosticsEngine &Diag; - bool IncludePath; + bool IncludePath, ShouldEmitAsError; + public: ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) - : Diag(Diag), IncludePath(false) {} + : Diag(Diag), IncludePath(false), ShouldEmitAsError(false) {} ~ClangDiagPathDiagConsumer() override {} StringRef getName() const override { return "ClangDiags"; } @@ -101,9 +102,14 @@ public: IncludePath = true; } + void enableWerror() { ShouldEmitAsError = true; } + void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) override { - unsigned WarnID = Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); + unsigned WarnID = + ShouldEmitAsError + ? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0") + : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); for (std::vector::iterator I = Diags.begin(), @@ -225,6 +231,9 @@ public: new ClangDiagPathDiagConsumer(PP.getDiagnostics()); PathConsumers.push_back(clangDiags); + if (Opts->AnalyzerWerror) + clangDiags->enableWerror(); + if (Opts->AnalysisDiagOpt == PD_TEXT) { clangDiags->enablePaths(); @@ -358,7 +367,7 @@ public: return true; llvm::Expected CTUDeclOrError = - CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName, + CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName, Opts->DisplayCTUProgress); if (!CTUDeclOrError) { diff --git a/clang/test/Analysis/override-werror.c b/clang/test/Analysis/override-werror.c index 7dc09f5..df80bac 100644 --- a/clang/test/Analysis/override-werror.c +++ b/clang/test/Analysis/override-werror.c @@ -1,14 +1,17 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -Werror %s -analyzer-store=region -verify +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -Werror %s -analyzer-store=region -analyzer-werror -verify=werror // This test case illustrates that using '-analyze' overrides the effect of // -Werror. This allows basic warnings not to interfere with producing // analyzer results. -char* f(int *p) { - return p; // expected-warning{{incompatible pointer types}} +char* f(int *p) { + return p; // expected-warning{{incompatible pointer types}} \ + werror-warning{{incompatible pointer types}} } void g(int *p) { - if (!p) *p = 0; // expected-warning{{null}} + if (!p) *p = 0; // expected-warning{{null}} \ + werror-error{{null}} } -- 2.7.4