10 #include "../clang-tidy/ClangTidyCheck.h"
11 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
12 #include "../clang-tidy/ClangTidyModuleRegistry.h"
24 #include "clang/AST/ASTContext.h"
25 #include "clang/AST/Decl.h"
26 #include "clang/Basic/LangOptions.h"
27 #include "clang/Basic/SourceLocation.h"
28 #include "clang/Basic/SourceManager.h"
29 #include "clang/Basic/TokenKinds.h"
30 #include "clang/Frontend/CompilerInstance.h"
31 #include "clang/Frontend/CompilerInvocation.h"
32 #include "clang/Frontend/FrontendActions.h"
33 #include "clang/Frontend/Utils.h"
34 #include "clang/Index/IndexDataConsumer.h"
35 #include "clang/Index/IndexingAction.h"
36 #include "clang/Lex/Lexer.h"
37 #include "clang/Lex/MacroInfo.h"
38 #include "clang/Lex/PPCallbacks.h"
39 #include "clang/Lex/Preprocessor.h"
40 #include "clang/Lex/PreprocessorOptions.h"
41 #include "clang/Sema/Sema.h"
42 #include "clang/Serialization/ASTWriter.h"
43 #include "clang/Serialization/PCHContainerOperations.h"
44 #include "clang/Tooling/CompilationDatabase.h"
45 #include "clang/Tooling/Syntax/Tokens.h"
46 #include "llvm/ADT/ArrayRef.h"
47 #include "llvm/ADT/STLExtras.h"
48 #include "llvm/ADT/SmallString.h"
49 #include "llvm/ADT/SmallVector.h"
50 #include "llvm/ADT/StringRef.h"
51 #include "llvm/Support/raw_ostream.h"
58 #define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS
59 #include "../clang-tidy/ClangTidyForceLinker.h"
65 template <
class T> std::size_t getUsedBytes(
const std::vector<T> &Vec) {
66 return Vec.capacity() *
sizeof(T);
69 class DeclTrackingASTConsumer :
public ASTConsumer {
71 DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
72 : TopLevelDecls(TopLevelDecls) {}
74 bool HandleTopLevelDecl(DeclGroupRef DG)
override {
76 auto &SM = D->getASTContext().getSourceManager();
79 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(D))
84 if (isa<ObjCMethodDecl>(D))
87 TopLevelDecls.push_back(D);
93 std::vector<Decl *> &TopLevelDecls;
98 std::vector<Decl *> takeTopLevelDecls() {
return std::move(TopLevelDecls); }
101 std::unique_ptr<ASTConsumer>
102 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
103 return std::make_unique<DeclTrackingASTConsumer>( TopLevelDecls);
107 std::vector<Decl *> TopLevelDecls;
121 static void attach(std::vector<Inclusion> Includes, CompilerInstance &Clang,
122 const PreambleBounds &PB) {
123 auto &PP = Clang.getPreprocessor();
124 auto *ExistingCallbacks = PP.getPPCallbacks();
126 if (!ExistingCallbacks)
128 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(
new ReplayPreamble(
129 std::move(Includes), ExistingCallbacks, Clang.getSourceManager(), PP,
130 Clang.getLangOpts(), PB)));
133 assert(PP.getPPCallbacks() != ExistingCallbacks &&
134 "Expected chaining implementation");
138 ReplayPreamble(std::vector<Inclusion> Includes,
PPCallbacks *Delegate,
139 const SourceManager &SM, Preprocessor &PP,
140 const LangOptions &LangOpts,
const PreambleBounds &PB)
141 : Includes(std::move(Includes)), Delegate(Delegate), SM(SM), PP(PP) {
144 MainFileTokens = syntax::tokenize(
145 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts);
163 void FileChanged(SourceLocation
Loc, FileChangeReason Reason,
164 SrcMgr::CharacteristicKind
Kind, FileID PrevFID)
override {
166 if (Reason == FileChangeReason::ExitFile &&
167 SM.getBuffer(PrevFID)->getBufferIdentifier() ==
"<built-in>")
172 for (
const auto &Inc : Includes) {
173 const FileEntry *
File =
nullptr;
174 if (Inc.Resolved !=
"")
175 if (
auto FE = SM.getFileManager().getFile(Inc.Resolved))
179 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
180 auto HashTok = llvm::partition_point(MainFileTokens,
181 [&HashLoc](
const syntax::Token &T) {
182 return T.location() < HashLoc;
184 assert(HashTok != MainFileTokens.end() && HashTok->kind() == tok::hash);
186 auto IncludeTok = std::next(HashTok);
187 assert(IncludeTok != MainFileTokens.end());
189 auto FileTok = std::next(IncludeTok);
190 assert(FileTok != MainFileTokens.end());
194 Token SynthesizedIncludeTok;
195 SynthesizedIncludeTok.startToken();
196 SynthesizedIncludeTok.setLocation(IncludeTok->location());
197 SynthesizedIncludeTok.setLength(IncludeTok->length());
198 SynthesizedIncludeTok.setKind(tok::raw_identifier);
199 SynthesizedIncludeTok.setRawIdentifierData(IncludeTok->text(SM).data());
200 PP.LookUpIdentifierInfo(SynthesizedIncludeTok);
203 Token SynthesizedFilenameTok;
204 SynthesizedFilenameTok.startToken();
205 SynthesizedFilenameTok.setLocation(FileTok->location());
210 SynthesizedFilenameTok.setLength(Inc.Written.length());
211 SynthesizedFilenameTok.setKind(tok::header_name);
212 SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
214 llvm::StringRef WrittenFilename =
215 llvm::StringRef(Inc.Written).drop_front().drop_back();
216 Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok,
217 WrittenFilename, Inc.Written.front() ==
'<',
218 FileTok->range(SM).toCharRange(SM),
File,
219 "SearchPath",
"RelPath",
220 nullptr, Inc.FileKind);
223 Delegate->FileSkipped(FileEntryRef(
File->getName(), *
File),
224 SynthesizedFilenameTok, Inc.FileKind);
226 llvm::SmallString<1> UnusedRecovery;
227 Delegate->FileNotFound(WrittenFilename, UnusedRecovery);
232 const std::vector<Inclusion> Includes;
234 const SourceManager &SM;
236 std::vector<syntax::Token> MainFileTokens;
245 llvm::Optional<ParsedAST>
247 std::unique_ptr<clang::CompilerInvocation>
CI,
248 llvm::ArrayRef<Diag> CompilerInvocationDiags,
249 std::shared_ptr<const PreambleData>
Preamble) {
253 auto VFS =
Inputs.TFS->view(
Inputs.CompileCommand.Directory);
255 VFS =
Preamble->StatCache->getConsumingFS(std::move(VFS));
260 CI->getFrontendOpts().DisableFree =
false;
261 const PrecompiledPreamble *PreamblePCH =
266 CI->getLangOpts()->DelayedTemplateParsing =
false;
270 llvm::Optional<PreamblePatch>
Patch;
276 std::move(
CI), PreamblePCH,
277 llvm::MemoryBuffer::getMemBufferCopy(
Inputs.Contents,
Filename), VFS,
282 auto Action = std::make_unique<ClangdFrontendAction>();
283 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
284 if (!Action->BeginSourceFile(*Clang, MainInput)) {
285 log(
"BeginSourceFile() failed when building AST for {0}",
286 MainInput.getFile());
296 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks;
297 ast_matchers::MatchFinder CTFinder;
298 llvm::Optional<tidy::ClangTidyContext> CTContext;
301 dlog(
"ClangTidy configuration for file {0}: {1}",
Filename,
304 for (
const auto &
E : tidy::ClangTidyModuleRegistry::entries())
305 E.instantiate()->addCheckFactories(CTFactories);
306 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
308 CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
309 CTContext->setASTContext(&Clang->getASTContext());
310 CTContext->setCurrentFile(
Filename);
311 CTChecks = CTFactories.
createChecks(CTContext.getPointer());
315 std::string CheckName = CTContext->getCheckName(
Info.getID());
316 bool IsClangTidyDiag = !CheckName.empty();
317 if (IsClangTidyDiag) {
324 bool IsInsideMainFile =
325 Info.hasSourceManager() &&
327 if (IsInsideMainFile &&
330 return DiagnosticsEngine::Ignored;
335 CTContext->treatAsError(CheckName)) {
342 Preprocessor *PP = &Clang->getPreprocessor();
343 for (
const auto &Check : CTChecks) {
344 if (!Check->isLanguageVersionSupported(CTContext->getLangOpts()))
348 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP);
349 Check->registerMatchers(&CTFinder);
355 llvm::Optional<IncludeFixer> FixIncludes;
356 auto BuildDir = VFS->getCurrentWorkingDirectory();
357 if (
Inputs.Opts.SuggestMissingIncludes &&
Inputs.Index &&
358 !BuildDir.getError()) {
360 auto Inserter = std::make_shared<IncludeInserter>(
362 &Clang->getPreprocessor().getHeaderSearchInfo());
364 for (
const auto &Inc :
Preamble->Includes.MainFileIncludes)
365 Inserter->addExisting(Inc);
369 ASTDiags.
contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl,
371 return FixIncludes->fix(DiagLevl,
Info);
373 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder());
380 Includes.MainFileIncludes =
Patch->preambleIncludes();
382 ReplayPreamble::attach(
Patch->preambleIncludes(), *Clang,
383 Patch->modifiedBounds());
388 Clang->getPreprocessor().addPPCallbacks(
395 Clang->getPreprocessor().addPPCallbacks(
396 std::make_unique<CollectMainFileMacros>(Clang->getSourceManager(),
403 CanonIncludes =
Preamble->CanonIncludes;
405 CanonIncludes.addSystemHeadersMapping(Clang->getLangOpts());
406 std::unique_ptr<CommentHandler> IWYUHandler =
408 Clang->getPreprocessor().addCommentHandler(IWYUHandler.get());
411 syntax::TokenCollector CollectTokens(Clang->getPreprocessor());
414 log(
"Execute() failed when building AST for {0}: {1}", MainInput.getFile(),
420 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();
421 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
423 Clang->getASTContext().setTraversalScope(ParsedDecls);
428 CTFinder.matchAST(Clang->getASTContext());
439 Clang->getPreprocessor().EndSourceFile();
441 std::vector<Diag> Diags = CompilerInvocationDiags;
447 std::vector<Diag> D = ASTDiags.
take(CTContext.getPointer());
448 Diags.insert(Diags.end(), D.begin(), D.end());
451 std::move(Action), std::move(Tokens), std::move(Macros),
452 std::move(ParsedDecls), std::move(Diags),
453 std::move(Includes), std::move(CanonIncludes));
464 auto PP = Clang->getPreprocessorPtr();
465 Clang->setPreprocessor(
nullptr);
466 Action->EndSourceFile();
474 return Clang->getASTContext();
480 return Clang->getPreprocessorPtr();
484 return Clang->getPreprocessor();
488 return LocalTopLevelDecls;
500 clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags);
506 Total +=
AST.getASTAllocatedMemory();
507 Total +=
AST.getSideTableAllocatedMemory();
508 Total +=
AST.Idents.getAllocator().getTotalMemory();
509 Total +=
AST.Selectors.getTotalMemory();
511 Total +=
AST.getSourceManager().getContentCacheSize();
512 Total +=
AST.getSourceManager().getDataStructureSizes();
513 Total +=
AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
515 if (ExternalASTSource *Ext =
AST.getExternalSource())
516 Total += Ext->getMemoryBufferSizes().malloc_bytes;
519 Total += PP.getTotalMemory();
520 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
521 Total += PRec->getTotalMemory();
522 Total += PP.getHeaderSearchInfo().getTotalMemory();
532 return CanonIncludes;
536 std::shared_ptr<const PreambleData>
Preamble,
537 std::unique_ptr<CompilerInstance> Clang,
538 std::unique_ptr<FrontendAction>
Action,
540 std::vector<Decl *> LocalTopLevelDecls,
545 Macros(std::move(Macros)),
Diags(std::move(
Diags)),
546 LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
547 Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) {
549 assert(this->Action);
555 return llvm::StringRef(Preamble->Version);