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