1*67e74705SXin Li //===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This file implements a clang-check tool that runs clang based on the info
11*67e74705SXin Li // stored in a compilation database.
12*67e74705SXin Li //
13*67e74705SXin Li // This tool uses the Clang Tooling infrastructure, see
14*67e74705SXin Li // http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
15*67e74705SXin Li // for details on setting it up with LLVM source tree.
16*67e74705SXin Li //
17*67e74705SXin Li //===----------------------------------------------------------------------===//
18*67e74705SXin Li
19*67e74705SXin Li #include "clang/AST/ASTConsumer.h"
20*67e74705SXin Li #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
21*67e74705SXin Li #include "clang/Driver/Options.h"
22*67e74705SXin Li #include "clang/Frontend/ASTConsumers.h"
23*67e74705SXin Li #include "clang/Frontend/CompilerInstance.h"
24*67e74705SXin Li #include "clang/Rewrite/Frontend/FixItRewriter.h"
25*67e74705SXin Li #include "clang/Rewrite/Frontend/FrontendActions.h"
26*67e74705SXin Li #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
27*67e74705SXin Li #include "clang/Tooling/CommonOptionsParser.h"
28*67e74705SXin Li #include "clang/Tooling/Tooling.h"
29*67e74705SXin Li #include "llvm/ADT/STLExtras.h"
30*67e74705SXin Li #include "llvm/Option/OptTable.h"
31*67e74705SXin Li #include "llvm/Support/Path.h"
32*67e74705SXin Li #include "llvm/Support/Signals.h"
33*67e74705SXin Li #include "llvm/Support/TargetSelect.h"
34*67e74705SXin Li
35*67e74705SXin Li using namespace clang::driver;
36*67e74705SXin Li using namespace clang::tooling;
37*67e74705SXin Li using namespace llvm;
38*67e74705SXin Li
39*67e74705SXin Li static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
40*67e74705SXin Li static cl::extrahelp MoreHelp(
41*67e74705SXin Li "\tFor example, to run clang-check on all files in a subtree of the\n"
42*67e74705SXin Li "\tsource tree, use:\n"
43*67e74705SXin Li "\n"
44*67e74705SXin Li "\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
45*67e74705SXin Li "\n"
46*67e74705SXin Li "\tor using a specific build path:\n"
47*67e74705SXin Li "\n"
48*67e74705SXin Li "\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
49*67e74705SXin Li "\n"
50*67e74705SXin Li "\tNote, that path/in/subtree and current directory should follow the\n"
51*67e74705SXin Li "\trules described above.\n"
52*67e74705SXin Li "\n"
53*67e74705SXin Li );
54*67e74705SXin Li
55*67e74705SXin Li static cl::OptionCategory ClangCheckCategory("clang-check options");
56*67e74705SXin Li static std::unique_ptr<opt::OptTable> Options(createDriverOptTable());
57*67e74705SXin Li static cl::opt<bool>
58*67e74705SXin Li ASTDump("ast-dump", cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)),
59*67e74705SXin Li cl::cat(ClangCheckCategory));
60*67e74705SXin Li static cl::opt<bool>
61*67e74705SXin Li ASTList("ast-list", cl::desc(Options->getOptionHelpText(options::OPT_ast_list)),
62*67e74705SXin Li cl::cat(ClangCheckCategory));
63*67e74705SXin Li static cl::opt<bool>
64*67e74705SXin Li ASTPrint("ast-print",
65*67e74705SXin Li cl::desc(Options->getOptionHelpText(options::OPT_ast_print)),
66*67e74705SXin Li cl::cat(ClangCheckCategory));
67*67e74705SXin Li static cl::opt<std::string> ASTDumpFilter(
68*67e74705SXin Li "ast-dump-filter",
69*67e74705SXin Li cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)),
70*67e74705SXin Li cl::cat(ClangCheckCategory));
71*67e74705SXin Li static cl::opt<bool>
72*67e74705SXin Li Analyze("analyze", cl::desc(Options->getOptionHelpText(options::OPT_analyze)),
73*67e74705SXin Li cl::cat(ClangCheckCategory));
74*67e74705SXin Li
75*67e74705SXin Li static cl::opt<bool>
76*67e74705SXin Li Fixit("fixit", cl::desc(Options->getOptionHelpText(options::OPT_fixit)),
77*67e74705SXin Li cl::cat(ClangCheckCategory));
78*67e74705SXin Li static cl::opt<bool> FixWhatYouCan(
79*67e74705SXin Li "fix-what-you-can",
80*67e74705SXin Li cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
81*67e74705SXin Li cl::cat(ClangCheckCategory));
82*67e74705SXin Li
83*67e74705SXin Li namespace {
84*67e74705SXin Li
85*67e74705SXin Li // FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
86*67e74705SXin Li // into a header file and reuse that.
87*67e74705SXin Li class FixItOptions : public clang::FixItOptions {
88*67e74705SXin Li public:
FixItOptions()89*67e74705SXin Li FixItOptions() {
90*67e74705SXin Li FixWhatYouCan = ::FixWhatYouCan;
91*67e74705SXin Li }
92*67e74705SXin Li
RewriteFilename(const std::string & filename,int & fd)93*67e74705SXin Li std::string RewriteFilename(const std::string& filename, int &fd) override {
94*67e74705SXin Li assert(llvm::sys::path::is_absolute(filename) &&
95*67e74705SXin Li "clang-fixit expects absolute paths only.");
96*67e74705SXin Li
97*67e74705SXin Li // We don't need to do permission checking here since clang will diagnose
98*67e74705SXin Li // any I/O errors itself.
99*67e74705SXin Li
100*67e74705SXin Li fd = -1; // No file descriptor for file.
101*67e74705SXin Li
102*67e74705SXin Li return filename;
103*67e74705SXin Li }
104*67e74705SXin Li };
105*67e74705SXin Li
106*67e74705SXin Li /// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
107*67e74705SXin Li /// in the final error counts.
108*67e74705SXin Li ///
109*67e74705SXin Li /// This has the side-effect that clang-check -fixit exits with code 0 on
110*67e74705SXin Li /// successfully fixing all errors.
111*67e74705SXin Li class FixItRewriter : public clang::FixItRewriter {
112*67e74705SXin Li public:
FixItRewriter(clang::DiagnosticsEngine & Diags,clang::SourceManager & SourceMgr,const clang::LangOptions & LangOpts,clang::FixItOptions * FixItOpts)113*67e74705SXin Li FixItRewriter(clang::DiagnosticsEngine& Diags,
114*67e74705SXin Li clang::SourceManager& SourceMgr,
115*67e74705SXin Li const clang::LangOptions& LangOpts,
116*67e74705SXin Li clang::FixItOptions* FixItOpts)
117*67e74705SXin Li : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
118*67e74705SXin Li }
119*67e74705SXin Li
IncludeInDiagnosticCounts() const120*67e74705SXin Li bool IncludeInDiagnosticCounts() const override { return false; }
121*67e74705SXin Li };
122*67e74705SXin Li
123*67e74705SXin Li /// \brief Subclasses \c clang::FixItAction so that we can install the custom
124*67e74705SXin Li /// \c FixItRewriter.
125*67e74705SXin Li class FixItAction : public clang::FixItAction {
126*67e74705SXin Li public:
BeginSourceFileAction(clang::CompilerInstance & CI,StringRef Filename)127*67e74705SXin Li bool BeginSourceFileAction(clang::CompilerInstance& CI,
128*67e74705SXin Li StringRef Filename) override {
129*67e74705SXin Li FixItOpts.reset(new FixItOptions);
130*67e74705SXin Li Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
131*67e74705SXin Li CI.getLangOpts(), FixItOpts.get()));
132*67e74705SXin Li return true;
133*67e74705SXin Li }
134*67e74705SXin Li };
135*67e74705SXin Li
136*67e74705SXin Li class ClangCheckActionFactory {
137*67e74705SXin Li public:
newASTConsumer()138*67e74705SXin Li std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
139*67e74705SXin Li if (ASTList)
140*67e74705SXin Li return clang::CreateASTDeclNodeLister();
141*67e74705SXin Li if (ASTDump)
142*67e74705SXin Li return clang::CreateASTDumper(ASTDumpFilter, /*DumpDecls=*/true,
143*67e74705SXin Li /*DumpLookups=*/false);
144*67e74705SXin Li if (ASTPrint)
145*67e74705SXin Li return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
146*67e74705SXin Li return llvm::make_unique<clang::ASTConsumer>();
147*67e74705SXin Li }
148*67e74705SXin Li };
149*67e74705SXin Li
150*67e74705SXin Li } // namespace
151*67e74705SXin Li
main(int argc,const char ** argv)152*67e74705SXin Li int main(int argc, const char **argv) {
153*67e74705SXin Li llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
154*67e74705SXin Li
155*67e74705SXin Li // Initialize targets for clang module support.
156*67e74705SXin Li llvm::InitializeAllTargets();
157*67e74705SXin Li llvm::InitializeAllTargetMCs();
158*67e74705SXin Li llvm::InitializeAllAsmPrinters();
159*67e74705SXin Li llvm::InitializeAllAsmParsers();
160*67e74705SXin Li
161*67e74705SXin Li CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory);
162*67e74705SXin Li ClangTool Tool(OptionsParser.getCompilations(),
163*67e74705SXin Li OptionsParser.getSourcePathList());
164*67e74705SXin Li
165*67e74705SXin Li // Clear adjusters because -fsyntax-only is inserted by the default chain.
166*67e74705SXin Li Tool.clearArgumentsAdjusters();
167*67e74705SXin Li Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());
168*67e74705SXin Li
169*67e74705SXin Li // Running the analyzer requires --analyze. Other modes can work with the
170*67e74705SXin Li // -fsyntax-only option.
171*67e74705SXin Li Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
172*67e74705SXin Li Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));
173*67e74705SXin Li
174*67e74705SXin Li ClangCheckActionFactory CheckFactory;
175*67e74705SXin Li std::unique_ptr<FrontendActionFactory> FrontendFactory;
176*67e74705SXin Li
177*67e74705SXin Li // Choose the correct factory based on the selected mode.
178*67e74705SXin Li if (Analyze)
179*67e74705SXin Li FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
180*67e74705SXin Li else if (Fixit)
181*67e74705SXin Li FrontendFactory = newFrontendActionFactory<FixItAction>();
182*67e74705SXin Li else
183*67e74705SXin Li FrontendFactory = newFrontendActionFactory(&CheckFactory);
184*67e74705SXin Li
185*67e74705SXin Li return Tool.run(FrontendFactory.get());
186*67e74705SXin Li }
187