File: | include/llvm/ADT/IntrusiveRefCntPtr.h |
Warning: | line 157, column 38 Potential leak of memory pointed to by field 'Obj' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- tools/extra/clang-tidy/ClangTidy.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 "ClangTidyDiagnosticConsumer.h" | |||
20 | #include "ClangTidyModuleRegistry.h" | |||
21 | #include "ClangTidyProfiling.h" | |||
22 | #include "clang/AST/ASTConsumer.h" | |||
23 | #include "clang/AST/ASTContext.h" | |||
24 | #include "clang/AST/Decl.h" | |||
25 | #include "clang/ASTMatchers/ASTMatchFinder.h" | |||
26 | #include "clang/Format/Format.h" | |||
27 | #include "clang/Frontend/ASTConsumers.h" | |||
28 | #include "clang/Frontend/CompilerInstance.h" | |||
29 | #include "clang/Frontend/FrontendActions.h" | |||
30 | #include "clang/Frontend/FrontendDiagnostic.h" | |||
31 | #include "clang/Frontend/MultiplexConsumer.h" | |||
32 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |||
33 | #include "clang/Lex/PPCallbacks.h" | |||
34 | #include "clang/Lex/Preprocessor.h" | |||
35 | #include "clang/Rewrite/Frontend/FixItRewriter.h" | |||
36 | #include "clang/Rewrite/Frontend/FrontendActions.h" | |||
37 | #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" | |||
38 | #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" | |||
39 | #include "clang/Tooling/DiagnosticsYaml.h" | |||
40 | #include "clang/Tooling/Refactoring.h" | |||
41 | #include "clang/Tooling/ReplacementsYaml.h" | |||
42 | #include "clang/Tooling/Tooling.h" | |||
43 | #include "llvm/Support/Process.h" | |||
44 | #include "llvm/Support/Signals.h" | |||
45 | #include <algorithm> | |||
46 | #include <utility> | |||
47 | ||||
48 | using namespace clang::ast_matchers; | |||
49 | using namespace clang::driver; | |||
50 | using namespace clang::tooling; | |||
51 | using namespace llvm; | |||
52 | ||||
53 | LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)namespace llvm { template<typename T> typename Registry <T>::node *Registry<T>::Head = nullptr; template< typename T> typename Registry<T>::node *Registry< T>::Tail = nullptr; template<typename T> void Registry <T>::add_node(typename Registry<T>::node *N) { if (Tail) Tail->Next = N; else Head = N; Tail = N; } template <typename T> typename Registry<T>::iterator Registry <T>::begin() { return iterator(Head); } template clang:: tidy::ClangTidyModuleRegistry::node *Registry<clang::tidy:: ClangTidyModuleRegistry::type>::Head; template clang::tidy ::ClangTidyModuleRegistry::node *Registry<clang::tidy::ClangTidyModuleRegistry ::type>::Tail; template void Registry<clang::tidy::ClangTidyModuleRegistry ::type>::add_node(clang::tidy::ClangTidyModuleRegistry::node *); template clang::tidy::ClangTidyModuleRegistry::iterator Registry <clang::tidy::ClangTidyModuleRegistry::type>::begin(); } | |||
54 | ||||
55 | namespace clang { | |||
56 | namespace tidy { | |||
57 | ||||
58 | namespace { | |||
59 | static const char *AnalyzerCheckNamePrefix = "clang-analyzer-"; | |||
60 | ||||
61 | class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer { | |||
62 | public: | |||
63 | AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {} | |||
64 | ||||
65 | void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags, | |||
66 | FilesMade *filesMade) override { | |||
67 | for (const ento::PathDiagnostic *PD : Diags) { | |||
68 | SmallString<64> CheckName(AnalyzerCheckNamePrefix); | |||
69 | CheckName += PD->getCheckName(); | |||
70 | Context.diag(CheckName, PD->getLocation().asLocation(), | |||
71 | PD->getShortDescription()) | |||
72 | << PD->path.back()->getRanges(); | |||
73 | ||||
74 | for (const auto &DiagPiece : | |||
75 | PD->path.flatten(/*ShouldFlattenMacros=*/true)) { | |||
76 | Context.diag(CheckName, DiagPiece->getLocation().asLocation(), | |||
77 | DiagPiece->getString(), DiagnosticIDs::Note) | |||
78 | << DiagPiece->getRanges(); | |||
79 | } | |||
80 | } | |||
81 | } | |||
82 | ||||
83 | StringRef getName() const override { return "ClangTidyDiags"; } | |||
84 | bool supportsLogicalOpControlFlow() const override { return true; } | |||
85 | bool supportsCrossFileDiagnostics() const override { return true; } | |||
86 | ||||
87 | private: | |||
88 | ClangTidyContext &Context; | |||
89 | }; | |||
90 | ||||
91 | class ErrorReporter { | |||
92 | public: | |||
93 | ErrorReporter(ClangTidyContext &Context, bool ApplyFixes, | |||
94 | llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) | |||
95 | : Files(FileSystemOptions(), BaseFS), DiagOpts(new DiagnosticOptions()), | |||
96 | DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), | |||
97 | Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, | |||
98 | DiagPrinter), | |||
99 | SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes), | |||
100 | TotalFixes(0), AppliedFixes(0), WarningsAsErrors(0) { | |||
101 | DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors(); | |||
102 | DiagPrinter->BeginSourceFile(LangOpts); | |||
103 | } | |||
104 | ||||
105 | SourceManager &getSourceManager() { return SourceMgr; } | |||
106 | ||||
107 | void reportDiagnostic(const ClangTidyError &Error) { | |||
108 | const tooling::DiagnosticMessage &Message = Error.Message; | |||
109 | SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); | |||
110 | // Contains a pair for each attempted fix: location and whether the fix was | |||
111 | // applied successfully. | |||
112 | SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations; | |||
113 | { | |||
114 | auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel); | |||
115 | std::string Name = Error.DiagnosticName; | |||
116 | if (Error.IsWarningAsError) { | |||
117 | Name += ",-warnings-as-errors"; | |||
118 | Level = DiagnosticsEngine::Error; | |||
119 | WarningsAsErrors++; | |||
120 | } | |||
121 | auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]")) | |||
122 | << Message.Message << Name; | |||
123 | for (const auto &FileAndReplacements : Error.Fix) { | |||
124 | for (const auto &Repl : FileAndReplacements.second) { | |||
125 | // Retrieve the source range for applicable fixes. Macro definitions | |||
126 | // on the command line have locations in a virtual buffer and don't | |||
127 | // have valid file paths and are therefore not applicable. | |||
128 | SourceRange Range; | |||
129 | SourceLocation FixLoc; | |||
130 | ++TotalFixes; | |||
131 | bool CanBeApplied = false; | |||
132 | if (Repl.isApplicable()) { | |||
133 | SmallString<128> FixAbsoluteFilePath = Repl.getFilePath(); | |||
134 | Files.makeAbsolutePath(FixAbsoluteFilePath); | |||
135 | if (ApplyFixes) { | |||
136 | tooling::Replacement R(FixAbsoluteFilePath, Repl.getOffset(), | |||
137 | Repl.getLength(), | |||
138 | Repl.getReplacementText()); | |||
139 | Replacements &Replacements = FileReplacements[R.getFilePath()]; | |||
140 | llvm::Error Err = Replacements.add(R); | |||
141 | if (Err) { | |||
142 | // FIXME: Implement better conflict handling. | |||
143 | llvm::errs() << "Trying to resolve conflict: " | |||
144 | << llvm::toString(std::move(Err)) << "\n"; | |||
145 | unsigned NewOffset = | |||
146 | Replacements.getShiftedCodePosition(R.getOffset()); | |||
147 | unsigned NewLength = Replacements.getShiftedCodePosition( | |||
148 | R.getOffset() + R.getLength()) - | |||
149 | NewOffset; | |||
150 | if (NewLength == R.getLength()) { | |||
151 | R = Replacement(R.getFilePath(), NewOffset, NewLength, | |||
152 | R.getReplacementText()); | |||
153 | Replacements = Replacements.merge(tooling::Replacements(R)); | |||
154 | CanBeApplied = true; | |||
155 | ++AppliedFixes; | |||
156 | } else { | |||
157 | llvm::errs() | |||
158 | << "Can't resolve conflict, skipping the replacement.\n"; | |||
159 | } | |||
160 | ||||
161 | } else { | |||
162 | CanBeApplied = true; | |||
163 | ++AppliedFixes; | |||
164 | } | |||
165 | } | |||
166 | FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset()); | |||
167 | SourceLocation FixEndLoc = | |||
168 | FixLoc.getLocWithOffset(Repl.getLength()); | |||
169 | Range = SourceRange(FixLoc, FixEndLoc); | |||
170 | Diag << FixItHint::CreateReplacement(Range, | |||
171 | Repl.getReplacementText()); | |||
172 | } | |||
173 | ||||
174 | if (ApplyFixes) | |||
175 | FixLocations.push_back(std::make_pair(FixLoc, CanBeApplied)); | |||
176 | } | |||
177 | } | |||
178 | } | |||
179 | for (auto Fix : FixLocations) { | |||
180 | Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied | |||
181 | : diag::note_fixit_failed); | |||
182 | } | |||
183 | for (const auto &Note : Error.Notes) | |||
184 | reportNote(Note); | |||
185 | } | |||
186 | ||||
187 | void Finish() { | |||
188 | if (ApplyFixes && TotalFixes > 0) { | |||
189 | Rewriter Rewrite(SourceMgr, LangOpts); | |||
190 | for (const auto &FileAndReplacements : FileReplacements) { | |||
191 | StringRef File = FileAndReplacements.first(); | |||
192 | llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = | |||
193 | SourceMgr.getFileManager().getBufferForFile(File); | |||
194 | if (!Buffer) { | |||
195 | llvm::errs() << "Can't get buffer for file " << File << ": " | |||
196 | << Buffer.getError().message() << "\n"; | |||
197 | // FIXME: Maybe don't apply fixes for other files as well. | |||
198 | continue; | |||
199 | } | |||
200 | StringRef Code = Buffer.get()->getBuffer(); | |||
201 | auto Style = format::getStyle( | |||
202 | *Context.getOptionsForFile(File).FormatStyle, File, "none"); | |||
203 | if (!Style) { | |||
204 | llvm::errs() << llvm::toString(Style.takeError()) << "\n"; | |||
205 | continue; | |||
206 | } | |||
207 | llvm::Expected<tooling::Replacements> Replacements = | |||
208 | format::cleanupAroundReplacements(Code, FileAndReplacements.second, | |||
209 | *Style); | |||
210 | if (!Replacements) { | |||
211 | llvm::errs() << llvm::toString(Replacements.takeError()) << "\n"; | |||
212 | continue; | |||
213 | } | |||
214 | if (llvm::Expected<tooling::Replacements> FormattedReplacements = | |||
215 | format::formatReplacements(Code, *Replacements, *Style)) { | |||
216 | Replacements = std::move(FormattedReplacements); | |||
217 | if (!Replacements) | |||
218 | llvm_unreachable("!Replacements")::llvm::llvm_unreachable_internal("!Replacements", "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp" , 218); | |||
219 | } else { | |||
220 | llvm::errs() << llvm::toString(FormattedReplacements.takeError()) | |||
221 | << ". Skipping formatting.\n"; | |||
222 | } | |||
223 | if (!tooling::applyAllReplacements(Replacements.get(), Rewrite)) { | |||
224 | llvm::errs() << "Can't apply replacements for file " << File << "\n"; | |||
225 | } | |||
226 | } | |||
227 | if (Rewrite.overwriteChangedFiles()) { | |||
228 | llvm::errs() << "clang-tidy failed to apply suggested fixes.\n"; | |||
229 | } else { | |||
230 | llvm::errs() << "clang-tidy applied " << AppliedFixes << " of " | |||
231 | << TotalFixes << " suggested fixes.\n"; | |||
232 | } | |||
233 | } | |||
234 | } | |||
235 | ||||
236 | unsigned getWarningsAsErrorsCount() const { return WarningsAsErrors; } | |||
237 | ||||
238 | private: | |||
239 | SourceLocation getLocation(StringRef FilePath, unsigned Offset) { | |||
240 | if (FilePath.empty()) | |||
241 | return SourceLocation(); | |||
242 | ||||
243 | const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath); | |||
244 | FileID ID = SourceMgr.getOrCreateFileID(File, SrcMgr::C_User); | |||
245 | return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset); | |||
246 | } | |||
247 | ||||
248 | void reportNote(const tooling::DiagnosticMessage &Message) { | |||
249 | SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); | |||
250 | Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) | |||
251 | << Message.Message; | |||
252 | } | |||
253 | ||||
254 | FileManager Files; | |||
255 | LangOptions LangOpts; // FIXME: use langopts from each original file | |||
256 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; | |||
257 | DiagnosticConsumer *DiagPrinter; | |||
258 | DiagnosticsEngine Diags; | |||
259 | SourceManager SourceMgr; | |||
260 | llvm::StringMap<Replacements> FileReplacements; | |||
261 | ClangTidyContext &Context; | |||
262 | bool ApplyFixes; | |||
263 | unsigned TotalFixes; | |||
264 | unsigned AppliedFixes; | |||
265 | unsigned WarningsAsErrors; | |||
266 | }; | |||
267 | ||||
268 | class ClangTidyASTConsumer : public MultiplexConsumer { | |||
269 | public: | |||
270 | ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers, | |||
271 | std::unique_ptr<ClangTidyProfiling> Profiling, | |||
272 | std::unique_ptr<ast_matchers::MatchFinder> Finder, | |||
273 | std::vector<std::unique_ptr<ClangTidyCheck>> Checks) | |||
274 | : MultiplexConsumer(std::move(Consumers)), | |||
275 | Profiling(std::move(Profiling)), Finder(std::move(Finder)), | |||
276 | Checks(std::move(Checks)) {} | |||
277 | ||||
278 | private: | |||
279 | // Destructor order matters! Profiling must be destructed last. | |||
280 | // Or at least after Finder. | |||
281 | std::unique_ptr<ClangTidyProfiling> Profiling; | |||
282 | std::unique_ptr<ast_matchers::MatchFinder> Finder; | |||
283 | std::vector<std::unique_ptr<ClangTidyCheck>> Checks; | |||
284 | }; | |||
285 | ||||
286 | } // namespace | |||
287 | ||||
288 | ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory( | |||
289 | ClangTidyContext &Context) | |||
290 | : Context(Context), CheckFactories(new ClangTidyCheckFactories) { | |||
291 | for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(), | |||
292 | E = ClangTidyModuleRegistry::end(); | |||
293 | I != E; ++I) { | |||
294 | std::unique_ptr<ClangTidyModule> Module(I->instantiate()); | |||
295 | Module->addCheckFactories(*CheckFactories); | |||
296 | } | |||
297 | } | |||
298 | ||||
299 | static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts, | |||
300 | AnalyzerOptionsRef AnalyzerOptions) { | |||
301 | StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix); | |||
302 | for (const auto &Opt : Opts.CheckOptions) { | |||
303 | StringRef OptName(Opt.first); | |||
304 | if (!OptName.startswith(AnalyzerPrefix)) | |||
305 | continue; | |||
306 | AnalyzerOptions->Config[OptName.substr(AnalyzerPrefix.size())] = Opt.second; | |||
307 | } | |||
308 | } | |||
309 | ||||
310 | typedef std::vector<std::pair<std::string, bool>> CheckersList; | |||
311 | ||||
312 | static CheckersList getCheckersControlList(ClangTidyContext &Context, | |||
313 | bool IncludeExperimental) { | |||
314 | CheckersList List; | |||
315 | ||||
316 | const auto &RegisteredCheckers = | |||
317 | AnalyzerOptions::getRegisteredCheckers(IncludeExperimental); | |||
318 | bool AnalyzerChecksEnabled = false; | |||
319 | for (StringRef CheckName : RegisteredCheckers) { | |||
320 | std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str()); | |||
321 | AnalyzerChecksEnabled |= Context.isCheckEnabled(ClangTidyCheckName); | |||
322 | } | |||
323 | ||||
324 | if (!AnalyzerChecksEnabled) | |||
325 | return List; | |||
326 | ||||
327 | // List all static analyzer checkers that our filter enables. | |||
328 | // | |||
329 | // Always add all core checkers if any other static analyzer check is enabled. | |||
330 | // This is currently necessary, as other path sensitive checks rely on the | |||
331 | // core checkers. | |||
332 | for (StringRef CheckName : RegisteredCheckers) { | |||
333 | std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str()); | |||
334 | ||||
335 | if (CheckName.startswith("core") || | |||
336 | Context.isCheckEnabled(ClangTidyCheckName)) { | |||
337 | List.emplace_back(CheckName, true); | |||
338 | } | |||
339 | } | |||
340 | return List; | |||
341 | } | |||
342 | ||||
343 | std::unique_ptr<clang::ASTConsumer> | |||
344 | ClangTidyASTConsumerFactory::CreateASTConsumer( | |||
345 | clang::CompilerInstance &Compiler, StringRef File) { | |||
346 | // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't | |||
347 | // modify Compiler. | |||
348 | Context.setSourceManager(&Compiler.getSourceManager()); | |||
349 | Context.setCurrentFile(File); | |||
350 | Context.setASTContext(&Compiler.getASTContext()); | |||
351 | ||||
352 | auto WorkingDir = Compiler.getSourceManager() | |||
353 | .getFileManager() | |||
354 | .getVirtualFileSystem() | |||
355 | ->getCurrentWorkingDirectory(); | |||
356 | if (WorkingDir) | |||
357 | Context.setCurrentBuildDirectory(WorkingDir.get()); | |||
358 | ||||
359 | std::vector<std::unique_ptr<ClangTidyCheck>> Checks; | |||
360 | CheckFactories->createChecks(&Context, Checks); | |||
361 | ||||
362 | ast_matchers::MatchFinder::MatchFinderOptions FinderOptions; | |||
363 | ||||
364 | std::unique_ptr<ClangTidyProfiling> Profiling; | |||
365 | if (Context.getEnableProfiling()) { | |||
366 | Profiling = llvm::make_unique<ClangTidyProfiling>( | |||
367 | Context.getProfileStorageParams()); | |||
368 | FinderOptions.CheckProfiling.emplace(Profiling->Records); | |||
369 | } | |||
370 | ||||
371 | std::unique_ptr<ast_matchers::MatchFinder> Finder( | |||
372 | new ast_matchers::MatchFinder(std::move(FinderOptions))); | |||
373 | ||||
374 | for (auto &Check : Checks) { | |||
375 | Check->registerMatchers(&*Finder); | |||
376 | Check->registerPPCallbacks(Compiler); | |||
377 | } | |||
378 | ||||
379 | std::vector<std::unique_ptr<ASTConsumer>> Consumers; | |||
380 | if (!Checks.empty()) | |||
381 | Consumers.push_back(Finder->newASTConsumer()); | |||
382 | ||||
383 | AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts(); | |||
384 | AnalyzerOptions->CheckersControlList = | |||
385 | getCheckersControlList(Context, Context.canEnableAnalyzerAlphaCheckers()); | |||
386 | if (!AnalyzerOptions->CheckersControlList.empty()) { | |||
387 | setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions); | |||
388 | AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel; | |||
389 | AnalyzerOptions->AnalysisDiagOpt = PD_NONE; | |||
390 | AnalyzerOptions->AnalyzeNestedBlocks = true; | |||
391 | AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true; | |||
392 | std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer = | |||
393 | ento::CreateAnalysisConsumer(Compiler); | |||
394 | AnalysisConsumer->AddDiagnosticConsumer( | |||
395 | new AnalyzerDiagnosticConsumer(Context)); | |||
396 | Consumers.push_back(std::move(AnalysisConsumer)); | |||
397 | } | |||
398 | return llvm::make_unique<ClangTidyASTConsumer>( | |||
399 | std::move(Consumers), std::move(Profiling), std::move(Finder), | |||
400 | std::move(Checks)); | |||
401 | } | |||
402 | ||||
403 | std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() { | |||
404 | std::vector<std::string> CheckNames; | |||
405 | for (const auto &CheckFactory : *CheckFactories) { | |||
406 | if (Context.isCheckEnabled(CheckFactory.first)) | |||
407 | CheckNames.push_back(CheckFactory.first); | |||
408 | } | |||
409 | ||||
410 | for (const auto &AnalyzerCheck : getCheckersControlList( | |||
411 | Context, Context.canEnableAnalyzerAlphaCheckers())) | |||
412 | CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first); | |||
413 | ||||
414 | std::sort(CheckNames.begin(), CheckNames.end()); | |||
415 | return CheckNames; | |||
416 | } | |||
417 | ||||
418 | ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() { | |||
419 | ClangTidyOptions::OptionMap Options; | |||
420 | std::vector<std::unique_ptr<ClangTidyCheck>> Checks; | |||
421 | CheckFactories->createChecks(&Context, Checks); | |||
422 | for (const auto &Check : Checks) | |||
423 | Check->storeOptions(Options); | |||
424 | return Options; | |||
425 | } | |||
426 | ||||
427 | DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message, | |||
428 | DiagnosticIDs::Level Level) { | |||
429 | return Context->diag(CheckName, Loc, Message, Level); | |||
430 | } | |||
431 | ||||
432 | void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) { | |||
433 | Context->setSourceManager(Result.SourceManager); | |||
434 | check(Result); | |||
435 | } | |||
436 | ||||
437 | OptionsView::OptionsView(StringRef CheckName, | |||
438 | const ClangTidyOptions::OptionMap &CheckOptions) | |||
439 | : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {} | |||
440 | ||||
441 | std::string OptionsView::get(StringRef LocalName, StringRef Default) const { | |||
442 | const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str()); | |||
443 | if (Iter != CheckOptions.end()) | |||
444 | return Iter->second; | |||
445 | return Default; | |||
446 | } | |||
447 | ||||
448 | std::string OptionsView::getLocalOrGlobal(StringRef LocalName, | |||
449 | StringRef Default) const { | |||
450 | auto Iter = CheckOptions.find(NamePrefix + LocalName.str()); | |||
451 | if (Iter != CheckOptions.end()) | |||
452 | return Iter->second; | |||
453 | // Fallback to global setting, if present. | |||
454 | Iter = CheckOptions.find(LocalName.str()); | |||
455 | if (Iter != CheckOptions.end()) | |||
456 | return Iter->second; | |||
457 | return Default; | |||
458 | } | |||
459 | ||||
460 | void OptionsView::store(ClangTidyOptions::OptionMap &Options, | |||
461 | StringRef LocalName, StringRef Value) const { | |||
462 | Options[NamePrefix + LocalName.str()] = Value; | |||
463 | } | |||
464 | ||||
465 | void OptionsView::store(ClangTidyOptions::OptionMap &Options, | |||
466 | StringRef LocalName, int64_t Value) const { | |||
467 | store(Options, LocalName, llvm::itostr(Value)); | |||
468 | } | |||
469 | ||||
470 | std::vector<std::string> | |||
471 | getCheckNames(const ClangTidyOptions &Options, | |||
472 | bool AllowEnablingAnalyzerAlphaCheckers) { | |||
473 | clang::tidy::ClangTidyContext Context( | |||
474 | llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), | |||
475 | Options), | |||
476 | AllowEnablingAnalyzerAlphaCheckers); | |||
477 | ClangTidyASTConsumerFactory Factory(Context); | |||
478 | return Factory.getCheckNames(); | |||
479 | } | |||
480 | ||||
481 | ClangTidyOptions::OptionMap | |||
482 | getCheckOptions(const ClangTidyOptions &Options, | |||
483 | bool AllowEnablingAnalyzerAlphaCheckers) { | |||
484 | clang::tidy::ClangTidyContext Context( | |||
485 | llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), | |||
486 | Options), | |||
487 | AllowEnablingAnalyzerAlphaCheckers); | |||
488 | ClangTidyASTConsumerFactory Factory(Context); | |||
489 | return Factory.getCheckOptions(); | |||
490 | } | |||
491 | ||||
492 | void runClangTidy(clang::tidy::ClangTidyContext &Context, | |||
493 | const CompilationDatabase &Compilations, | |||
494 | ArrayRef<std::string> InputFiles, | |||
495 | llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS, | |||
496 | bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) { | |||
497 | ClangTool Tool(Compilations, InputFiles, | |||
498 | std::make_shared<PCHContainerOperations>(), BaseFS); | |||
499 | ||||
500 | // Add extra arguments passed by the clang-tidy command-line. | |||
501 | ArgumentsAdjuster PerFileExtraArgumentsInserter = | |||
502 | [&Context](const CommandLineArguments &Args, StringRef Filename) { | |||
503 | ClangTidyOptions Opts = Context.getOptionsForFile(Filename); | |||
504 | CommandLineArguments AdjustedArgs = Args; | |||
505 | if (Opts.ExtraArgsBefore) { | |||
506 | auto I = AdjustedArgs.begin(); | |||
507 | if (I != AdjustedArgs.end() && !StringRef(*I).startswith("-")) | |||
508 | ++I; // Skip compiler binary name, if it is there. | |||
509 | AdjustedArgs.insert(I, Opts.ExtraArgsBefore->begin(), | |||
510 | Opts.ExtraArgsBefore->end()); | |||
511 | } | |||
512 | if (Opts.ExtraArgs) | |||
513 | AdjustedArgs.insert(AdjustedArgs.end(), Opts.ExtraArgs->begin(), | |||
514 | Opts.ExtraArgs->end()); | |||
515 | return AdjustedArgs; | |||
516 | }; | |||
517 | ||||
518 | // Remove plugins arguments. | |||
519 | ArgumentsAdjuster PluginArgumentsRemover = | |||
520 | [](const CommandLineArguments &Args, StringRef Filename) { | |||
521 | CommandLineArguments AdjustedArgs; | |||
522 | for (size_t I = 0, E = Args.size(); I < E; ++I) { | |||
523 | if (I + 4 < Args.size() && Args[I] == "-Xclang" && | |||
524 | (Args[I + 1] == "-load" || Args[I + 1] == "-add-plugin" || | |||
525 | StringRef(Args[I + 1]).startswith("-plugin-arg-")) && | |||
526 | Args[I + 2] == "-Xclang") { | |||
527 | I += 3; | |||
528 | } else | |||
529 | AdjustedArgs.push_back(Args[I]); | |||
530 | } | |||
531 | return AdjustedArgs; | |||
532 | }; | |||
533 | ||||
534 | Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter); | |||
535 | Tool.appendArgumentsAdjuster(PluginArgumentsRemover); | |||
536 | Context.setEnableProfiling(EnableCheckProfile); | |||
537 | Context.setProfileStoragePrefix(StoreCheckProfile); | |||
538 | ||||
539 | ClangTidyDiagnosticConsumer DiagConsumer(Context); | |||
540 | ||||
541 | Tool.setDiagnosticConsumer(&DiagConsumer); | |||
542 | ||||
543 | class ActionFactory : public FrontendActionFactory { | |||
544 | public: | |||
545 | ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {} | |||
546 | FrontendAction *create() override { return new Action(&ConsumerFactory); } | |||
547 | ||||
548 | bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, | |||
549 | FileManager *Files, | |||
550 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | |||
551 | DiagnosticConsumer *DiagConsumer) override { | |||
552 | // Explicitly set ProgramAction to RunAnalysis to make the preprocessor | |||
553 | // define __clang_analyzer__ macro. The frontend analyzer action will not | |||
554 | // be called here. | |||
555 | Invocation->getFrontendOpts().ProgramAction = frontend::RunAnalysis; | |||
556 | return FrontendActionFactory::runInvocation( | |||
557 | Invocation, Files, PCHContainerOps, DiagConsumer); | |||
558 | } | |||
559 | ||||
560 | private: | |||
561 | class Action : public ASTFrontendAction { | |||
562 | public: | |||
563 | Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {} | |||
564 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, | |||
565 | StringRef File) override { | |||
566 | return Factory->CreateASTConsumer(Compiler, File); | |||
567 | } | |||
568 | ||||
569 | private: | |||
570 | ClangTidyASTConsumerFactory *Factory; | |||
571 | }; | |||
572 | ||||
573 | ClangTidyASTConsumerFactory ConsumerFactory; | |||
574 | }; | |||
575 | ||||
576 | ActionFactory Factory(Context); | |||
577 | Tool.run(&Factory); | |||
578 | } | |||
579 | ||||
580 | void handleErrors(ClangTidyContext &Context, bool Fix, | |||
581 | unsigned &WarningsAsErrorsCount, | |||
582 | llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) { | |||
583 | ErrorReporter Reporter(Context, Fix, BaseFS); | |||
| ||||
584 | vfs::FileSystem &FileSystem = | |||
585 | *Reporter.getSourceManager().getFileManager().getVirtualFileSystem(); | |||
586 | auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory(); | |||
587 | if (!InitialWorkingDir) | |||
588 | llvm::report_fatal_error("Cannot get current working path."); | |||
589 | ||||
590 | for (const ClangTidyError &Error : Context.getErrors()) { | |||
591 | if (!Error.BuildDirectory.empty()) { | |||
592 | // By default, the working directory of file system is the current | |||
593 | // clang-tidy running directory. | |||
594 | // | |||
595 | // Change the directory to the one used during the analysis. | |||
596 | FileSystem.setCurrentWorkingDirectory(Error.BuildDirectory); | |||
597 | } | |||
598 | Reporter.reportDiagnostic(Error); | |||
599 | // Return to the initial directory to correctly resolve next Error. | |||
600 | FileSystem.setCurrentWorkingDirectory(InitialWorkingDir.get()); | |||
601 | } | |||
602 | Reporter.Finish(); | |||
603 | WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount(); | |||
604 | } | |||
605 | ||||
606 | void exportReplacements(const llvm::StringRef MainFilePath, | |||
607 | const std::vector<ClangTidyError> &Errors, | |||
608 | raw_ostream &OS) { | |||
609 | TranslationUnitDiagnostics TUD; | |||
610 | TUD.MainSourceFile = MainFilePath; | |||
611 | for (const auto &Error : Errors) { | |||
612 | tooling::Diagnostic Diag = Error; | |||
613 | TUD.Diagnostics.insert(TUD.Diagnostics.end(), Diag); | |||
614 | } | |||
615 | ||||
616 | yaml::Output YAML(OS); | |||
617 | YAML << TUD; | |||
618 | } | |||
619 | ||||
620 | } // namespace tidy | |||
621 | } // namespace clang |
1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// | |||
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 | // This file defines the RefCountedBase, ThreadSafeRefCountedBase, and | |||
11 | // IntrusiveRefCntPtr classes. | |||
12 | // | |||
13 | // IntrusiveRefCntPtr is a smart pointer to an object which maintains a | |||
14 | // reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a | |||
15 | // refcount member variable and methods for updating the refcount. An object | |||
16 | // that inherits from (ThreadSafe)RefCountedBase deletes itself when its | |||
17 | // refcount hits zero. | |||
18 | // | |||
19 | // For example: | |||
20 | // | |||
21 | // class MyClass : public RefCountedBase<MyClass> {}; | |||
22 | // | |||
23 | // void foo() { | |||
24 | // // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by | |||
25 | // // 1 (from 0 in this case). | |||
26 | // IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); | |||
27 | // | |||
28 | // // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. | |||
29 | // IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); | |||
30 | // | |||
31 | // // Constructing an IntrusiveRefCntPtr has no effect on the object's | |||
32 | // // refcount. After a move, the moved-from pointer is null. | |||
33 | // IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); | |||
34 | // assert(Ptr1 == nullptr); | |||
35 | // | |||
36 | // // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. | |||
37 | // Ptr2.reset(); | |||
38 | // | |||
39 | // // The object deletes itself when we return from the function, because | |||
40 | // // Ptr3's destructor decrements its refcount to 0. | |||
41 | // } | |||
42 | // | |||
43 | // You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: | |||
44 | // | |||
45 | // IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); | |||
46 | // OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required | |||
47 | // | |||
48 | // IntrusiveRefCntPtr works with any class that | |||
49 | // | |||
50 | // - inherits from (ThreadSafe)RefCountedBase, | |||
51 | // - has Retain() and Release() methods, or | |||
52 | // - specializes IntrusiveRefCntPtrInfo. | |||
53 | // | |||
54 | //===----------------------------------------------------------------------===// | |||
55 | ||||
56 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
57 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
58 | ||||
59 | #include <atomic> | |||
60 | #include <cassert> | |||
61 | #include <cstddef> | |||
62 | ||||
63 | namespace llvm { | |||
64 | ||||
65 | /// A CRTP mixin class that adds reference counting to a type. | |||
66 | /// | |||
67 | /// The lifetime of an object which inherits from RefCountedBase is managed by | |||
68 | /// calls to Release() and Retain(), which increment and decrement the object's | |||
69 | /// refcount, respectively. When a Release() call decrements the refcount to 0, | |||
70 | /// the object deletes itself. | |||
71 | template <class Derived> class RefCountedBase { | |||
72 | mutable unsigned RefCount = 0; | |||
73 | ||||
74 | public: | |||
75 | RefCountedBase() = default; | |||
76 | RefCountedBase(const RefCountedBase &) {} | |||
77 | ||||
78 | void Retain() const { ++RefCount; } | |||
79 | ||||
80 | void Release() const { | |||
81 | assert(RefCount > 0 && "Reference count is already zero.")(static_cast <bool> (RefCount > 0 && "Reference count is already zero." ) ? void (0) : __assert_fail ("RefCount > 0 && \"Reference count is already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn338205/include/llvm/ADT/IntrusiveRefCntPtr.h" , 81, __extension__ __PRETTY_FUNCTION__)); | |||
82 | if (--RefCount == 0) | |||
83 | delete static_cast<const Derived *>(this); | |||
84 | } | |||
85 | }; | |||
86 | ||||
87 | /// A thread-safe version of \c RefCountedBase. | |||
88 | template <class Derived> class ThreadSafeRefCountedBase { | |||
89 | mutable std::atomic<int> RefCount; | |||
90 | ||||
91 | protected: | |||
92 | ThreadSafeRefCountedBase() : RefCount(0) {} | |||
93 | ||||
94 | public: | |||
95 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } | |||
96 | ||||
97 | void Release() const { | |||
98 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; | |||
99 | assert(NewRefCount >= 0 && "Reference count was already zero.")(static_cast <bool> (NewRefCount >= 0 && "Reference count was already zero." ) ? void (0) : __assert_fail ("NewRefCount >= 0 && \"Reference count was already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn338205/include/llvm/ADT/IntrusiveRefCntPtr.h" , 99, __extension__ __PRETTY_FUNCTION__)); | |||
100 | if (NewRefCount == 0) | |||
101 | delete static_cast<const Derived *>(this); | |||
102 | } | |||
103 | }; | |||
104 | ||||
105 | /// Class you can specialize to provide custom retain/release functionality for | |||
106 | /// a type. | |||
107 | /// | |||
108 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr | |||
109 | /// works with any type which defines Retain() and Release() functions -- you | |||
110 | /// can define those functions yourself if RefCountedBase doesn't work for you. | |||
111 | /// | |||
112 | /// One case when you might want to specialize this type is if you have | |||
113 | /// - Foo.h defines type Foo and includes Bar.h, and | |||
114 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. | |||
115 | /// | |||
116 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in | |||
117 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h | |||
118 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call | |||
119 | /// T::Retain and T::Release. | |||
120 | /// | |||
121 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which | |||
122 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then | |||
123 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any | |||
124 | /// functions on Foo itself, because Foo would be an incomplete type. | |||
125 | template <typename T> struct IntrusiveRefCntPtrInfo { | |||
126 | static void retain(T *obj) { obj->Retain(); } | |||
127 | static void release(T *obj) { obj->Release(); } | |||
128 | }; | |||
129 | ||||
130 | /// A smart pointer to a reference-counted object that inherits from | |||
131 | /// RefCountedBase or ThreadSafeRefCountedBase. | |||
132 | /// | |||
133 | /// This class increments its pointee's reference count when it is created, and | |||
134 | /// decrements its refcount when it's destroyed (or is changed to point to a | |||
135 | /// different object). | |||
136 | template <typename T> class IntrusiveRefCntPtr { | |||
137 | T *Obj = nullptr; | |||
138 | ||||
139 | public: | |||
140 | using element_type = T; | |||
141 | ||||
142 | explicit IntrusiveRefCntPtr() = default; | |||
143 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } | |||
144 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } | |||
145 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } | |||
146 | ||||
147 | template <class X> | |||
148 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { | |||
149 | S.Obj = nullptr; | |||
150 | } | |||
151 | ||||
152 | template <class X> | |||
153 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { | |||
154 | retain(); | |||
155 | } | |||
156 | ||||
157 | ~IntrusiveRefCntPtr() { release(); } | |||
| ||||
158 | ||||
159 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { | |||
160 | swap(S); | |||
161 | return *this; | |||
162 | } | |||
163 | ||||
164 | T &operator*() const { return *Obj; } | |||
165 | T *operator->() const { return Obj; } | |||
166 | T *get() const { return Obj; } | |||
167 | explicit operator bool() const { return Obj; } | |||
168 | ||||
169 | void swap(IntrusiveRefCntPtr &other) { | |||
170 | T *tmp = other.Obj; | |||
171 | other.Obj = Obj; | |||
172 | Obj = tmp; | |||
173 | } | |||
174 | ||||
175 | void reset() { | |||
176 | release(); | |||
177 | Obj = nullptr; | |||
178 | } | |||
179 | ||||
180 | void resetWithoutRelease() { Obj = nullptr; } | |||
181 | ||||
182 | private: | |||
183 | void retain() { | |||
184 | if (Obj) | |||
185 | IntrusiveRefCntPtrInfo<T>::retain(Obj); | |||
186 | } | |||
187 | ||||
188 | void release() { | |||
189 | if (Obj) | |||
190 | IntrusiveRefCntPtrInfo<T>::release(Obj); | |||
191 | } | |||
192 | ||||
193 | template <typename X> friend class IntrusiveRefCntPtr; | |||
194 | }; | |||
195 | ||||
196 | template <class T, class U> | |||
197 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, | |||
198 | const IntrusiveRefCntPtr<U> &B) { | |||
199 | return A.get() == B.get(); | |||
200 | } | |||
201 | ||||
202 | template <class T, class U> | |||
203 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, | |||
204 | const IntrusiveRefCntPtr<U> &B) { | |||
205 | return A.get() != B.get(); | |||
206 | } | |||
207 | ||||
208 | template <class T, class U> | |||
209 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
210 | return A.get() == B; | |||
211 | } | |||
212 | ||||
213 | template <class T, class U> | |||
214 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
215 | return A.get() != B; | |||
216 | } | |||
217 | ||||
218 | template <class T, class U> | |||
219 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
220 | return A == B.get(); | |||
221 | } | |||
222 | ||||
223 | template <class T, class U> | |||
224 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
225 | return A != B.get(); | |||
226 | } | |||
227 | ||||
228 | template <class T> | |||
229 | bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
230 | return !B; | |||
231 | } | |||
232 | ||||
233 | template <class T> | |||
234 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
235 | return B == A; | |||
236 | } | |||
237 | ||||
238 | template <class T> | |||
239 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
240 | return !(A == B); | |||
241 | } | |||
242 | ||||
243 | template <class T> | |||
244 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
245 | return !(A == B); | |||
246 | } | |||
247 | ||||
248 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from | |||
249 | // Casting.h. | |||
250 | template <typename From> struct simplify_type; | |||
251 | ||||
252 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { | |||
253 | using SimpleType = T *; | |||
254 | ||||
255 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { | |||
256 | return Val.get(); | |||
257 | } | |||
258 | }; | |||
259 | ||||
260 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { | |||
261 | using SimpleType = /*const*/ T *; | |||
262 | ||||
263 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { | |||
264 | return Val.get(); | |||
265 | } | |||
266 | }; | |||
267 | ||||
268 | } // end namespace llvm | |||
269 | ||||
270 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |