clang-tools  16.0.0git
ClangTidyMain.cpp
Go to the documentation of this file.
1 //===--- tools/extra/clang-tidy/ClangTidyMain.cpp - Clang tidy 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 /// \file This file implements a clang-tidy tool.
10 ///
11 /// This tool uses the Clang Tooling infrastructure, see
12 /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
13 /// for details on setting it up with LLVM source tree.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "ClangTidyMain.h"
18 #include "../ClangTidy.h"
19 #include "../ClangTidyForceLinker.h"
20 #include "../GlobList.h"
21 #include "clang/Tooling/CommonOptionsParser.h"
22 #include "llvm/ADT/StringSet.h"
23 #include "llvm/Support/InitLLVM.h"
24 #include "llvm/Support/PluginLoader.h"
25 #include "llvm/Support/Process.h"
26 #include "llvm/Support/Signals.h"
27 #include "llvm/Support/TargetSelect.h"
28 #include "llvm/Support/WithColor.h"
29 
30 using namespace clang::tooling;
31 using namespace llvm;
32 
33 static cl::OptionCategory ClangTidyCategory("clang-tidy options");
34 
35 static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
36 static cl::extrahelp ClangTidyHelp(R"(
37 Configuration files:
38  clang-tidy attempts to read configuration for each source file from a
39  .clang-tidy file located in the closest parent directory of the source
40  file. If InheritParentConfig is true in a config file, the configuration file
41  in the parent directory (if any exists) will be taken and current config file
42  will be applied on top of the parent one. If any configuration options have
43  a corresponding command-line option, command-line option takes precedence.
44  The effective configuration can be inspected using -dump-config:
45 
46  $ clang-tidy -dump-config
47  ---
48  Checks: '-*,some-check'
49  WarningsAsErrors: ''
50  HeaderFilterRegex: ''
51  FormatStyle: none
52  InheritParentConfig: true
53  User: user
54  CheckOptions:
55  some-check.SomeOption: 'some value'
56  ...
57 
58 )");
59 
60 const char DefaultChecks[] = // Enable these checks by default:
61  "clang-diagnostic-*," // * compiler diagnostics
62  "clang-analyzer-*"; // * Static Analyzer checks
63 
64 static cl::opt<std::string> Checks("checks", cl::desc(R"(
65 Comma-separated list of globs with optional '-'
66 prefix. Globs are processed in order of
67 appearance in the list. Globs without '-'
68 prefix add checks with matching names to the
69 set, globs with the '-' prefix remove checks
70 with matching names from the set of enabled
71 checks. This option's value is appended to the
72 value of the 'Checks' option in .clang-tidy
73 file, if any.
74 )"),
75  cl::init(""), cl::cat(ClangTidyCategory));
76 
77 static cl::opt<std::string> WarningsAsErrors("warnings-as-errors", cl::desc(R"(
78 Upgrades warnings to errors. Same format as
79 '-checks'.
80 This option's value is appended to the value of
81 the 'WarningsAsErrors' option in .clang-tidy
82 file, if any.
83 )"),
84  cl::init(""),
85  cl::cat(ClangTidyCategory));
86 
87 static cl::opt<std::string> HeaderFilter("header-filter", cl::desc(R"(
88 Regular expression matching the names of the
89 headers to output diagnostics from. Diagnostics
90 from the main file of each translation unit are
91 always displayed.
92 Can be used together with -line-filter.
93 This option overrides the 'HeaderFilterRegex'
94 option in .clang-tidy file, if any.
95 )"),
96  cl::init(""),
97  cl::cat(ClangTidyCategory));
98 
99 static cl::opt<bool>
100  SystemHeaders("system-headers",
101  cl::desc("Display the errors from system headers."),
102  cl::init(false), cl::cat(ClangTidyCategory));
103 static cl::opt<std::string> LineFilter("line-filter", cl::desc(R"(
104 List of files with line ranges to filter the
105 warnings. Can be used together with
106 -header-filter. The format of the list is a
107 JSON array of objects:
108  [
109  {"name":"file1.cpp","lines":[[1,3],[5,7]]},
110  {"name":"file2.h"}
111  ]
112 )"),
113  cl::init(""),
114  cl::cat(ClangTidyCategory));
115 
116 static cl::opt<bool> Fix("fix", cl::desc(R"(
117 Apply suggested fixes. Without -fix-errors
118 clang-tidy will bail out if any compilation
119 errors were found.
120 )"),
121  cl::init(false), cl::cat(ClangTidyCategory));
122 
123 static cl::opt<bool> FixErrors("fix-errors", cl::desc(R"(
124 Apply suggested fixes even if compilation
125 errors were found. If compiler errors have
126 attached fix-its, clang-tidy will apply them as
127 well.
128 )"),
129  cl::init(false), cl::cat(ClangTidyCategory));
130 
131 static cl::opt<bool> FixNotes("fix-notes", cl::desc(R"(
132 If a warning has no fix, but a single fix can
133 be found through an associated diagnostic note,
134 apply the fix.
135 Specifying this flag will implicitly enable the
136 '--fix' flag.
137 )"),
138  cl::init(false), cl::cat(ClangTidyCategory));
139 
140 static cl::opt<std::string> FormatStyle("format-style", cl::desc(R"(
141 Style for formatting code around applied fixes:
142  - 'none' (default) turns off formatting
143  - 'file' (literally 'file', not a placeholder)
144  uses .clang-format file in the closest parent
145  directory
146  - '{ <json> }' specifies options inline, e.g.
147  -format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
148  - 'llvm', 'google', 'webkit', 'mozilla'
149 See clang-format documentation for the up-to-date
150 information about formatting styles and options.
151 This option overrides the 'FormatStyle` option in
152 .clang-tidy file, if any.
153 )"),
154  cl::init("none"),
155  cl::cat(ClangTidyCategory));
156 
157 static cl::opt<bool> ListChecks("list-checks", cl::desc(R"(
158 List all enabled checks and exit. Use with
159 -checks=* to list all available checks.
160 )"),
161  cl::init(false), cl::cat(ClangTidyCategory));
162 
163 static cl::opt<bool> ExplainConfig("explain-config", cl::desc(R"(
164 For each enabled check explains, where it is
165 enabled, i.e. in clang-tidy binary, command
166 line or a specific configuration file.
167 )"),
168  cl::init(false), cl::cat(ClangTidyCategory));
169 
170 static cl::opt<std::string> Config("config", cl::desc(R"(
171 Specifies a configuration in YAML/JSON format:
172  -config="{Checks: '*',
173  CheckOptions: {x: y}}"
174 When the value is empty, clang-tidy will
175 attempt to find a file named .clang-tidy for
176 each source file in its parent directories.
177 )"),
178  cl::init(""), cl::cat(ClangTidyCategory));
179 
180 static cl::opt<std::string> ConfigFile("config-file", cl::desc(R"(
181 Specify the path of .clang-tidy or custom config file:
182  e.g. --config-file=/some/path/myTidyConfigFile
183 This option internally works exactly the same way as
184  --config option after reading specified config file.
185 Use either --config-file or --config, not both.
186 )"),
187  cl::init(""),
188  cl::cat(ClangTidyCategory));
189 
190 static cl::opt<bool> DumpConfig("dump-config", cl::desc(R"(
191 Dumps configuration in the YAML format to
192 stdout. This option can be used along with a
193 file name (and '--' if the file is outside of a
194 project with configured compilation database).
195 The configuration used for this file will be
196 printed.
197 Use along with -checks=* to include
198 configuration of all checks.
199 )"),
200  cl::init(false), cl::cat(ClangTidyCategory));
201 
202 static cl::opt<bool> EnableCheckProfile("enable-check-profile", cl::desc(R"(
203 Enable per-check timing profiles, and print a
204 report to stderr.
205 )"),
206  cl::init(false),
207  cl::cat(ClangTidyCategory));
208 
209 static cl::opt<std::string> StoreCheckProfile("store-check-profile",
210  cl::desc(R"(
211 By default reports are printed in tabulated
212 format to stderr. When this option is passed,
213 these per-TU profiles are instead stored as JSON.
214 )"),
215  cl::value_desc("prefix"),
216  cl::cat(ClangTidyCategory));
217 
218 /// This option allows enabling the experimental alpha checkers from the static
219 /// analyzer. This option is set to false and not visible in help, because it is
220 /// highly not recommended for users.
221 static cl::opt<bool>
222  AllowEnablingAnalyzerAlphaCheckers("allow-enabling-analyzer-alpha-checkers",
223  cl::init(false), cl::Hidden,
224  cl::cat(ClangTidyCategory));
225 
226 static cl::opt<std::string> ExportFixes("export-fixes", cl::desc(R"(
227 YAML file to store suggested fixes in. The
228 stored fixes can be applied to the input source
229 code with clang-apply-replacements.
230 )"),
231  cl::value_desc("filename"),
232  cl::cat(ClangTidyCategory));
233 
234 static cl::opt<bool> Quiet("quiet", cl::desc(R"(
235 Run clang-tidy in quiet mode. This suppresses
236 printing statistics about ignored warnings and
237 warnings treated as errors if the respective
238 options are specified.
239 )"),
240  cl::init(false),
241  cl::cat(ClangTidyCategory));
242 
243 static cl::opt<std::string> VfsOverlay("vfsoverlay", cl::desc(R"(
244 Overlay the virtual filesystem described by file
245 over the real file system.
246 )"),
247  cl::value_desc("filename"),
248  cl::cat(ClangTidyCategory));
249 
250 static cl::opt<bool> UseColor("use-color", cl::desc(R"(
251 Use colors in diagnostics. If not set, colors
252 will be used if the terminal connected to
253 standard output supports colors.
254 This option overrides the 'UseColor' option in
255 .clang-tidy file, if any.
256 )"),
257  cl::init(false), cl::cat(ClangTidyCategory));
258 
259 static cl::opt<bool> VerifyConfig("verify-config", cl::desc(R"(
260 Check the config files to ensure each check and
261 option is recognized.
262 )"),
263  cl::init(false), cl::cat(ClangTidyCategory));
264 
265 namespace clang {
266 namespace tidy {
267 
268 static void printStats(const ClangTidyStats &Stats) {
269  if (Stats.errorsIgnored()) {
270  llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
271  StringRef Separator = "";
272  if (Stats.ErrorsIgnoredNonUserCode) {
273  llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
274  Separator = ", ";
275  }
276  if (Stats.ErrorsIgnoredLineFilter) {
277  llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
278  << " due to line filter";
279  Separator = ", ";
280  }
281  if (Stats.ErrorsIgnoredNOLINT) {
282  llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
283  Separator = ", ";
284  }
285  if (Stats.ErrorsIgnoredCheckFilter)
286  llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
287  << " with check filters";
288  llvm::errs() << ").\n";
289  if (Stats.ErrorsIgnoredNonUserCode)
290  llvm::errs() << "Use -header-filter=.* to display errors from all "
291  "non-system headers. Use -system-headers to display "
292  "errors from system headers as well.\n";
293  }
294 }
295 
296 static std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider(
297  llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) {
298  ClangTidyGlobalOptions GlobalOptions;
299  if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
300  llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
301  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
302  return nullptr;
303  }
304 
305  ClangTidyOptions DefaultOptions;
306  DefaultOptions.Checks = DefaultChecks;
307  DefaultOptions.WarningsAsErrors = "";
308  DefaultOptions.HeaderFilterRegex = HeaderFilter;
309  DefaultOptions.SystemHeaders = SystemHeaders;
310  DefaultOptions.FormatStyle = FormatStyle;
311  DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
312  // USERNAME is used on Windows.
313  if (!DefaultOptions.User)
314  DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");
315 
316  ClangTidyOptions OverrideOptions;
317  if (Checks.getNumOccurrences() > 0)
318  OverrideOptions.Checks = Checks;
319  if (WarningsAsErrors.getNumOccurrences() > 0)
320  OverrideOptions.WarningsAsErrors = WarningsAsErrors;
321  if (HeaderFilter.getNumOccurrences() > 0)
322  OverrideOptions.HeaderFilterRegex = HeaderFilter;
323  if (SystemHeaders.getNumOccurrences() > 0)
324  OverrideOptions.SystemHeaders = SystemHeaders;
325  if (FormatStyle.getNumOccurrences() > 0)
326  OverrideOptions.FormatStyle = FormatStyle;
327  if (UseColor.getNumOccurrences() > 0)
328  OverrideOptions.UseColor = UseColor;
329 
330  auto LoadConfig =
331  [&](StringRef Configuration,
332  StringRef Source) -> std::unique_ptr<ClangTidyOptionsProvider> {
333  llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
334  parseConfiguration(MemoryBufferRef(Configuration, Source));
335  if (ParsedConfig)
336  return std::make_unique<ConfigOptionsProvider>(
337  std::move(GlobalOptions),
338  ClangTidyOptions::getDefaults().merge(DefaultOptions, 0),
339  std::move(*ParsedConfig), std::move(OverrideOptions), std::move(FS));
340  llvm::errs() << "Error: invalid configuration specified.\n"
341  << ParsedConfig.getError().message() << "\n";
342  return nullptr;
343  };
344 
345  if (ConfigFile.getNumOccurrences() > 0) {
346  if (Config.getNumOccurrences() > 0) {
347  llvm::errs() << "Error: --config-file and --config are "
348  "mutually exclusive. Specify only one.\n";
349  return nullptr;
350  }
351 
352  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
353  llvm::MemoryBuffer::getFile(ConfigFile);
354  if (std::error_code EC = Text.getError()) {
355  llvm::errs() << "Error: can't read config-file '" << ConfigFile
356  << "': " << EC.message() << "\n";
357  return nullptr;
358  }
359 
360  return LoadConfig((*Text)->getBuffer(), ConfigFile);
361  }
362 
363  if (Config.getNumOccurrences() > 0)
364  return LoadConfig(Config, "<command-line-config>");
365 
366  return std::make_unique<FileOptionsProvider>(
367  std::move(GlobalOptions), std::move(DefaultOptions),
368  std::move(OverrideOptions), std::move(FS));
369 }
370 
371 llvm::IntrusiveRefCntPtr<vfs::FileSystem>
372 getVfsFromFile(const std::string &OverlayFile,
373  llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
374  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
375  BaseFS->getBufferForFile(OverlayFile);
376  if (!Buffer) {
377  llvm::errs() << "Can't load virtual filesystem overlay file '"
378  << OverlayFile << "': " << Buffer.getError().message()
379  << ".\n";
380  return nullptr;
381  }
382 
383  IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getVFSFromYAML(
384  std::move(Buffer.get()), /*DiagHandler*/ nullptr, OverlayFile);
385  if (!FS) {
386  llvm::errs() << "Error: invalid virtual filesystem overlay file '"
387  << OverlayFile << "'.\n";
388  return nullptr;
389  }
390  return FS;
391 }
392 
393 static StringRef closest(StringRef Value, const StringSet<> &Allowed) {
394  unsigned MaxEdit = 5U;
395  StringRef Closest;
396  for (auto Item : Allowed.keys()) {
397  unsigned Cur = Value.edit_distance_insensitive(Item, true, MaxEdit);
398  if (Cur < MaxEdit) {
399  Closest = Item;
400  MaxEdit = Cur;
401  }
402  }
403  return Closest;
404 }
405 
406 static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n";
407 
408 static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob,
409  StringRef Source) {
410  llvm::StringRef Cur, Rest;
411  bool AnyInvalid = false;
412  for (std::tie(Cur, Rest) = CheckGlob.split(',');
413  !(Cur.empty() && Rest.empty()); std::tie(Cur, Rest) = Rest.split(',')) {
414  Cur = Cur.trim();
415  if (Cur.empty())
416  continue;
417  Cur.consume_front("-");
418  if (Cur.startswith("clang-diagnostic"))
419  continue;
420  if (Cur.contains('*')) {
421  SmallString<128> RegexText("^");
422  StringRef MetaChars("()^$|*+?.[]\\{}");
423  for (char C : Cur) {
424  if (C == '*')
425  RegexText.push_back('.');
426  else if (MetaChars.contains(C))
427  RegexText.push_back('\\');
428  RegexText.push_back(C);
429  }
430  RegexText.push_back('$');
431  llvm::Regex Glob(RegexText);
432  std::string Error;
433  if (!Glob.isValid(Error)) {
434  AnyInvalid = true;
435  llvm::WithColor::error(llvm::errs(), Source)
436  << "building check glob '" << Cur << "' " << Error << "'\n";
437  continue;
438  }
439  if (llvm::none_of(AllChecks.keys(),
440  [&Glob](StringRef S) { return Glob.match(S); })) {
441  AnyInvalid = true;
442  llvm::WithColor::warning(llvm::errs(), Source)
443  << "check glob '" << Cur << "' doesn't match any known check"
445  }
446  } else {
447  if (AllChecks.contains(Cur))
448  continue;
449  AnyInvalid = true;
450  llvm::raw_ostream &Output = llvm::WithColor::warning(llvm::errs(), Source)
451  << "unknown check '" << Cur << '\'';
452  llvm::StringRef Closest = closest(Cur, AllChecks);
453  if (!Closest.empty())
454  Output << "; did you mean '" << Closest << '\'';
456  }
457  }
458  return AnyInvalid;
459 }
460 
461 int clangTidyMain(int argc, const char **argv) {
462  llvm::InitLLVM X(argc, argv);
463 
464  // Enable help for -load option, if plugins are enabled.
465  if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load"))
466  LoadOpt->addCategory(ClangTidyCategory);
467 
468  llvm::Expected<CommonOptionsParser> OptionsParser =
469  CommonOptionsParser::create(argc, argv, ClangTidyCategory,
470  cl::ZeroOrMore);
471  if (!OptionsParser) {
472  llvm::WithColor::error() << llvm::toString(OptionsParser.takeError());
473  return 1;
474  }
475 
476  llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS(
477  new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
478 
479  if (!VfsOverlay.empty()) {
480  IntrusiveRefCntPtr<vfs::FileSystem> VfsFromFile =
481  getVfsFromFile(VfsOverlay, BaseFS);
482  if (!VfsFromFile)
483  return 1;
484  BaseFS->pushOverlay(std::move(VfsFromFile));
485  }
486 
487  auto OwningOptionsProvider = createOptionsProvider(BaseFS);
488  auto *OptionsProvider = OwningOptionsProvider.get();
489  if (!OptionsProvider)
490  return 1;
491 
492  auto MakeAbsolute = [](const std::string &Input) -> SmallString<256> {
493  if (Input.empty())
494  return {};
495  SmallString<256> AbsolutePath(Input);
496  if (std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath)) {
497  llvm::errs() << "Can't make absolute path from " << Input << ": "
498  << EC.message() << "\n";
499  }
500  return AbsolutePath;
501  };
502 
503  SmallString<256> ProfilePrefix = MakeAbsolute(StoreCheckProfile);
504 
505  StringRef FileName("dummy");
506  auto PathList = OptionsParser->getSourcePathList();
507  if (!PathList.empty()) {
508  FileName = PathList.front();
509  }
510 
511  SmallString<256> FilePath = MakeAbsolute(std::string(FileName));
512 
513  ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath);
514  std::vector<std::string> EnabledChecks =
516 
517  if (ExplainConfig) {
518  // FIXME: Show other ClangTidyOptions' fields, like ExtraArg.
519  std::vector<clang::tidy::ClangTidyOptionsProvider::OptionsSource>
520  RawOptions = OptionsProvider->getRawOptions(FilePath);
521  for (const std::string &Check : EnabledChecks) {
522  for (const auto &[Opts, Source] : llvm::reverse(RawOptions)) {
523  if (Opts.Checks && GlobList(*Opts.Checks).contains(Check)) {
524  llvm::outs() << "'" << Check << "' is enabled in the " << Source
525  << ".\n";
526  break;
527  }
528  }
529  }
530  return 0;
531  }
532 
533  if (ListChecks) {
534  if (EnabledChecks.empty()) {
535  llvm::errs() << "No checks enabled.\n";
536  return 1;
537  }
538  llvm::outs() << "Enabled checks:";
539  for (const auto &CheckName : EnabledChecks)
540  llvm::outs() << "\n " << CheckName;
541  llvm::outs() << "\n\n";
542  return 0;
543  }
544 
545  if (DumpConfig) {
546  EffectiveOptions.CheckOptions =
548  llvm::outs() << configurationAsText(ClangTidyOptions::getDefaults().merge(
549  EffectiveOptions, 0))
550  << "\n";
551  return 0;
552  }
553 
554  if (VerifyConfig) {
555  std::vector<ClangTidyOptionsProvider::OptionsSource> RawOptions =
556  OptionsProvider->getRawOptions(FileName);
557  NamesAndOptions Valid =
559  bool AnyInvalid = false;
560  for (const auto &[Opts, Source] : RawOptions) {
561  if (Opts.Checks)
562  AnyInvalid |= verifyChecks(Valid.Names, *Opts.Checks, Source);
563 
564  for (auto Key : Opts.CheckOptions.keys()) {
565  if (Valid.Options.contains(Key))
566  continue;
567  AnyInvalid = true;
568  auto &Output = llvm::WithColor::warning(llvm::errs(), Source)
569  << "unknown check option '" << Key << '\'';
570  llvm::StringRef Closest = closest(Key, Valid.Options);
571  if (!Closest.empty())
572  Output << "; did you mean '" << Closest << '\'';
574  }
575  }
576  if (AnyInvalid)
577  return 1;
578  llvm::outs() << "No config errors detected.\n";
579  return 0;
580  }
581 
582  if (EnabledChecks.empty()) {
583  llvm::errs() << "Error: no checks enabled.\n";
584  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
585  return 1;
586  }
587 
588  if (PathList.empty()) {
589  llvm::errs() << "Error: no input files specified.\n";
590  llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
591  return 1;
592  }
593 
594  llvm::InitializeAllTargetInfos();
595  llvm::InitializeAllTargetMCs();
596  llvm::InitializeAllAsmParsers();
597 
598  ClangTidyContext Context(std::move(OwningOptionsProvider),
600  std::vector<ClangTidyError> Errors =
601  runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS,
602  FixNotes, EnableCheckProfile, ProfilePrefix);
603  bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) {
604  return E.DiagLevel == ClangTidyError::Error;
605  });
606 
607  // --fix-errors and --fix-notes imply --fix.
608  FixBehaviour Behaviour = FixNotes ? FB_FixNotes
609  : (Fix || FixErrors) ? FB_Fix
610  : FB_NoFix;
611 
612  const bool DisableFixes = FoundErrors && !FixErrors;
613 
614  unsigned WErrorCount = 0;
615 
616  handleErrors(Errors, Context, DisableFixes ? FB_NoFix : Behaviour,
617  WErrorCount, BaseFS);
618 
619  if (!ExportFixes.empty() && !Errors.empty()) {
620  std::error_code EC;
621  llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::OF_None);
622  if (EC) {
623  llvm::errs() << "Error opening output file: " << EC.message() << '\n';
624  return 1;
625  }
626  exportReplacements(FilePath.str(), Errors, OS);
627  }
628 
629  if (!Quiet) {
630  printStats(Context.getStats());
631  if (DisableFixes && Behaviour != FB_NoFix)
632  llvm::errs()
633  << "Found compiler errors, but -fix-errors was not specified.\n"
634  "Fixes have NOT been applied.\n\n";
635  }
636 
637  if (WErrorCount) {
638  if (!Quiet) {
639  StringRef Plural = WErrorCount == 1 ? "" : "s";
640  llvm::errs() << WErrorCount << " warning" << Plural << " treated as error"
641  << Plural << "\n";
642  }
643  return 1;
644  }
645 
646  if (FoundErrors) {
647  // TODO: Figure out when zero exit code should be used with -fix-errors:
648  // a. when a fix has been applied for an error
649  // b. when a fix has been applied for all errors
650  // c. some other condition.
651  // For now always returning zero when -fix-errors is used.
652  if (FixErrors)
653  return 0;
654  if (!Quiet)
655  llvm::errs() << "Found compiler error(s).\n";
656  return 1;
657  }
658 
659  return 0;
660 }
661 
662 } // namespace tidy
663 } // namespace clang
clang::tidy::FB_Fix
@ FB_Fix
Only apply fixes added to warnings.
Definition: ClangTidy.h:99
clang::tidy::parseConfiguration
llvm::ErrorOr< ClangTidyOptions > parseConfiguration(llvm::MemoryBufferRef Config)
Parses configuration from JSON and returns ClangTidyOptions or an error.
Definition: ClangTidyOptions.cpp:418
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:31
clang::tidy::getAllChecksAndOptions
NamesAndOptions getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers)
Definition: ClangTidy.cpp:627
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
StoreCheckProfile
static cl::opt< std::string > StoreCheckProfile("store-check-profile", cl::desc(R"( By default reports are printed in tabulated format to stderr. When this option is passed, these per-TU profiles are instead stored as JSON. )"), cl::value_desc("prefix"), cl::cat(ClangTidyCategory))
Checks
static cl::opt< std::string > Checks("checks", cl::desc(R"( Comma-separated list of globs with optional '-' prefix. Globs are processed in order of appearance in the list. Globs without '-' prefix add checks with matching names to the set, globs with the '-' prefix remove checks with matching names from the set of enabled checks. This option's value is appended to the value of the 'Checks' option in .clang-tidy file, if any. )"), cl::init(""), cl::cat(ClangTidyCategory))
FormatStyle
static cl::opt< std::string > FormatStyle("format-style", cl::desc(R"( Style for formatting code around applied fixes: - 'none' (default) turns off formatting - 'file' (literally 'file', not a placeholder) uses .clang-format file in the closest parent directory - '{ <json> }' specifies options inline, e.g. -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' - 'llvm', 'google', 'webkit', 'mozilla' See clang-format documentation for the up-to-date information about formatting styles and options. This option overrides the 'FormatStyle` option in .clang-tidy file, if any. )"), cl::init("none"), cl::cat(ClangTidyCategory))
clang::tidy::parseLineFilter
std::error_code parseLineFilter(StringRef LineFilter, clang::tidy::ClangTidyGlobalOptions &Options)
Parses -line-filter option and stores it to the Options.
Definition: ClangTidyOptions.cpp:410
clang::tidy::ClangTidyStats
Contains displayed and ignored diagnostic counters for a ClangTidy run.
Definition: ClangTidyDiagnosticConsumer.h:45
SystemHeaders
static cl::opt< bool > SystemHeaders("system-headers", cl::desc("Display the errors from system headers."), cl::init(false), cl::cat(ClangTidyCategory))
clang::clangd::detail::error
llvm::Error error(std::error_code, std::string &&)
Definition: Logger.cpp:80
VerifyConfig
static cl::opt< bool > VerifyConfig("verify-config", cl::desc(R"( Check the config files to ensure each check and option is recognized. )"), cl::init(false), cl::cat(ClangTidyCategory))
Text
std::string Text
Definition: HTMLGenerator.cpp:81
ClangTidyCategory
static cl::OptionCategory ClangTidyCategory("clang-tidy options")
clang::tidy::getCheckOptions
ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options, bool AllowEnablingAnalyzerAlphaCheckers)
Returns the effective check-specific options.
Definition: ClangTidy.cpp:496
clang::tidy::VerifyConfigWarningEnd
static constexpr StringLiteral VerifyConfigWarningEnd
Definition: ClangTidyMain.cpp:266
clang::tidy::handleErrors
void handleErrors(llvm::ArrayRef< ClangTidyError > Errors, ClangTidyContext &Context, FixBehaviour Fix, unsigned &WarningsAsErrorsCount, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS)
Displays the found Errors to the users.
Definition: ClangTidy.cpp:585
ConfigFile
static cl::opt< std::string > ConfigFile("config-file", cl::desc(R"( Specify the path of .clang-tidy or custom config file: e.g. --config-file=/some/path/myTidyConfigFile This option internally works exactly the same way as --config option after reading specified config file. Use either --config-file or --config, not both. )"), cl::init(""), cl::cat(ClangTidyCategory))
clang::tidy::clangTidyMain
int clangTidyMain(int argc, const char **argv)
Definition: ClangTidyMain.cpp:321
ListChecks
static cl::opt< bool > ListChecks("list-checks", cl::desc(R"( List all enabled checks and exit. Use with -checks=* to list all available checks. )"), cl::init(false), cl::cat(ClangTidyCategory))
Fix
static cl::opt< bool > Fix("fix", cl::desc(R"( Apply suggested fixes. Without -fix-errors clang-tidy will bail out if any compilation errors were found. )"), cl::init(false), cl::cat(ClangTidyCategory))
run-clang-tidy.make_absolute
def make_absolute(f, directory)
Definition: run-clang-tidy.py:86
UseColor
static cl::opt< bool > UseColor("use-color", cl::desc(R"( Use colors in diagnostics. If not set, colors will be used if the terminal connected to standard output supports colors. This option overrides the 'UseColor' option in .clang-tidy file, if any. )"), cl::init(false), cl::cat(ClangTidyCategory))
clang::tidy::FixBehaviour
FixBehaviour
Controls what kind of fixes clang-tidy is allowed to apply.
Definition: ClangTidy.h:95
Error
constexpr static llvm::SourceMgr::DiagKind Error
Definition: ConfigCompile.cpp:591
clang::tidy::runClangTidy
std::vector< ClangTidyError > runClangTidy(clang::tidy::ClangTidyContext &Context, const CompilationDatabase &Compilations, ArrayRef< std::string > InputFiles, llvm::IntrusiveRefCntPtr< llvm::vfs::OverlayFileSystem > BaseFS, bool ApplyAnyFix, bool EnableCheckProfile, llvm::StringRef StoreCheckProfile)
Definition: ClangTidy.cpp:507
X
int X
Definition: LSPBinderTests.cpp:25
AllowEnablingAnalyzerAlphaCheckers
static cl::opt< bool > AllowEnablingAnalyzerAlphaCheckers("allow-enabling-analyzer-alpha-checkers", cl::init(false), cl::Hidden, cl::cat(ClangTidyCategory))
This option allows enabling the experimental alpha checkers from the static analyzer.
Config
static cl::opt< std::string > Config("config", cl::desc(R"( Specifies a configuration in YAML/JSON format: -config="{Checks:' *', CheckOptions:{x:y}}" When the value is empty, clang-tidy will attempt to find a file named .clang-tidy for each source file in its parent directories. )"), cl::init(""), cl::cat(ClangTidyCategory))
clang::tooling
Definition: ClangTidy.h:26
clang::clangd::SymbolKind::Key
@ Key
clang::tidy::getVfsFromFile
llvm::IntrusiveRefCntPtr< vfs::FileSystem > getVfsFromFile(const std::string &OverlayFile, llvm::IntrusiveRefCntPtr< vfs::FileSystem > BaseFS)
Definition: ClangTidyMain.cpp:232
ClangTidyMain.h
clang::clangd::Separator
@ Separator
Definition: FuzzyMatch.h:59
clang::tidy::configurationAsText
std::string configurationAsText(const ClangTidyOptions &Options)
Serializes configuration to a YAML-encoded string.
Definition: ClangTidyOptions.cpp:443
Quiet
static cl::opt< bool > Quiet("quiet", cl::desc(R"( Run clang-tidy in quiet mode. This suppresses printing statistics about ignored warnings and warnings treated as errors if the respective options are specified. )"), cl::init(false), cl::cat(ClangTidyCategory))
FileName
StringRef FileName
Definition: KernelNameRestrictionCheck.cpp:46
clang::tidy::verifyChecks
static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob, StringRef Source)
Definition: ClangTidyMain.cpp:268
Output
std::string Output
Definition: TraceTests.cpp:159
clang::clangd::lookup
std::vector< std::string > lookup(const SymbolIndex &I, llvm::ArrayRef< SymbolID > IDs)
Definition: TestIndex.cpp:145
HeaderFilter
static cl::opt< std::string > HeaderFilter("header-filter", cl::desc(R"( Regular expression matching the names of the headers to output diagnostics from. Diagnostics from the main file of each translation unit are always displayed. Can be used together with -line-filter. This option overrides the 'HeaderFilterRegex' option in .clang-tidy file, if any. )"), cl::init(""), cl::cat(ClangTidyCategory))
DefaultChecks
const char DefaultChecks[]
Definition: ClangTidyMain.cpp:38
clang::tidy::closest
static StringRef closest(StringRef Value, const StringSet<> &Allowed)
Definition: ClangTidyMain.cpp:253
WarningsAsErrors
static cl::opt< std::string > WarningsAsErrors("warnings-as-errors", cl::desc(R"( Upgrades warnings to errors. Same format as '-checks'. This option's value is appended to the value of the 'WarningsAsErrors' option in .clang-tidy file, if any. )"), cl::init(""), cl::cat(ClangTidyCategory))
FixErrors
static cl::opt< bool > FixErrors("fix-errors", cl::desc(R"( Apply suggested fixes even if compilation errors were found. If compiler errors have attached fix-its, clang-tidy will apply them as well. )"), cl::init(false), cl::cat(ClangTidyCategory))
EnableCheckProfile
static cl::opt< bool > EnableCheckProfile("enable-check-profile", cl::desc(R"( Enable per-check timing profiles, and print a report to stderr. )"), cl::init(false), cl::cat(ClangTidyCategory))
ExportFixes
static cl::opt< std::string > ExportFixes("export-fixes", cl::desc(R"( YAML file to store suggested fixes in. The stored fixes can be applied to the input source code with clang-apply-replacements. )"), cl::value_desc("filename"), cl::cat(ClangTidyCategory))
FixNotes
static cl::opt< bool > FixNotes("fix-notes", cl::desc(R"( If a warning has no fix, but a single fix can be found through an associated diagnostic note, apply the fix. Specifying this flag will implicitly enable the '--fix' flag. )"), cl::init(false), cl::cat(ClangTidyCategory))
LineFilter
static cl::opt< std::string > LineFilter("line-filter", cl::desc(R"( List of files with line ranges to filter the warnings. Can be used together with -header-filter. The format of the list is a JSON array of objects: [ {"name":"file1.cpp","lines":[[1,3],[5,7]]}, {"name":"file2.h"} ] )"), cl::init(""), cl::cat(ClangTidyCategory))
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::tidy::createOptionsProvider
static std::unique_ptr< ClangTidyOptionsProvider > createOptionsProvider(llvm::IntrusiveRefCntPtr< vfs::FileSystem > FS)
Definition: ClangTidyMain.cpp:156
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
clang::tidy::cppcoreguidelines::toString
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Definition: SpecialMemberFunctionsCheck.cpp:55
ClangTidyHelp
static cl::extrahelp ClangTidyHelp(R"( Configuration files: clang-tidy attempts to read configuration for each source file from a .clang-tidy file located in the closest parent directory of the source file. If InheritParentConfig is true in a config file, the configuration file in the parent directory (if any exists) will be taken and current config file will be applied on top of the parent one. If any configuration options have a corresponding command-line option, command-line option takes precedence. The effective configuration can be inspected using -dump-config: $ clang-tidy -dump-config --- Checks: '-*,some-check' WarningsAsErrors: '' HeaderFilterRegex: '' FormatStyle: none InheritParentConfig: true User: user CheckOptions: some-check.SomeOption: 'some value' ... )")
clang::tidy::getCheckNames
std::vector< std::string > getCheckNames(const ClangTidyOptions &Options, bool AllowEnablingAnalyzerAlphaCheckers)
Fills the list of check names that are enabled when the provided filters are applied.
Definition: ClangTidy.cpp:485
VfsOverlay
static cl::opt< std::string > VfsOverlay("vfsoverlay", cl::desc(R"( Overlay the virtual filesystem described by file over the real file system. )"), cl::value_desc("filename"), cl::cat(ClangTidyCategory))
clang::tidy::FB_FixNotes
@ FB_FixNotes
Apply fixes found in notes.
Definition: ClangTidy.h:101
clang::tidy::printStats
static void printStats(const ClangTidyStats &Stats)
Definition: ClangTidyMain.cpp:128
clang::tidy::exportReplacements
void exportReplacements(const llvm::StringRef MainFilePath, const std::vector< ClangTidyError > &Errors, raw_ostream &OS)
Definition: ClangTidy.cpp:612
DumpConfig
static cl::opt< bool > DumpConfig("dump-config", cl::desc(R"( Dumps configuration in the YAML format to stdout. This option can be used along with a file name (and '--' if the file is outside of a project with configured compilation database). The configuration used for this file will be printed. Use along with -checks=* to include configuration of all checks. )"), cl::init(false), cl::cat(ClangTidyCategory))
ExplainConfig
static cl::opt< bool > ExplainConfig("explain-config", cl::desc(R"( For each enabled check explains, where it is enabled, i.e. in clang-tidy binary, command line or a specific configuration file. )"), cl::init(false), cl::cat(ClangTidyCategory))
CommonHelp
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage)
clang::tidy::FB_NoFix
@ FB_NoFix
Don't try to apply any fix.
Definition: ClangTidy.h:97
clang::clangd::MessageType::Error
@ Error
An error message.