diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -336,6 +336,18 @@ "might be modeled by the analyzer to never return NULL.", false) +ANALYZER_OPTION( + bool, ShouldIgnoreBisonGeneratedFiles, "ignore-bison-generated-files", + "If enabled, any files containing the \"/* A Bison parser, made by\" " + "won't be analyzed.", + true) + +ANALYZER_OPTION( + bool, ShouldIgnoreFlexGeneratedFiles, "ignore-flex-generated-files", + "If enabled, any files containing the \"/* A lexical scanner generated by " + "flex\" won't be analyzed.", + true) + //===----------------------------------------------------------------------===// // Unsigned analyzer options. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -35,6 +35,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -493,13 +494,11 @@ } } -static bool isBisonFile(ASTContext &C) { +static bool fileContainsString(StringRef Substring, ASTContext &C) { const SourceManager &SM = C.getSourceManager(); FileID FID = SM.getMainFileID(); StringRef Buffer = SM.getBufferOrFake(FID).getBuffer(); - if (Buffer.startswith("/* A Bison parser, made by")) - return true; - return false; + return Buffer.contains(Substring); } void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) { @@ -546,38 +545,48 @@ } void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { - // Don't run the actions if an error has occurred with parsing the file. DiagnosticsEngine &Diags = PP.getDiagnostics(); if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; - if (isBisonFile(C)) { + // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. + // FIXME: This should be replaced with something that doesn't rely on + // side-effects in PathDiagnosticConsumer's destructor. This is required when + // used with option -disable-free. + const auto DiagFlusherScopeExit = + llvm::make_scope_exit([this] { Mgr.reset(); }); + + if (Opts->ShouldIgnoreBisonGeneratedFiles && + fileContainsString("/* A Bison parser, made by", C)) { reportAnalyzerProgress("Skipping bison-generated file\n"); - } else if (Opts->DisableAllCheckers) { + return; + } - // Don't analyze if the user explicitly asked for no checks to be performed - // on this file. + if (Opts->ShouldIgnoreFlexGeneratedFiles && + fileContainsString("/* A lexical scanner generated by flex", C)) { + reportAnalyzerProgress("Skipping flex-generated file\n"); + return; + } + + // Don't analyze if the user explicitly asked for no checks to be performed + // on this file. + if (Opts->DisableAllCheckers) { reportAnalyzerProgress("All checks are disabled using a supplied option\n"); - } else { - // Otherwise, just run the analysis. - runAnalysisOnTranslationUnit(C); + return; } + // Otherwise, just run the analysis. + runAnalysisOnTranslationUnit(C); + // Count how many basic blocks we have not covered. NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks(); NumVisitedBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumVisitedBasicBlocks(); if (NumBlocksInAnalyzedFunctions > 0) PercentReachableBlocks = - (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) / + (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) / NumBlocksInAnalyzedFunctions; - - // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. - // FIXME: This should be replaced with something that doesn't rely on - // side-effects in PathDiagnosticConsumer's destructor. This is required when - // used with option -disable-free. - Mgr.reset(); } AnalysisConsumer::AnalysisMode diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -83,6 +83,8 @@ // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true // CHECK-NEXT: graph-trim-interval = 1000 +// CHECK-NEXT: ignore-bison-generated-files = true +// CHECK-NEXT: ignore-flex-generated-files = true // CHECK-NEXT: inline-lambdas = true // CHECK-NEXT: ipa = dynamic-bifurcate // CHECK-NEXT: ipa-always-inline-size = 3 diff --git a/clang/test/Analysis/flexignore.c b/clang/test/Analysis/flexignore.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/flexignore.c @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -DEXPECT_NO_DIAGNOSTICS %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify=conditional %s \ +// RUN: -analyzer-config ignore-flex-generated-files=false + +#ifdef EXPECT_NO_DIAGNOSTICS +// expected-no-diagnostics +#endif + +/* A lexical scanner generated by flex */ + +void clang_analyzer_warnIfReached(); +void foo() { + clang_analyzer_warnIfReached(); // conditional-warning {{REACHABLE}} +} diff --git a/clang/test/Analysis/yaccignore.c b/clang/test/Analysis/yaccignore.c --- a/clang/test/Analysis/yaccignore.c +++ b/clang/test/Analysis/yaccignore.c @@ -1,13 +1,14 @@ -/* A Bison parser, made by GNU Bison 1.875. */ - -// RUN: rm -rf %t.plist -// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist -o %t.plist -verify %s -// RUN: FileCheck --input-file=%t.plist %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -DEXPECT_NO_DIAGNOSTICS %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify=conditional %s \ +// RUN: -analyzer-config ignore-bison-generated-files=false +#ifdef EXPECT_NO_DIAGNOSTICS // expected-no-diagnostics -int foo() { - int *x = 0; - return *x; // no-warning -} +#endif -// CHECK: diagnostics +/* A Bison parser, made by GNU Bison 1.875. */ + +void clang_analyzer_warnIfReached(); +void foo() { + clang_analyzer_warnIfReached(); // conditional-warning {{REACHABLE}} +}