Bug Summary

File:include/llvm/ADT/IntrusiveRefCntPtr.h
Warning:line 157, column 38
Potential leak of memory pointed to by field 'Obj'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ClangTidy.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -relaxed-aliasing -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/tools/clang/tools/extra/clang-tidy -I /build/llvm-toolchain-snapshot-7~svn338205/tools/clang/tools/extra/clang-tidy -I /build/llvm-toolchain-snapshot-7~svn338205/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn338205/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/lib/gcc/x86_64-linux-gnu/8/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/tools/clang/tools/extra/clang-tidy -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fno-common -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-07-29-043837-17923-1 -x c++ /build/llvm-toolchain-snapshot-7~svn338205/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp -faddrsig

/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/tools/extra/clang-tidy/ClangTidy.cpp

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
48using namespace clang::ast_matchers;
49using namespace clang::driver;
50using namespace clang::tooling;
51using namespace llvm;
52
53LLVM_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
55namespace clang {
56namespace tidy {
57
58namespace {
59static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
60
61class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
62public:
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
87private:
88 ClangTidyContext &Context;
89};
90
91class ErrorReporter {
92public:
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,
2
Memory is allocated
3
Calling '~IntrusiveRefCntPtr'
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
238private:
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
268class ClangTidyASTConsumer : public MultiplexConsumer {
269public:
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
278private:
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
288ClangTidyASTConsumerFactory::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
299static 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
310typedef std::vector<std::pair<std::string, bool>> CheckersList;
311
312static 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
343std::unique_ptr<clang::ASTConsumer>
344ClangTidyASTConsumerFactory::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
403std::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
418ClangTidyOptions::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
427DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
428 DiagnosticIDs::Level Level) {
429 return Context->diag(CheckName, Loc, Message, Level);
430}
431
432void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
433 Context->setSourceManager(Result.SourceManager);
434 check(Result);
435}
436
437OptionsView::OptionsView(StringRef CheckName,
438 const ClangTidyOptions::OptionMap &CheckOptions)
439 : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
440
441std::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
448std::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
460void OptionsView::store(ClangTidyOptions::OptionMap &Options,
461 StringRef LocalName, StringRef Value) const {
462 Options[NamePrefix + LocalName.str()] = Value;
463}
464
465void OptionsView::store(ClangTidyOptions::OptionMap &Options,
466 StringRef LocalName, int64_t Value) const {
467 store(Options, LocalName, llvm::itostr(Value));
468}
469
470std::vector<std::string>
471getCheckNames(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
481ClangTidyOptions::OptionMap
482getCheckOptions(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
492void 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
580void handleErrors(ClangTidyContext &Context, bool Fix,
581 unsigned &WarningsAsErrorsCount,
582 llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
583 ErrorReporter Reporter(Context, Fix, BaseFS);
1
Calling constructor for 'ErrorReporter'
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
606void 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

/build/llvm-toolchain-snapshot-7~svn338205/include/llvm/ADT/IntrusiveRefCntPtr.h

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
63namespace 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.
71template <class Derived> class RefCountedBase {
72 mutable unsigned RefCount = 0;
73
74public:
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.
88template <class Derived> class ThreadSafeRefCountedBase {
89 mutable std::atomic<int> RefCount;
90
91protected:
92 ThreadSafeRefCountedBase() : RefCount(0) {}
93
94public:
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.
125template <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).
136template <typename T> class IntrusiveRefCntPtr {
137 T *Obj = nullptr;
138
139public:
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(); }
4
Potential leak of memory pointed to by field 'Obj'
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
182private:
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
196template <class T, class U>
197inline bool operator==(const IntrusiveRefCntPtr<T> &A,
198 const IntrusiveRefCntPtr<U> &B) {
199 return A.get() == B.get();
200}
201
202template <class T, class U>
203inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
204 const IntrusiveRefCntPtr<U> &B) {
205 return A.get() != B.get();
206}
207
208template <class T, class U>
209inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
210 return A.get() == B;
211}
212
213template <class T, class U>
214inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
215 return A.get() != B;
216}
217
218template <class T, class U>
219inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
220 return A == B.get();
221}
222
223template <class T, class U>
224inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
225 return A != B.get();
226}
227
228template <class T>
229bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
230 return !B;
231}
232
233template <class T>
234bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
235 return B == A;
236}
237
238template <class T>
239bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
240 return !(A == B);
241}
242
243template <class T>
244bool 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.
250template <typename From> struct simplify_type;
251
252template <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
260template <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