]> granicus.if.org Git - clang/commitdiff
[analyzer] Add werror flag for analyzer warnings
authorKeno Fischer <keno@alumni.harvard.edu>
Fri, 7 Jun 2019 23:34:00 +0000 (23:34 +0000)
committerKeno Fischer <keno@alumni.harvard.edu>
Fri, 7 Jun 2019 23:34:00 +0000 (23:34 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362855 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Driver/CC1Options.td
include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
lib/Frontend/CompilerInvocation.cpp
lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
test/Analysis/override-werror.c

index 56ff05d3e4c790969fef598f6b59baec280e98ce..1aad3b70ea9854b6386f355be081b08e0a1582c0 100644 (file)
@@ -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<analyzer_config_compatibility_mode>;
 
+def analyzer_werror : Flag<["-"], "analyzer-werror">,
+  HelpText<"Emit analyzer results as errors rather than warnings">;
+
 //===----------------------------------------------------------------------===//
 // Migrator Options
 //===----------------------------------------------------------------------===//
index 4d81f90961cb9c1d22540c5e769226cfa49081b2..9630a229bd3bf8cdf9afdbdf2df47d74c030f05a 100644 (file)
@@ -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);
   }
 
index 1b475dc0370eb4d185459dd6bdc147fdc0b003db..5596e4b6a3c8c1a87c1cd3d02e012d2791c6f372 100644 (file)
@@ -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 =
index 5c674923e06f716b59f379a115be27fedd0fb655..a75ff2563cf5189b7240655e7db116a8d62c34f6 100644 (file)
@@ -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<const PathDiagnostic *> &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<const PathDiagnostic*>::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<const VarDecl *> CTUDeclOrError =
-      CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName, 
+      CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName,
                                Opts->DisplayCTUProgress);
 
     if (!CTUDeclOrError) {
index 7dc09f518627ac41da0749c07b4cfc9cce72ae16..df80bac84f4afd650dcc71ff51c33f17919209bf 100644 (file)
@@ -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}}
 }