1 //===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements a clang-check tool that runs clang based on the info
10 // stored in a compilation database.
12 // This tool uses the Clang Tooling infrastructure, see
13 // http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
14 // for details on setting it up with LLVM source tree.
16 //===----------------------------------------------------------------------===//
18 #include "clang/AST/ASTConsumer.h"
19 #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
20 #include "clang/Driver/Options.h"
21 #include "clang/Frontend/ASTConsumers.h"
22 #include "clang/Frontend/CompilerInstance.h"
23 #include "clang/Rewrite/Frontend/FixItRewriter.h"
24 #include "clang/Rewrite/Frontend/FrontendActions.h"
25 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
26 #include "clang/Tooling/CommonOptionsParser.h"
27 #include "clang/Tooling/Syntax/BuildTree.h"
28 #include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
29 #include "clang/Tooling/Syntax/Tokens.h"
30 #include "clang/Tooling/Syntax/Tree.h"
31 #include "clang/Tooling/Tooling.h"
32 #include "llvm/ADT/STLExtras.h"
33 #include "llvm/Option/OptTable.h"
34 #include "llvm/Support/Path.h"
35 #include "llvm/Support/Signals.h"
36 #include "llvm/Support/TargetSelect.h"
38 using namespace clang::driver
;
39 using namespace clang::tooling
;
42 static cl::extrahelp
CommonHelp(CommonOptionsParser::HelpMessage
);
43 static cl::extrahelp
MoreHelp(
44 "\tFor example, to run clang-check on all files in a subtree of the\n"
45 "\tsource tree, use:\n"
47 "\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
49 "\tor using a specific build path:\n"
51 "\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
53 "\tNote, that path/in/subtree and current directory should follow the\n"
54 "\trules described above.\n"
58 static cl::OptionCategory
ClangCheckCategory("clang-check options");
59 static const opt::OptTable
&Options
= getDriverOptTable();
62 cl::desc(Options
.getOptionHelpText(options::OPT_ast_dump
)),
63 cl::cat(ClangCheckCategory
));
66 cl::desc(Options
.getOptionHelpText(options::OPT_ast_list
)),
67 cl::cat(ClangCheckCategory
));
70 cl::desc(Options
.getOptionHelpText(options::OPT_ast_print
)),
71 cl::cat(ClangCheckCategory
));
72 static cl::opt
<std::string
> ASTDumpFilter(
74 cl::desc(Options
.getOptionHelpText(options::OPT_ast_dump_filter
)),
75 cl::cat(ClangCheckCategory
));
78 cl::desc(Options
.getOptionHelpText(options::OPT_analyze
)),
79 cl::cat(ClangCheckCategory
));
80 static cl::opt
<std::string
>
81 AnalyzerOutput("analyzer-output-path",
82 cl::desc(Options
.getOptionHelpText(options::OPT_o
)),
83 cl::cat(ClangCheckCategory
));
86 Fixit("fixit", cl::desc(Options
.getOptionHelpText(options::OPT_fixit
)),
87 cl::cat(ClangCheckCategory
));
88 static cl::opt
<bool> FixWhatYouCan(
90 cl::desc(Options
.getOptionHelpText(options::OPT_fix_what_you_can
)),
91 cl::cat(ClangCheckCategory
));
93 static cl::opt
<bool> SyntaxTreeDump("syntax-tree-dump",
94 cl::desc("dump the syntax tree"),
95 cl::cat(ClangCheckCategory
));
96 static cl::opt
<bool> TokensDump("tokens-dump",
97 cl::desc("dump the preprocessed tokens"),
98 cl::cat(ClangCheckCategory
));
102 // FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
103 // into a header file and reuse that.
104 class FixItOptions
: public clang::FixItOptions
{
107 FixWhatYouCan
= ::FixWhatYouCan
;
110 std::string
RewriteFilename(const std::string
& filename
, int &fd
) override
{
111 // We don't need to do permission checking here since clang will diagnose
112 // any I/O errors itself.
114 fd
= -1; // No file descriptor for file.
120 /// Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
121 /// in the final error counts.
123 /// This has the side-effect that clang-check -fixit exits with code 0 on
124 /// successfully fixing all errors.
125 class FixItRewriter
: public clang::FixItRewriter
{
127 FixItRewriter(clang::DiagnosticsEngine
& Diags
,
128 clang::SourceManager
& SourceMgr
,
129 const clang::LangOptions
& LangOpts
,
130 clang::FixItOptions
* FixItOpts
)
131 : clang::FixItRewriter(Diags
, SourceMgr
, LangOpts
, FixItOpts
) {
134 bool IncludeInDiagnosticCounts() const override
{ return false; }
137 /// Subclasses \c clang::FixItAction so that we can install the custom
138 /// \c FixItRewriter.
139 class ClangCheckFixItAction
: public clang::FixItAction
{
141 bool BeginSourceFileAction(clang::CompilerInstance
& CI
) override
{
142 FixItOpts
.reset(new FixItOptions
);
143 Rewriter
.reset(new FixItRewriter(CI
.getDiagnostics(), CI
.getSourceManager(),
144 CI
.getLangOpts(), FixItOpts
.get()));
149 class DumpSyntaxTree
: public clang::ASTFrontendAction
{
151 std::unique_ptr
<clang::ASTConsumer
>
152 CreateASTConsumer(clang::CompilerInstance
&CI
, StringRef InFile
) override
{
153 class Consumer
: public clang::ASTConsumer
{
155 Consumer(clang::CompilerInstance
&CI
) : Collector(CI
.getPreprocessor()) {}
157 void HandleTranslationUnit(clang::ASTContext
&AST
) override
{
158 clang::syntax::TokenBuffer TB
= std::move(Collector
).consume();
160 llvm::outs() << TB
.dumpForTests();
161 clang::syntax::TokenBufferTokenManager
TBTM(TB
, AST
.getLangOpts(),
162 AST
.getSourceManager());
163 clang::syntax::Arena A
;
165 << clang::syntax::buildSyntaxTree(A
, TBTM
, AST
)->dump(TBTM
);
169 clang::syntax::TokenCollector Collector
;
171 return std::make_unique
<Consumer
>(CI
);
175 class ClangCheckActionFactory
{
177 std::unique_ptr
<clang::ASTConsumer
> newASTConsumer() {
179 return clang::CreateASTDeclNodeLister();
181 return clang::CreateASTDumper(nullptr /*Dump to stdout.*/, ASTDumpFilter
,
183 /*Deserialize=*/false,
184 /*DumpLookups=*/false,
185 /*DumpDeclTypes=*/false,
186 clang::ADOF_Default
);
188 return clang::CreateASTPrinter(nullptr, ASTDumpFilter
);
189 return std::make_unique
<clang::ASTConsumer
>();
195 int main(int argc
, const char **argv
) {
196 llvm::sys::PrintStackTraceOnErrorSignal(argv
[0]);
198 // Initialize targets for clang module support.
199 llvm::InitializeAllTargets();
200 llvm::InitializeAllTargetMCs();
201 llvm::InitializeAllAsmPrinters();
202 llvm::InitializeAllAsmParsers();
204 auto ExpectedParser
=
205 CommonOptionsParser::create(argc
, argv
, ClangCheckCategory
);
206 if (!ExpectedParser
) {
207 llvm::errs() << ExpectedParser
.takeError();
210 CommonOptionsParser
&OptionsParser
= ExpectedParser
.get();
211 ClangTool
Tool(OptionsParser
.getCompilations(),
212 OptionsParser
.getSourcePathList());
215 // Set output path if is provided by user.
217 // As the original -o options have been removed by default via the
218 // strip-output adjuster, we only need to add the analyzer -o options here
219 // when it is provided by users.
220 if (!AnalyzerOutput
.empty())
221 Tool
.appendArgumentsAdjuster(
222 getInsertArgumentAdjuster(CommandLineArguments
{"-o", AnalyzerOutput
},
223 ArgumentInsertPosition::END
));
225 // Running the analyzer requires --analyze. Other modes can work with the
226 // -fsyntax-only option.
228 // The syntax-only adjuster is installed by default.
229 // Good: It also strips options that trigger extra output, like -save-temps.
230 // Bad: We don't want the -fsyntax-only when executing the static analyzer.
232 // To enable the static analyzer, we first strip all -fsyntax-only options
233 // and then add an --analyze option to the front.
234 Tool
.appendArgumentsAdjuster(
235 [&](const CommandLineArguments
&Args
, StringRef
/*unused*/) {
236 CommandLineArguments AdjustedArgs
;
237 for (const std::string
&Arg
: Args
)
238 if (Arg
!= "-fsyntax-only")
239 AdjustedArgs
.emplace_back(Arg
);
242 Tool
.appendArgumentsAdjuster(
243 getInsertArgumentAdjuster("--analyze", ArgumentInsertPosition::BEGIN
));
246 ClangCheckActionFactory CheckFactory
;
247 std::unique_ptr
<FrontendActionFactory
> FrontendFactory
;
249 // Choose the correct factory based on the selected mode.
251 FrontendFactory
= newFrontendActionFactory
<clang::ento::AnalysisAction
>();
253 FrontendFactory
= newFrontendActionFactory
<ClangCheckFixItAction
>();
254 else if (SyntaxTreeDump
|| TokensDump
)
255 FrontendFactory
= newFrontendActionFactory
<DumpSyntaxTree
>();
257 FrontendFactory
= newFrontendActionFactory(&CheckFactory
);
259 return Tool
.run(FrontendFactory
.get());