Skip to content

Commit

Permalink
[clang-scan-deps] Support for clang --analyze in clang-scan-deps
Browse files Browse the repository at this point in the history
The goal is to have 100% fidelity in clang-scan-deps behavior when
--analyze is present in compilation command.

At the same time I don't want to break clang-tidy which expects
__static_analyzer__ macro defined as built-in.

I introduce new cc1 options (-setup-static-analyzer) that controls
the macro definition and is conditionally set in driver.

Differential Revision: https://reviews.llvm.org/D68093

llvm-svn: 374815
  • Loading branch information
jkorous-apple committed Oct 14, 2019
1 parent 7e385bd commit c5d14b5
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 9 deletions.
7 changes: 3 additions & 4 deletions clang-tools-extra/clang-tidy/ClangTidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/Tooling/Core/Diagnostic.h"
Expand Down Expand Up @@ -539,10 +540,8 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
FileManager *Files,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
DiagnosticConsumer *DiagConsumer) override {
// Explicitly set ProgramAction to RunAnalysis to make the preprocessor
// define __clang_analyzer__ macro. The frontend analyzer action will not
// be called here.
Invocation->getFrontendOpts().ProgramAction = frontend::RunAnalysis;
// Explicitly ask to define __clang_analyzer__ macro.
Invocation->getPreprocessorOpts().SetUpStaticAnalyzer = true;
return FrontendActionFactory::runInvocation(
Invocation, Files, PCHContainerOps, DiagConsumer);
}
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/CC1Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,8 @@ def preamble_bytes_EQ : Joined<["-"], "preamble-bytes=">,
"covering the first N bytes of the main file">;
def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
def setup_static_analyzer : Flag<["-"], "setup-static-analyzer">,
HelpText<"Set up preprocessor for static analyzer (done automatically when static analyzer is run).">;

//===----------------------------------------------------------------------===//
// OpenCL Options
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Lex/PreprocessorOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ class PreprocessorOptions {
ExcludedPreprocessorDirectiveSkipMapping
*ExcludedConditionalDirectiveSkipMappings = nullptr;

/// Set up preprocessor for RunAnalysis action.
bool SetUpStaticAnalyzer = false;

public:
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3803,6 +3803,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (isa<AnalyzeJobAction>(JA))
RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);

if (isa<AnalyzeJobAction>(JA) ||
(isa<PreprocessJobAction>(JA) && Args.hasArg(options::OPT__analyze)))
CmdArgs.push_back("-setup-static-analyzer");

// Enable compatilibily mode to avoid analyzer-config related errors.
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3349,6 +3349,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
// "editor placeholder in source file" error in PP only mode.
if (isStrictlyPreprocessorAction(Action))
Opts.LexEditorPlaceholders = false;

Opts.SetUpStaticAnalyzer = Args.hasArg(OPT_setup_static_analyzer);
}

static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
const PreprocessorOptions &PPOpts,
MacroBuilder &Builder) {
// Compiler version introspection macros.
Builder.defineMacro("__llvm__"); // LLVM Backend
Expand Down Expand Up @@ -997,8 +998,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
Builder.defineMacro("__SSP_ALL__", "3");

// Define a macro that exists only when using the static analyzer.
if (FEOpts.ProgramAction == frontend::RunAnalysis)
if (PPOpts.SetUpStaticAnalyzer)
Builder.defineMacro("__clang_analyzer__");

if (LangOpts.FastRelaxedMath)
Expand Down Expand Up @@ -1125,9 +1125,10 @@ void clang::InitializePreprocessor(
// macros. This is not the right way to handle this.
if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
Builder);
PP.getPreprocessorOpts(), Builder);

InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder);
InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts,
PP.getPreprocessorOpts(), Builder);

// Install definitions to make Objective-C++ ARC work well with various
// C++ Standard Library implementations.
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Analysis/preprocessor-setup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUN: %clang_cc1 -E -setup-static-analyzer %s

#ifndef __clang_analyzer__
#error __clang_analyzer__ not defined
#endif
7 changes: 7 additions & 0 deletions clang/test/ClangScanDeps/Inputs/static-analyzer-cdb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"directory": "DIR",
"command": "clang --analyze DIR/static-analyzer.c",
"file": "DIR/static-analyzer.c"
}
]
16 changes: 16 additions & 0 deletions clang/test/ClangScanDeps/static-analyzer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: rm -rf %t.dir
// RUN: rm -rf %t.dir/cdb.json
// RUN: mkdir -p %t.dir
// RUN: cp %s %t.dir/static-analyzer.c
// RUN: mkdir %t.dir/Inputs
// RUN: cp %S/Inputs/header.h %t.dir/Inputs/analyze_header_input.h
// RUN: sed -e "s|DIR|%t.dir|g" %S/Inputs/static-analyzer-cdb.json > %t.dir/cdb.json
//
// RUN: clang-scan-deps -compilation-database %t.dir/cdb.json -j 1 | FileCheck %s

#ifdef __clang_analyzer__
#include "Inputs/analyze_header_input.h"
#endif

// CHECK: analyze_header_input.h

2 changes: 1 addition & 1 deletion llvm/utils/lit/lit/llvm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def use_clang(self, additional_tool_dirs=[], additional_flags=[], required=True)
builtin_include_dir = self.get_clang_builtin_include_dir(self.config.clang)
tool_substitutions = [
ToolSubst('%clang', command=self.config.clang, extra_args=additional_flags),
ToolSubst('%clang_analyze_cc1', command='%clang_cc1', extra_args=['-analyze', '%analyze']+additional_flags),
ToolSubst('%clang_analyze_cc1', command='%clang_cc1', extra_args=['-analyze', '%analyze', '-setup-static-analyzer']+additional_flags),
ToolSubst('%clang_cc1', command=self.config.clang, extra_args=['-cc1', '-internal-isystem', builtin_include_dir, '-nostdsysteminc']+additional_flags),
ToolSubst('%clang_cpp', command=self.config.clang, extra_args=['--driver-mode=cpp']+additional_flags),
ToolSubst('%clang_cl', command=self.config.clang, extra_args=['--driver-mode=cl']+additional_flags),
Expand Down

0 comments on commit c5d14b5

Please sign in to comment.