blob: 8bcff121087f2975d4e5c56f936a1575b97c01ad [file] [log] [blame]
Daniel Jasperd07c8402013-07-29 08:19:24 +00001//===--- 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"
Manuel Klimek814f9bd2013-11-14 15:49:44 +000019#include "clang/Tooling/CommonOptionsParser.h"
Alexander Kornienkoe9951542014-09-24 18:36:03 +000020#include "llvm/Support/Process.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000021
22using namespace clang::ast_matchers;
23using namespace clang::driver;
24using namespace clang::tooling;
25using namespace llvm;
26
Alexander Kornienko99c9d6a2014-02-05 13:43:27 +000027static cl::OptionCategory ClangTidyCategory("clang-tidy options");
Daniel Jasperd07c8402013-07-29 08:19:24 +000028
Manuel Klimek814f9bd2013-11-14 15:49:44 +000029static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
Alexander Kornienkod53d2682014-09-04 14:23:36 +000030static 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"
Alexander Kornienko5c423312014-12-03 14:03:03 +000036 " 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");
Daniel Jasperd07c8402013-07-29 08:19:24 +000049
Alexander Kornienko50ab1562014-10-29 18:25:09 +000050const 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
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000054
Alexander Kornienko23fe9592014-05-15 14:27:36 +000055static cl::opt<std::string>
Alexander Kornienko3ab34672014-05-16 13:07:18 +000056Checks("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"
Alexander Kornienkod53d2682014-09-04 14:23:36 +000061 "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."),
Alexander Kornienko23fe9592014-05-15 14:27:36 +000064 cl::init(""), cl::cat(ClangTidyCategory));
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000065
Alexander Kornienko3ab34672014-05-16 13:07:18 +000066static cl::opt<std::string>
Jonathan Roelofsd60388a2016-01-13 17:36:41 +000067 WarningsAsErrors("warnings-as-errors",
68 cl::desc("Upgrades warnings to errors. "
69 "Same format as '-checks'."),
70 cl::init(""), cl::cat(ClangTidyCategory));
71
72static cl::opt<std::string>
73 HeaderFilter("header-filter",
74 cl::desc("Regular expression matching the names of the\n"
75 "headers to output diagnostics from. Diagnostics\n"
76 "from the main file of each translation unit are\n"
77 "always displayed.\n"
78 "Can be used together with -line-filter.\n"
79 "This option overrides the value read from a\n"
80 ".clang-tidy file."),
81 cl::init(""), cl::cat(ClangTidyCategory));
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000082
Alexander Kornienko37f7abe2014-10-28 22:16:13 +000083static cl::opt<bool>
84 SystemHeaders("system-headers",
Alexander Kornienko5eac3c62014-11-03 14:06:31 +000085 cl::desc("Display the errors from system headers."),
Alexander Kornienko37f7abe2014-10-28 22:16:13 +000086 cl::init(false), cl::cat(ClangTidyCategory));
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000087static cl::opt<std::string>
88LineFilter("line-filter",
89 cl::desc("List of files with line ranges to filter the\n"
90 "warnings. Can be used together with\n"
91 "-header-filter. The format of the list is a JSON\n"
92 "array of objects:\n"
93 " [\n"
94 " {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"
95 " {\"name\":\"file2.h\"}\n"
96 " ]"),
97 cl::init(""), cl::cat(ClangTidyCategory));
98
Alexander Kornienko5eac3c62014-11-03 14:06:31 +000099static cl::opt<bool>
100 Fix("fix", cl::desc("Apply suggested fixes. Without -fix-errors\n"
101 "clang-tidy will bail out if any compilation\n"
102 "errors were found."),
103 cl::init(false), cl::cat(ClangTidyCategory));
104
105static cl::opt<bool>
106 FixErrors("fix-errors",
107 cl::desc("Apply suggested fixes even if compilation errors\n"
108 "were found. If compiler errors have attached\n"
109 "fix-its, clang-tidy will apply them as well."),
110 cl::init(false), cl::cat(ClangTidyCategory));
Daniel Jasperd07c8402013-07-29 08:19:24 +0000111
Alexander Kornienko3ab34672014-05-16 13:07:18 +0000112static cl::opt<bool>
113ListChecks("list-checks",
114 cl::desc("List all enabled checks and exit. Use with\n"
Aaron Ballman5a4892b2015-07-27 13:41:30 +0000115 "-checks=* to list all available checks."),
Alexander Kornienko3ab34672014-05-16 13:07:18 +0000116 cl::init(false), cl::cat(ClangTidyCategory));
Daniel Jasperd07c8402013-07-29 08:19:24 +0000117
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000118static cl::opt<std::string> Config(
119 "config",
120 cl::desc("Specifies a configuration in YAML/JSON format:\n"
Alexander Kornienko5c423312014-12-03 14:03:03 +0000121 " -config=\"{Checks: '*', CheckOptions: [{key: x, value: y}]}\"\n"
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000122 "When the value is empty, clang-tidy will attempt to find\n"
Alexander Kornienko7165e892014-09-26 11:48:53 +0000123 "a file named .clang-tidy for each source file in its parent\n"
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000124 "directories."),
125 cl::init(""), cl::cat(ClangTidyCategory));
126
Alexander Kornienko5c423312014-12-03 14:03:03 +0000127static cl::opt<bool> DumpConfig(
128 "dump-config",
129 cl::desc("Dumps configuration in the YAML format to stdout. This option\n"
Alexander Kornienkobe506982015-09-16 13:21:57 +0000130 "can be used along with a file name (and '--' if the file is\n"
Alexander Kornienko5c423312014-12-03 14:03:03 +0000131 "outside of a project with configured compilation database). The\n"
Alexander Kornienkobe506982015-09-16 13:21:57 +0000132 "configuration used for this file will be printed.\n"
133 "Use along with -checks=* to include configuration of all\n"
134 "checks.\n"),
Alexander Kornienko5c423312014-12-03 14:03:03 +0000135 cl::init(false), cl::cat(ClangTidyCategory));
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000136
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000137static cl::opt<bool> EnableCheckProfile(
138 "enable-check-profile",
139 cl::desc("Enable per-check timing profiles, and print a report to stderr."),
140 cl::init(false), cl::cat(ClangTidyCategory));
141
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000142static cl::opt<bool> AnalyzeTemporaryDtors(
143 "analyze-temporary-dtors",
144 cl::desc("Enable temporary destructor-aware analysis in\n"
145 "clang-analyzer- checks.\n"
146 "This option overrides the value read from a\n"
147 ".clang-tidy file."),
148 cl::init(false), cl::cat(ClangTidyCategory));
Alex McCarthyfec08c72014-04-30 14:09:24 +0000149
Benjamin Kramerfb98b742014-09-04 10:31:23 +0000150static cl::opt<std::string> ExportFixes(
151 "export-fixes",
152 cl::desc("YAML file to store suggested fixes in. The\n"
153 "stored fixes can be applied to the input source\n"
154 "code with clang-apply-replacements."),
155 cl::value_desc("filename"), cl::cat(ClangTidyCategory));
156
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000157namespace clang {
158namespace tidy {
159
160static void printStats(const ClangTidyStats &Stats) {
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000161 if (Stats.errorsIgnored()) {
162 llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
Alexander Kornienko5d174542014-05-07 09:06:53 +0000163 StringRef Separator = "";
164 if (Stats.ErrorsIgnoredNonUserCode) {
165 llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
166 Separator = ", ";
167 }
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000168 if (Stats.ErrorsIgnoredLineFilter) {
169 llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
170 << " due to line filter";
171 Separator = ", ";
172 }
Alexander Kornienko5d174542014-05-07 09:06:53 +0000173 if (Stats.ErrorsIgnoredNOLINT) {
174 llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
175 Separator = ", ";
176 }
177 if (Stats.ErrorsIgnoredCheckFilter)
178 llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
179 << " with check filters";
180 llvm::errs() << ").\n";
181 if (Stats.ErrorsIgnoredNonUserCode)
Aaron Ballman5a4892b2015-07-27 13:41:30 +0000182 llvm::errs() << "Use -header-filter=.* to display errors from all "
Alexander Kornienko5d174542014-05-07 09:06:53 +0000183 "non-system headers.\n";
184 }
185}
186
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000187static void printProfileData(const ProfileData &Profile,
188 llvm::raw_ostream &OS) {
189 // Time is first to allow for sorting by it.
190 std::vector<std::pair<llvm::TimeRecord, StringRef>> Timers;
191 TimeRecord Total;
192
193 for (const auto& P : Profile.Records) {
194 Timers.emplace_back(P.getValue(), P.getKey());
195 Total += P.getValue();
196 }
197
198 std::sort(Timers.begin(), Timers.end());
199
200 std::string Line = "===" + std::string(73, '-') + "===\n";
201 OS << Line;
202
203 if (Total.getUserTime())
204 OS << " ---User Time---";
205 if (Total.getSystemTime())
206 OS << " --System Time--";
207 if (Total.getProcessTime())
208 OS << " --User+System--";
209 OS << " ---Wall Time---";
210 if (Total.getMemUsed())
211 OS << " ---Mem---";
212 OS << " --- Name ---\n";
213
214 // Loop through all of the timing data, printing it out.
215 for (auto I = Timers.rbegin(), E = Timers.rend(); I != E; ++I) {
216 I->first.print(Total, OS);
217 OS << I->second << '\n';
218 }
219
220 Total.print(Total, OS);
221 OS << "Total\n";
222 OS << Line << "\n";
223 OS.flush();
224}
225
Benjamin Kramere7103712015-03-23 12:49:15 +0000226static std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider() {
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000227 ClangTidyGlobalOptions GlobalOptions;
228 if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000229 llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
230 llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000231 return nullptr;
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000232 }
Alexander Kornienko33a9bcc2014-04-29 15:20:10 +0000233
Alexander Kornienkoe9951542014-09-24 18:36:03 +0000234 ClangTidyOptions DefaultOptions;
235 DefaultOptions.Checks = DefaultChecks;
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000236 DefaultOptions.WarningsAsErrors = "";
Alexander Kornienkoe9951542014-09-24 18:36:03 +0000237 DefaultOptions.HeaderFilterRegex = HeaderFilter;
Alexander Kornienko37f7abe2014-10-28 22:16:13 +0000238 DefaultOptions.SystemHeaders = SystemHeaders;
Alexander Kornienkoe9951542014-09-24 18:36:03 +0000239 DefaultOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
240 DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
241 // USERNAME is used on Windows.
242 if (!DefaultOptions.User)
243 DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000244
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000245 ClangTidyOptions OverrideOptions;
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000246 if (Checks.getNumOccurrences() > 0)
247 OverrideOptions.Checks = Checks;
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000248 if (WarningsAsErrors.getNumOccurrences() > 0)
249 OverrideOptions.WarningsAsErrors = WarningsAsErrors;
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000250 if (HeaderFilter.getNumOccurrences() > 0)
251 OverrideOptions.HeaderFilterRegex = HeaderFilter;
Alexander Kornienko37f7abe2014-10-28 22:16:13 +0000252 if (SystemHeaders.getNumOccurrences() > 0)
253 OverrideOptions.SystemHeaders = SystemHeaders;
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000254 if (AnalyzeTemporaryDtors.getNumOccurrences() > 0)
255 OverrideOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
256
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000257 if (!Config.empty()) {
258 if (llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
259 parseConfiguration(Config)) {
260 return llvm::make_unique<DefaultOptionsProvider>(
261 GlobalOptions, ClangTidyOptions::getDefaults()
262 .mergeWith(DefaultOptions)
263 .mergeWith(*ParsedConfig)
264 .mergeWith(OverrideOptions));
265 } else {
266 llvm::errs() << "Error: invalid configuration specified.\n"
267 << ParsedConfig.getError().message() << "\n";
268 return nullptr;
269 }
270 }
271 return llvm::make_unique<FileOptionsProvider>(GlobalOptions, DefaultOptions,
272 OverrideOptions);
273}
274
Benjamin Kramere7103712015-03-23 12:49:15 +0000275static int clangTidyMain(int argc, const char **argv) {
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000276 CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory,
277 cl::ZeroOrMore);
Alexander Kornienkoeff4e922014-09-26 11:42:29 +0000278
279 auto OptionsProvider = createOptionsProvider();
280 if (!OptionsProvider)
281 return 1;
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000282
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000283 StringRef FileName("dummy");
284 auto PathList = OptionsParser.getSourcePathList();
285 if (!PathList.empty()) {
Alexander Kornienkoe0c900e2015-08-17 11:27:11 +0000286 FileName = PathList.front();
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000287 }
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000288 ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FileName);
289 std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions);
Alexander Kornienkofbf92582014-06-02 20:32:06 +0000290
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000291 if (ListChecks) {
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000292 llvm::outs() << "Enabled checks:";
Alexander Kornienkofbf92582014-06-02 20:32:06 +0000293 for (auto CheckName : EnabledChecks)
Alexander Kornienko16ac6ce2014-03-05 13:14:32 +0000294 llvm::outs() << "\n " << CheckName;
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000295 llvm::outs() << "\n\n";
296 return 0;
297 }
298
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000299 if (DumpConfig) {
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000300 EffectiveOptions.CheckOptions = getCheckOptions(EffectiveOptions);
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000301 llvm::outs() << configurationAsText(
302 ClangTidyOptions::getDefaults().mergeWith(
303 EffectiveOptions))
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000304 << "\n";
305 return 0;
306 }
307
Alexander Kornienkofbf92582014-06-02 20:32:06 +0000308 if (EnabledChecks.empty()) {
309 llvm::errs() << "Error: no checks enabled.\n";
310 llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
311 return 1;
312 }
313
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000314 if (PathList.empty()) {
315 llvm::errs() << "Error: no input files specified.\n";
316 llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
317 return 1;
318 }
319
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000320 ProfileData Profile;
321
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000322 std::vector<ClangTidyError> Errors;
323 ClangTidyStats Stats =
324 runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
Alexander Kornienko65eccb42015-08-17 10:03:27 +0000325 PathList, &Errors,
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000326 EnableCheckProfile ? &Profile : nullptr);
Alexander Kornienko5eac3c62014-11-03 14:06:31 +0000327 bool FoundErrors =
328 std::find_if(Errors.begin(), Errors.end(), [](const ClangTidyError &E) {
329 return E.DiagLevel == ClangTidyError::Error;
330 }) != Errors.end();
331
332 const bool DisableFixes = Fix && FoundErrors && !FixErrors;
333
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000334 unsigned WErrorCount = 0;
335
Alexander Kornienko5eac3c62014-11-03 14:06:31 +0000336 // -fix-errors implies -fix.
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000337 handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, WErrorCount);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000338
Alexander Kornienko4153da22014-09-04 15:19:49 +0000339 if (!ExportFixes.empty() && !Errors.empty()) {
Benjamin Kramerfb98b742014-09-04 10:31:23 +0000340 std::error_code EC;
341 llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
342 if (EC) {
343 llvm::errs() << "Error opening output file: " << EC.message() << '\n';
344 return 1;
345 }
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000346 exportReplacements(Errors, OS);
Benjamin Kramerfb98b742014-09-04 10:31:23 +0000347 }
348
Alexander Kornienko5d174542014-05-07 09:06:53 +0000349 printStats(Stats);
Alexander Kornienko5eac3c62014-11-03 14:06:31 +0000350 if (DisableFixes)
Alexander Kornienkob0a9b702014-12-09 15:02:17 +0000351 llvm::errs()
352 << "Found compiler errors, but -fix-errors was not specified.\n"
353 "Fixes have NOT been applied.\n\n";
Alexander Kornienko5eac3c62014-11-03 14:06:31 +0000354
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000355 if (EnableCheckProfile)
356 printProfileData(Profile, llvm::errs());
357
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000358 if (WErrorCount) {
359 StringRef Plural = WErrorCount == 1 ? "" : "s";
360 llvm::errs() << WErrorCount << " warning" << Plural << " treated as error"
361 << Plural << "\n";
362 return WErrorCount;
363 }
364
Daniel Jasperd07c8402013-07-29 08:19:24 +0000365 return 0;
366}
Daniel Jasper89bbab02013-08-04 15:56:30 +0000367
Aaron Ballmanea2f90c2015-10-02 13:27:19 +0000368// This anchor is used to force the linker to link the CERTModule.
369extern volatile int CERTModuleAnchorSource;
370static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
371 CERTModuleAnchorSource;
372
Daniel Jasper89bbab02013-08-04 15:56:30 +0000373// This anchor is used to force the linker to link the LLVMModule.
374extern volatile int LLVMModuleAnchorSource;
Alexander Kornienkoe1292f82015-08-19 16:54:51 +0000375static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
376 LLVMModuleAnchorSource;
Daniel Jasper89bbab02013-08-04 15:56:30 +0000377
Aaron Ballmanaaa40802015-10-06 13:31:00 +0000378// This anchor is used to force the linker to link the CppCoreGuidelinesModule.
379extern volatile int CppCoreGuidelinesModuleAnchorSource;
380static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
381 CppCoreGuidelinesModuleAnchorSource;
382
Daniel Jasper89bbab02013-08-04 15:56:30 +0000383// This anchor is used to force the linker to link the GoogleModule.
384extern volatile int GoogleModuleAnchorSource;
Alexander Kornienkoe1292f82015-08-19 16:54:51 +0000385static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
386 GoogleModuleAnchorSource;
Daniel Jasper89bbab02013-08-04 15:56:30 +0000387
Alexander Kornienko16ac6ce2014-03-05 13:14:32 +0000388// This anchor is used to force the linker to link the MiscModule.
389extern volatile int MiscModuleAnchorSource;
Alexander Kornienkoe1292f82015-08-19 16:54:51 +0000390static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
391 MiscModuleAnchorSource;
Alexander Kornienko16ac6ce2014-03-05 13:14:32 +0000392
Alexander Kornienkofc650862015-08-14 13:17:11 +0000393// This anchor is used to force the linker to link the ModernizeModule.
394extern volatile int ModernizeModuleAnchorSource;
Alexander Kornienkoe1292f82015-08-19 16:54:51 +0000395static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
396 ModernizeModuleAnchorSource;
Alexander Kornienkofc650862015-08-14 13:17:11 +0000397
Alexander Kornienkob959f4c2015-12-30 10:24:40 +0000398// This anchor is used to force the linker to link the PerformanceModule.
399extern volatile int PerformanceModuleAnchorSource;
400static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
401 PerformanceModuleAnchorSource;
402
Alexander Kornienko2192a8e2014-10-26 01:41:14 +0000403// This anchor is used to force the linker to link the ReadabilityModule.
404extern volatile int ReadabilityModuleAnchorSource;
Alexander Kornienkoe1292f82015-08-19 16:54:51 +0000405static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
406 ReadabilityModuleAnchorSource;
Alexander Kornienko2192a8e2014-10-26 01:41:14 +0000407
Daniel Jasper89bbab02013-08-04 15:56:30 +0000408} // namespace tidy
409} // namespace clang
Alexander Kornienkoc28c32d2014-09-10 11:43:09 +0000410
411int main(int argc, const char **argv) {
412 return clang::tidy::clangTidyMain(argc, argv);
413}