clang-tools  3.8.0
ClangTidyMain.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-tidy/ClangTidyMain.cpp - Clang tidy tool -------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file This file implements a clang-tidy tool.
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 "../ClangTidy.h"
19 #include "clang/Tooling/CommonOptionsParser.h"
20 #include "llvm/Support/Process.h"
21 
22 using namespace clang::ast_matchers;
23 using namespace clang::driver;
24 using namespace clang::tooling;
25 using namespace llvm;
26 
27 static cl::OptionCategory ClangTidyCategory("clang-tidy options");
28 
29 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
30 static cl::extrahelp ClangTidyHelp(
31  "Configuration files:\n"
32  " clang-tidy attempts to read configuration for each source file from a\n"
33  " .clang-tidy file located in the closest parent directory of the source\n"
34  " file. If any configuration options have a corresponding command-line\n"
35  " option, command-line option takes precedence. The effective\n"
36  " configuration can be inspected using -dump-config:\n"
37  "\n"
38  " $ clang-tidy -dump-config - --\n"
39  " ---\n"
40  " Checks: '-*,some-check'\n"
41  " HeaderFilterRegex: ''\n"
42  " AnalyzeTemporaryDtors: false\n"
43  " User: user\n"
44  " CheckOptions: \n"
45  " - key: some-check.SomeOption\n"
46  " value: 'some value'\n"
47  " ...\n"
48  "\n\n");
49 
50 const char DefaultChecks[] = // Enable these checks:
51  "clang-diagnostic-*," // * compiler diagnostics
52  "clang-analyzer-*," // * Static Analyzer checks
53  "-clang-analyzer-alpha*"; // * but not alpha checks: many false positives
54 
55 static cl::opt<std::string>
56 Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n"
57  "prefix. Globs are processed in order of appearance\n"
58  "in the list. Globs without '-' prefix add checks\n"
59  "with matching names to the set, globs with the '-'\n"
60  "prefix remove checks with matching names from the\n"
61  "set of enabled checks.\n"
62  "This option's value is appended to the value read\n"
63  "from a .clang-tidy file, if any."),
64  cl::init(""), cl::cat(ClangTidyCategory));
65 
66 static cl::opt<std::string>
67 HeaderFilter("header-filter",
68  cl::desc("Regular expression matching the names of the\n"
69  "headers to output diagnostics from. Diagnostics\n"
70  "from the main file of each translation unit are\n"
71  "always displayed.\n"
72  "Can be used together with -line-filter.\n"
73  "This option overrides the value read from a\n"
74  ".clang-tidy file."),
75  cl::init(""), cl::cat(ClangTidyCategory));
76 
77 static cl::opt<bool>
78  SystemHeaders("system-headers",
79  cl::desc("Display the errors from system headers."),
80  cl::init(false), cl::cat(ClangTidyCategory));
81 static cl::opt<std::string>
82 LineFilter("line-filter",
83  cl::desc("List of files with line ranges to filter the\n"
84  "warnings. Can be used together with\n"
85  "-header-filter. The format of the list is a JSON\n"
86  "array of objects:\n"
87  " [\n"
88  " {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"
89  " {\"name\":\"file2.h\"}\n"
90  " ]"),
91  cl::init(""), cl::cat(ClangTidyCategory));
92 
93 static cl::opt<bool>
94  Fix("fix", cl::desc("Apply suggested fixes. Without -fix-errors\n"
95  "clang-tidy will bail out if any compilation\n"
96  "errors were found."),
97  cl::init(false), cl::cat(ClangTidyCategory));
98 
99 static cl::opt<bool>
100  FixErrors("fix-errors",
101  cl::desc("Apply suggested fixes even if compilation errors\n"
102  "were found. If compiler errors have attached\n"
103  "fix-its, clang-tidy will apply them as well."),
104  cl::init(false), cl::cat(ClangTidyCategory));
105 
106 static cl::opt<bool>
107 ListChecks("list-checks",
108  cl::desc("List all enabled checks and exit. Use with\n"
109  "-checks=* to list all available checks."),
110  cl::init(false), cl::cat(ClangTidyCategory));
111 
112 static cl::opt<std::string> Config(
113  "config",
114  cl::desc("Specifies a configuration in YAML/JSON format:\n"
115  " -config=\"{Checks: '*', CheckOptions: [{key: x, value: y}]}\"\n"
116  "When the value is empty, clang-tidy will attempt to find\n"
117  "a file named .clang-tidy for each source file in its parent\n"
118  "directories."),
119  cl::init(""), cl::cat(ClangTidyCategory));
120 
121 static cl::opt<bool> DumpConfig(
122  "dump-config",
123  cl::desc("Dumps configuration in the YAML format to stdout. This option\n"
124  "can be used along with a file name (and '--' if the file is\n"
125  "outside of a project with configured compilation database). The\n"
126  "configuration used for this file will be printed.\n"
127  "Use along with -checks=* to include configuration of all\n"
128  "checks.\n"),
129  cl::init(false), cl::cat(ClangTidyCategory));
130 
131 static cl::opt<bool> EnableCheckProfile(
132  "enable-check-profile",
133  cl::desc("Enable per-check timing profiles, and print a report to stderr."),
134  cl::init(false), cl::cat(ClangTidyCategory));
135 
136 static cl::opt<bool> AnalyzeTemporaryDtors(
137  "analyze-temporary-dtors",
138  cl::desc("Enable temporary destructor-aware analysis in\n"
139  "clang-analyzer- checks.\n"
140  "This option overrides the value read from a\n"
141  ".clang-tidy file."),
142  cl::init(false), cl::cat(ClangTidyCategory));
143 
144 static cl::opt<std::string> ExportFixes(
145  "export-fixes",
146  cl::desc("YAML file to store suggested fixes in. The\n"
147  "stored fixes can be applied to the input source\n"
148  "code with clang-apply-replacements."),
149  cl::value_desc("filename"), cl::cat(ClangTidyCategory));
150 
151 namespace clang {
152 namespace tidy {
153 
154 static void printStats(const ClangTidyStats &Stats) {
155  if (Stats.errorsIgnored()) {
156  llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
157  StringRef Separator = "";
158  if (Stats.ErrorsIgnoredNonUserCode) {
159  llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
160  Separator = ", ";
161  }
162  if (Stats.ErrorsIgnoredLineFilter) {
163  llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
164  << " due to line filter";
165  Separator = ", ";
166  }
167  if (Stats.ErrorsIgnoredNOLINT) {
168  llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
169  Separator = ", ";
170  }
171  if (Stats.ErrorsIgnoredCheckFilter)
172  llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
173  << " with check filters";
174  llvm::errs() << ").\n";
175  if (Stats.ErrorsIgnoredNonUserCode)
176  llvm::errs() << "Use -header-filter=.* to display errors from all "
177  "non-system headers.\n";
178  }
179 }
180 
181 static void printProfileData(const ProfileData &Profile,
182  llvm::raw_ostream &OS) {
183  // Time is first to allow for sorting by it.
184  std::vector<std::pair<llvm::TimeRecord, StringRef>> Timers;
185  TimeRecord Total;
186 
187  for (const auto& P : Profile.Records) {
188  Timers.emplace_back(P.getValue(), P.getKey());
189  Total += P.getValue();
190  }
191 
192  std::sort(Timers.begin(), Timers.end());
193 
194  std::string Line = "===" + std::string(73, '-') + "===\n";
195  OS << Line;
196 
197  if (Total.getUserTime())
198  OS << " ---User Time---";
199  if (Total.getSystemTime())
200  OS << " --System Time--";
201  if (Total.getProcessTime())
202  OS << " --User+System--";
203  OS << " ---Wall Time---";
204  if (Total.getMemUsed())
205  OS << " ---Mem---";
206  OS << " --- Name ---\n";
207 
208  // Loop through all of the timing data, printing it out.
209  for (auto I = Timers.rbegin(), E = Timers.rend(); I != E; ++I) {
210  I->first.print(Total, OS);
211  OS << I->second << '\n';
212  }
213 
214  Total.print(Total, OS);
215  OS << "Total\n";
216  OS << Line << "\n";
217  OS.flush();
218 }
219 
220 static std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider() {
221  ClangTidyGlobalOptions GlobalOptions;
222  if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
223  llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
224  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
225  return nullptr;
226  }
227 
228  ClangTidyOptions DefaultOptions;
229  DefaultOptions.Checks = DefaultChecks;
230  DefaultOptions.HeaderFilterRegex = HeaderFilter;
231  DefaultOptions.SystemHeaders = SystemHeaders;
233  DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
234  // USERNAME is used on Windows.
235  if (!DefaultOptions.User)
236  DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");
237 
238  ClangTidyOptions OverrideOptions;
239  if (Checks.getNumOccurrences() > 0)
240  OverrideOptions.Checks = Checks;
241  if (HeaderFilter.getNumOccurrences() > 0)
242  OverrideOptions.HeaderFilterRegex = HeaderFilter;
243  if (SystemHeaders.getNumOccurrences() > 0)
244  OverrideOptions.SystemHeaders = SystemHeaders;
245  if (AnalyzeTemporaryDtors.getNumOccurrences() > 0)
247 
248  if (!Config.empty()) {
249  if (llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
251  return llvm::make_unique<DefaultOptionsProvider>(
252  GlobalOptions, ClangTidyOptions::getDefaults()
253  .mergeWith(DefaultOptions)
254  .mergeWith(*ParsedConfig)
255  .mergeWith(OverrideOptions));
256  } else {
257  llvm::errs() << "Error: invalid configuration specified.\n"
258  << ParsedConfig.getError().message() << "\n";
259  return nullptr;
260  }
261  }
262  return llvm::make_unique<FileOptionsProvider>(GlobalOptions, DefaultOptions,
263  OverrideOptions);
264 }
265 
266 static int clangTidyMain(int argc, const char **argv) {
267  CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory,
268  cl::ZeroOrMore);
269 
270  auto OptionsProvider = createOptionsProvider();
271  if (!OptionsProvider)
272  return 1;
273 
274  StringRef FileName("dummy");
275  auto PathList = OptionsParser.getSourcePathList();
276  if (!PathList.empty()) {
277  FileName = PathList.front();
278  }
279  ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName);
280  std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions);
281 
282  if (ListChecks) {
283  llvm::outs() << "Enabled checks:";
284  for (auto CheckName : EnabledChecks)
285  llvm::outs() << "\n " << CheckName;
286  llvm::outs() << "\n\n";
287  return 0;
288  }
289 
290  if (DumpConfig) {
291  EffectiveOptions.CheckOptions = getCheckOptions(EffectiveOptions);
292  llvm::outs() << configurationAsText(
293  ClangTidyOptions::getDefaults().mergeWith(
294  EffectiveOptions))
295  << "\n";
296  return 0;
297  }
298 
299  if (EnabledChecks.empty()) {
300  llvm::errs() << "Error: no checks enabled.\n";
301  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
302  return 1;
303  }
304 
305  if (PathList.empty()) {
306  llvm::errs() << "Error: no input files specified.\n";
307  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
308  return 1;
309  }
310 
311  ProfileData Profile;
312 
313  std::vector<ClangTidyError> Errors;
314  ClangTidyStats Stats =
315  runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
316  PathList, &Errors,
317  EnableCheckProfile ? &Profile : nullptr);
318  bool FoundErrors =
319  std::find_if(Errors.begin(), Errors.end(), [](const ClangTidyError &E) {
320  return E.DiagLevel == ClangTidyError::Error;
321  }) != Errors.end();
322 
323  const bool DisableFixes = Fix && FoundErrors && !FixErrors;
324 
325  // -fix-errors implies -fix.
326  handleErrors(Errors, (FixErrors || Fix) && !DisableFixes);
327 
328  if (!ExportFixes.empty() && !Errors.empty()) {
329  std::error_code EC;
330  llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
331  if (EC) {
332  llvm::errs() << "Error opening output file: " << EC.message() << '\n';
333  return 1;
334  }
335  exportReplacements(Errors, OS);
336  }
337 
338  printStats(Stats);
339  if (DisableFixes)
340  llvm::errs()
341  << "Found compiler errors, but -fix-errors was not specified.\n"
342  "Fixes have NOT been applied.\n\n";
343 
344  if (EnableCheckProfile)
345  printProfileData(Profile, llvm::errs());
346 
347  return 0;
348 }
349 
350 // This anchor is used to force the linker to link the CERTModule.
351 extern volatile int CERTModuleAnchorSource;
352 static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
354 
355 // This anchor is used to force the linker to link the LLVMModule.
356 extern volatile int LLVMModuleAnchorSource;
357 static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
359 
360 // This anchor is used to force the linker to link the CppCoreGuidelinesModule.
361 extern volatile int CppCoreGuidelinesModuleAnchorSource;
362 static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
364 
365 // This anchor is used to force the linker to link the GoogleModule.
366 extern volatile int GoogleModuleAnchorSource;
367 static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
369 
370 // This anchor is used to force the linker to link the MiscModule.
371 extern volatile int MiscModuleAnchorSource;
372 static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
374 
375 // This anchor is used to force the linker to link the ModernizeModule.
376 extern volatile int ModernizeModuleAnchorSource;
377 static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
379 
380 // This anchor is used to force the linker to link the PerformanceModule.
381 extern volatile int PerformanceModuleAnchorSource;
382 static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
384 
385 // This anchor is used to force the linker to link the ReadabilityModule.
386 extern volatile int ReadabilityModuleAnchorSource;
387 static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
389 
390 } // namespace tidy
391 } // namespace clang
392 
393 int main(int argc, const char **argv) {
394  return clang::tidy::clangTidyMain(argc, argv);
395 }
llvm::Optional< std::string > Checks
Checks filter.
volatile int GoogleModuleAnchorSource
static void printStats(const ClangTidyStats &Stats)
llvm::Optional< std::string > User
Specifies the name or e-mail of the user running clang-tidy.
static cl::opt< bool > SystemHeaders("system-headers", cl::desc("Display the errors from system headers."), cl::init(false), cl::cat(ClangTidyCategory))
volatile int ReadabilityModuleAnchorSource
static cl::opt< bool > ListChecks("list-checks", cl::desc("List all enabled checks and exit. Use with\n""-checks=* to list all available checks."), cl::init(false), cl::cat(ClangTidyCategory))
static cl::opt< bool > DumpConfig("dump-config", cl::desc("Dumps configuration in the YAML format to stdout. This option\n""can be used along with a file name (and '--' if the file is\n""outside of a project with configured compilation database). The\n""configuration used for this file will be printed.\n""Use along with -checks=* to include configuration of all\n""checks.\n"), cl::init(false), cl::cat(ClangTidyCategory))
llvm::Optional< std::string > HeaderFilterRegex
Output warnings from headers matching this filter.
ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options)
Returns the effective check-specific options.
Definition: ClangTidy.cpp:362
static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination
Contains options for clang-tidy.
std::error_code parseLineFilter(StringRef LineFilter, clang::tidy::ClangTidyGlobalOptions &Options)
Parses -line-filter option and stores it to the Options.
llvm::StringMap< llvm::TimeRecord > Records
llvm::ErrorOr< ClangTidyOptions > parseConfiguration(StringRef Config)
OptionMap CheckOptions
Key-value mapping used to store check-specific options.
llvm::Optional< bool > SystemHeaders
Output warnings from system headers matching HeaderFilterRegex.
volatile int LLVMModuleAnchorSource
volatile int PerformanceModuleAnchorSource
static cl::opt< bool > EnableCheckProfile("enable-check-profile", cl::desc("Enable per-check timing profiles, and print a report to stderr."), cl::init(false), cl::cat(ClangTidyCategory))
void exportReplacements(const std::vector< ClangTidyError > &Errors, raw_ostream &OS)
Serializes replacements into YAML and writes them to the specified output stream. ...
Definition: ClangTidy.cpp:431
static cl::opt< std::string > LineFilter("line-filter", cl::desc("List of files with line ranges to filter the\n""warnings. Can be used together with\n""-header-filter. The format of the list is a JSON\n""array of objects:\n"" [\n"" {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"" {\"name\":\"file2.h\"}\n"" ]"), cl::init(""), cl::cat(ClangTidyCategory))
volatile int CppCoreGuidelinesModuleAnchorSource
void handleErrors(const std::vector< ClangTidyError > &Errors, bool Fix)
Displays the found Errors to the users.
Definition: ClangTidy.cpp:424
static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination
static cl::opt< std::string > Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n""prefix. Globs are processed in order of appearance\n""in the list. Globs without '-' prefix add checks\n""with matching names to the set, globs with the '-'\n""prefix remove checks with matching names from the\n""set of enabled checks.\n""This option's value is appended to the value read\n""from a .clang-tidy file, if any."), cl::init(""), cl::cat(ClangTidyCategory))
std::string configurationAsText(const ClangTidyOptions &Options)
Serializes configuration to a YAML-encoded string.
volatile int CERTModuleAnchorSource
static cl::OptionCategory ClangTidyCategory("clang-tidy options")
static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination
std::vector< std::string > getCheckNames(const ClangTidyOptions &Options)
Fills the list of check names that are enabled when the provided filters are applied.
Definition: ClangTidy.cpp:354
ClangTidyStats runClangTidy(std::unique_ptr< ClangTidyOptionsProvider > OptionsProvider, const tooling::CompilationDatabase &Compilations, ArrayRef< std::string > InputFiles, std::vector< ClangTidyError > *Errors, ProfileData *Profile)
Run a set of clang-tidy checks on a set of files.
Definition: ClangTidy.cpp:371
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage)
static void printProfileData(const ProfileData &Profile, llvm::raw_ostream &OS)
volatile int MiscModuleAnchorSource
static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination
static int clangTidyMain(int argc, const char **argv)
static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination
static cl::opt< std::string > Config("config", cl::desc("Specifies a configuration in YAML/JSON format:\n"" -config=\"{Checks: '*', CheckOptions: [{key: x, value: y}]}\"\n""When the value is empty, clang-tidy will attempt to find\n""a file named .clang-tidy for each source file in its parent\n""directories."), cl::init(""), cl::cat(ClangTidyCategory))
static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination
llvm::Optional< bool > AnalyzeTemporaryDtors
Turns on temporary destructor-based analysis.
static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination
static cl::extrahelp ClangTidyHelp("Configuration files:\n"" clang-tidy attempts to read configuration for each source file from a\n"" .clang-tidy file located in the closest parent directory of the source\n"" file. If any configuration options have a corresponding command-line\n"" option, command-line option takes precedence. The effective\n"" configuration can be inspected using -dump-config:\n""\n"" $ clang-tidy -dump-config - --\n"" ---\n"" Checks: '-*,some-check'\n"" HeaderFilterRegex: ''\n"" AnalyzeTemporaryDtors: false\n"" User: user\n"" CheckOptions: \n"" - key: some-check.SomeOption\n"" value: 'some value'\n"" ...\n""\n\n")
const char DefaultChecks[]
static std::unique_ptr< ClangTidyOptionsProvider > createOptionsProvider()
int main(int argc, const char **argv)
static cl::opt< bool > FixErrors("fix-errors", cl::desc("Apply suggested fixes even if compilation errors\n""were found. If compiler errors have attached\n""fix-its, clang-tidy will apply them as well."), cl::init(false), cl::cat(ClangTidyCategory))
A detected error complete with information to display diagnostic and automatic fix.
Contains displayed and ignored diagnostic counters for a ClangTidy run.
volatile int ModernizeModuleAnchorSource
static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination
static cl::opt< std::string > ExportFixes("export-fixes", cl::desc("YAML file to store suggested fixes in. The\n""stored fixes can be applied to the input source\n""code with clang-apply-replacements."), cl::value_desc("filename"), cl::cat(ClangTidyCategory))
static cl::opt< bool > Fix("fix", cl::desc("Apply suggested fixes. Without -fix-errors\n""clang-tidy will bail out if any compilation\n""errors were found."), cl::init(false), cl::cat(ClangTidyCategory))
static cl::opt< std::string > HeaderFilter("header-filter", cl::desc("Regular expression matching the names of the\n""headers to output diagnostics from. Diagnostics\n""from the main file of each translation unit are\n""always displayed.\n""Can be used together with -line-filter.\n""This option overrides the value read from a\n"".clang-tidy file."), cl::init(""), cl::cat(ClangTidyCategory))
Container for clang-tidy profiling data.
static cl::opt< bool > AnalyzeTemporaryDtors("analyze-temporary-dtors", cl::desc("Enable temporary destructor-aware analysis in\n""clang-analyzer- checks.\n""This option overrides the value read from a\n"".clang-tidy file."), cl::init(false), cl::cat(ClangTidyCategory))