Mercurial > hg > CbC > CbC_llvm
comparison clang-tools-extra/clangd/ParsedAST.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
comparison
equal
deleted
inserted
replaced
220:42394fc6a535 | 221:79ff65ed7e25 |
---|---|
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 // | 6 // |
7 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
8 | 8 |
9 #include "ParsedAST.h" | 9 #include "ParsedAST.h" |
10 #include "../clang-tidy/ClangTidyCheck.h" | |
10 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" | 11 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h" |
11 #include "../clang-tidy/ClangTidyModuleRegistry.h" | 12 #include "../clang-tidy/ClangTidyModuleRegistry.h" |
12 #include "AST.h" | 13 #include "AST.h" |
13 #include "Compiler.h" | 14 #include "Compiler.h" |
15 #include "Config.h" | |
14 #include "Diagnostics.h" | 16 #include "Diagnostics.h" |
17 #include "FeatureModule.h" | |
15 #include "Headers.h" | 18 #include "Headers.h" |
19 #include "HeuristicResolver.h" | |
16 #include "IncludeFixer.h" | 20 #include "IncludeFixer.h" |
21 #include "Preamble.h" | |
17 #include "SourceCode.h" | 22 #include "SourceCode.h" |
23 #include "TidyProvider.h" | |
18 #include "index/CanonicalIncludes.h" | 24 #include "index/CanonicalIncludes.h" |
19 #include "index/Index.h" | 25 #include "index/Index.h" |
20 #include "support/Logger.h" | 26 #include "support/Logger.h" |
21 #include "support/Trace.h" | 27 #include "support/Trace.h" |
22 #include "clang/AST/ASTContext.h" | 28 #include "clang/AST/ASTContext.h" |
23 #include "clang/AST/Decl.h" | 29 #include "clang/AST/Decl.h" |
30 #include "clang/Basic/Diagnostic.h" | |
24 #include "clang/Basic/LangOptions.h" | 31 #include "clang/Basic/LangOptions.h" |
25 #include "clang/Basic/SourceLocation.h" | 32 #include "clang/Basic/SourceLocation.h" |
26 #include "clang/Basic/SourceManager.h" | 33 #include "clang/Basic/SourceManager.h" |
27 #include "clang/Basic/TokenKinds.h" | 34 #include "clang/Basic/TokenKinds.h" |
28 #include "clang/Frontend/CompilerInstance.h" | 35 #include "clang/Frontend/CompilerInstance.h" |
43 #include "clang/Tooling/Syntax/Tokens.h" | 50 #include "clang/Tooling/Syntax/Tokens.h" |
44 #include "llvm/ADT/ArrayRef.h" | 51 #include "llvm/ADT/ArrayRef.h" |
45 #include "llvm/ADT/STLExtras.h" | 52 #include "llvm/ADT/STLExtras.h" |
46 #include "llvm/ADT/SmallString.h" | 53 #include "llvm/ADT/SmallString.h" |
47 #include "llvm/ADT/SmallVector.h" | 54 #include "llvm/ADT/SmallVector.h" |
55 #include "llvm/ADT/StringRef.h" | |
48 #include "llvm/Support/raw_ostream.h" | 56 #include "llvm/Support/raw_ostream.h" |
49 #include <algorithm> | 57 #include <algorithm> |
50 #include <memory> | 58 #include <memory> |
59 #include <vector> | |
51 | 60 |
52 // Force the linker to link in Clang-tidy modules. | 61 // Force the linker to link in Clang-tidy modules. |
53 // clangd doesn't support the static analyzer. | 62 // clangd doesn't support the static analyzer. |
54 #define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS | 63 #define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS |
55 #include "../clang-tidy/ClangTidyForceLinker.h" | 64 #include "../clang-tidy/ClangTidyForceLinker.h" |
112 class ReplayPreamble : private PPCallbacks { | 121 class ReplayPreamble : private PPCallbacks { |
113 public: | 122 public: |
114 // Attach preprocessor hooks such that preamble events will be injected at | 123 // Attach preprocessor hooks such that preamble events will be injected at |
115 // the appropriate time. | 124 // the appropriate time. |
116 // Events will be delivered to the *currently registered* PP callbacks. | 125 // Events will be delivered to the *currently registered* PP callbacks. |
117 static void attach(const IncludeStructure &Includes, CompilerInstance &Clang, | 126 static void attach(std::vector<Inclusion> Includes, CompilerInstance &Clang, |
118 const PreambleBounds &PB) { | 127 const PreambleBounds &PB) { |
119 auto &PP = Clang.getPreprocessor(); | 128 auto &PP = Clang.getPreprocessor(); |
120 auto *ExistingCallbacks = PP.getPPCallbacks(); | 129 auto *ExistingCallbacks = PP.getPPCallbacks(); |
121 // No need to replay events if nobody is listening. | 130 // No need to replay events if nobody is listening. |
122 if (!ExistingCallbacks) | 131 if (!ExistingCallbacks) |
123 return; | 132 return; |
124 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble( | 133 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble( |
125 Includes, ExistingCallbacks, Clang.getSourceManager(), PP, | 134 std::move(Includes), ExistingCallbacks, Clang.getSourceManager(), PP, |
126 Clang.getLangOpts(), PB))); | 135 Clang.getLangOpts(), PB))); |
127 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks | 136 // We're relying on the fact that addPPCallbacks keeps the old PPCallbacks |
128 // around, creating a chaining wrapper. Guard against other implementations. | 137 // around, creating a chaining wrapper. Guard against other implementations. |
129 assert(PP.getPPCallbacks() != ExistingCallbacks && | 138 assert(PP.getPPCallbacks() != ExistingCallbacks && |
130 "Expected chaining implementation"); | 139 "Expected chaining implementation"); |
131 } | 140 } |
132 | 141 |
133 private: | 142 private: |
134 ReplayPreamble(const IncludeStructure &Includes, PPCallbacks *Delegate, | 143 ReplayPreamble(std::vector<Inclusion> Includes, PPCallbacks *Delegate, |
135 const SourceManager &SM, Preprocessor &PP, | 144 const SourceManager &SM, Preprocessor &PP, |
136 const LangOptions &LangOpts, const PreambleBounds &PB) | 145 const LangOptions &LangOpts, const PreambleBounds &PB) |
137 : Includes(Includes), Delegate(Delegate), SM(SM), PP(PP) { | 146 : Includes(std::move(Includes)), Delegate(Delegate), SM(SM), PP(PP) { |
138 // Only tokenize the preamble section of the main file, as we are not | 147 // Only tokenize the preamble section of the main file, as we are not |
139 // interested in the rest of the tokens. | 148 // interested in the rest of the tokens. |
140 MainFileTokens = syntax::tokenize( | 149 MainFileTokens = syntax::tokenize( |
141 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts); | 150 syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts); |
142 } | 151 } |
158 // We insert them right after the built-in header, which still appears. | 167 // We insert them right after the built-in header, which still appears. |
159 void FileChanged(SourceLocation Loc, FileChangeReason Reason, | 168 void FileChanged(SourceLocation Loc, FileChangeReason Reason, |
160 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override { | 169 SrcMgr::CharacteristicKind Kind, FileID PrevFID) override { |
161 // It'd be nice if there was a better way to identify built-in headers... | 170 // It'd be nice if there was a better way to identify built-in headers... |
162 if (Reason == FileChangeReason::ExitFile && | 171 if (Reason == FileChangeReason::ExitFile && |
163 SM.getBuffer(PrevFID)->getBufferIdentifier() == "<built-in>") | 172 SM.getBufferOrFake(PrevFID).getBufferIdentifier() == "<built-in>") |
164 replay(); | 173 replay(); |
165 } | 174 } |
166 | 175 |
167 void replay() { | 176 void replay() { |
168 for (const auto &Inc : Includes.MainFileIncludes) { | 177 for (const auto &Inc : Includes) { |
169 const FileEntry *File = nullptr; | 178 llvm::Optional<FileEntryRef> File; |
170 if (Inc.Resolved != "") | 179 if (Inc.Resolved != "") |
171 if (auto FE = SM.getFileManager().getFile(Inc.Resolved)) | 180 File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved)); |
172 File = *FE; | |
173 | 181 |
174 // Re-lex the #include directive to find its interesting parts. | 182 // Re-lex the #include directive to find its interesting parts. |
175 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset); | 183 auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset); |
176 auto HashTok = llvm::partition_point(MainFileTokens, | 184 auto HashTok = llvm::partition_point(MainFileTokens, |
177 [&HashLoc](const syntax::Token &T) { | 185 [&HashLoc](const syntax::Token &T) { |
205 // quotes/angles. | 213 // quotes/angles. |
206 SynthesizedFilenameTok.setLength(Inc.Written.length()); | 214 SynthesizedFilenameTok.setLength(Inc.Written.length()); |
207 SynthesizedFilenameTok.setKind(tok::header_name); | 215 SynthesizedFilenameTok.setKind(tok::header_name); |
208 SynthesizedFilenameTok.setLiteralData(Inc.Written.data()); | 216 SynthesizedFilenameTok.setLiteralData(Inc.Written.data()); |
209 | 217 |
218 const FileEntry *FE = File ? &File->getFileEntry() : nullptr; | |
210 llvm::StringRef WrittenFilename = | 219 llvm::StringRef WrittenFilename = |
211 llvm::StringRef(Inc.Written).drop_front().drop_back(); | 220 llvm::StringRef(Inc.Written).drop_front().drop_back(); |
212 Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok, | 221 Delegate->InclusionDirective(HashTok->location(), SynthesizedIncludeTok, |
213 WrittenFilename, Inc.Written.front() == '<', | 222 WrittenFilename, Inc.Written.front() == '<', |
214 FileTok->range(SM).toCharRange(SM), File, | 223 FileTok->range(SM).toCharRange(SM), FE, |
215 "SearchPath", "RelPath", | 224 "SearchPath", "RelPath", |
216 /*Imported=*/nullptr, Inc.FileKind); | 225 /*Imported=*/nullptr, Inc.FileKind); |
217 if (File) | 226 if (File) |
218 // FIXME: Use correctly named FileEntryRef. | 227 Delegate->FileSkipped(*File, SynthesizedFilenameTok, Inc.FileKind); |
219 Delegate->FileSkipped(FileEntryRef(File->getName(), *File), | |
220 SynthesizedFilenameTok, Inc.FileKind); | |
221 else { | 228 else { |
222 llvm::SmallString<1> UnusedRecovery; | 229 llvm::SmallString<1> UnusedRecovery; |
223 Delegate->FileNotFound(WrittenFilename, UnusedRecovery); | 230 Delegate->FileNotFound(WrittenFilename, UnusedRecovery); |
224 } | 231 } |
225 } | 232 } |
226 } | 233 } |
227 | 234 |
228 const IncludeStructure &Includes; | 235 const std::vector<Inclusion> Includes; |
229 PPCallbacks *Delegate; | 236 PPCallbacks *Delegate; |
230 const SourceManager &SM; | 237 const SourceManager &SM; |
231 Preprocessor &PP; | 238 Preprocessor &PP; |
232 std::vector<syntax::Token> MainFileTokens; | 239 std::vector<syntax::Token> MainFileTokens; |
233 }; | 240 }; |
234 | 241 |
235 } // namespace | 242 } // namespace |
236 | |
237 void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) { | |
238 AST.getASTContext().getTranslationUnitDecl()->dump(OS, true); | |
239 } | |
240 | 243 |
241 llvm::Optional<ParsedAST> | 244 llvm::Optional<ParsedAST> |
242 ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, | 245 ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, |
243 std::unique_ptr<clang::CompilerInvocation> CI, | 246 std::unique_ptr<clang::CompilerInvocation> CI, |
244 llvm::ArrayRef<Diag> CompilerInvocationDiags, | 247 llvm::ArrayRef<Diag> CompilerInvocationDiags, |
245 std::shared_ptr<const PreambleData> Preamble) { | 248 std::shared_ptr<const PreambleData> Preamble) { |
246 trace::Span Tracer("BuildAST"); | 249 trace::Span Tracer("BuildAST"); |
247 SPAN_ATTACH(Tracer, "File", Filename); | 250 SPAN_ATTACH(Tracer, "File", Filename); |
248 | 251 |
249 auto VFS = Inputs.FS; | 252 auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); |
250 if (Preamble && Preamble->StatCache) | 253 if (Preamble && Preamble->StatCache) |
251 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS)); | 254 VFS = Preamble->StatCache->getConsumingFS(std::move(VFS)); |
252 if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { | |
253 log("Couldn't set working directory when building the preamble."); | |
254 // We proceed anyway, our lit-tests rely on results for non-existing working | |
255 // dirs. | |
256 } | |
257 | 255 |
258 assert(CI); | 256 assert(CI); |
259 // Command-line parsing sets DisableFree to true by default, but we don't want | 257 // Command-line parsing sets DisableFree to true by default, but we don't want |
260 // to leak memory in clangd. | 258 // to leak memory in clangd. |
261 CI->getFrontendOpts().DisableFree = false; | 259 CI->getFrontendOpts().DisableFree = false; |
264 | 262 |
265 // This is on-by-default in windows to allow parsing SDK headers, but it | 263 // This is on-by-default in windows to allow parsing SDK headers, but it |
266 // breaks many features. Disable it for the main-file (not preamble). | 264 // breaks many features. Disable it for the main-file (not preamble). |
267 CI->getLangOpts()->DelayedTemplateParsing = false; | 265 CI->getLangOpts()->DelayedTemplateParsing = false; |
268 | 266 |
267 std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners; | |
268 if (Inputs.FeatureModules) { | |
269 for (auto &M : *Inputs.FeatureModules) { | |
270 if (auto Listener = M.astListeners()) | |
271 ASTListeners.emplace_back(std::move(Listener)); | |
272 } | |
273 } | |
269 StoreDiags ASTDiags; | 274 StoreDiags ASTDiags; |
270 | 275 ASTDiags.setDiagCallback( |
276 [&ASTListeners](const clang::Diagnostic &D, clangd::Diag &Diag) { | |
277 llvm::for_each(ASTListeners, | |
278 [&](const auto &L) { L->sawDiagnostic(D, Diag); }); | |
279 }); | |
280 | |
281 llvm::Optional<PreamblePatch> Patch; | |
282 bool PreserveDiags = true; | |
283 if (Preamble) { | |
284 Patch = PreamblePatch::create(Filename, Inputs, *Preamble); | |
285 Patch->apply(*CI); | |
286 PreserveDiags = Patch->preserveDiagnostics(); | |
287 } | |
271 auto Clang = prepareCompilerInstance( | 288 auto Clang = prepareCompilerInstance( |
272 std::move(CI), PreamblePCH, | 289 std::move(CI), PreamblePCH, |
273 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS, | 290 llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS, |
274 ASTDiags); | 291 ASTDiags); |
275 if (!Clang) | 292 if (!Clang) |
292 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks; | 309 std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks; |
293 ast_matchers::MatchFinder CTFinder; | 310 ast_matchers::MatchFinder CTFinder; |
294 llvm::Optional<tidy::ClangTidyContext> CTContext; | 311 llvm::Optional<tidy::ClangTidyContext> CTContext; |
295 { | 312 { |
296 trace::Span Tracer("ClangTidyInit"); | 313 trace::Span Tracer("ClangTidyInit"); |
314 tidy::ClangTidyOptions ClangTidyOpts = | |
315 getTidyOptionsForFile(Inputs.ClangTidyProvider, Filename); | |
297 dlog("ClangTidy configuration for file {0}: {1}", Filename, | 316 dlog("ClangTidy configuration for file {0}: {1}", Filename, |
298 tidy::configurationAsText(Inputs.Opts.ClangTidyOpts)); | 317 tidy::configurationAsText(ClangTidyOpts)); |
299 tidy::ClangTidyCheckFactories CTFactories; | 318 tidy::ClangTidyCheckFactories CTFactories; |
300 for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) | 319 for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) |
301 E.instantiate()->addCheckFactories(CTFactories); | 320 E.instantiate()->addCheckFactories(CTFactories); |
302 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>( | 321 CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>( |
303 tidy::ClangTidyGlobalOptions(), Inputs.Opts.ClangTidyOpts)); | 322 tidy::ClangTidyGlobalOptions(), ClangTidyOpts)); |
304 CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); | 323 CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); |
305 CTContext->setASTContext(&Clang->getASTContext()); | 324 CTContext->setASTContext(&Clang->getASTContext()); |
306 CTContext->setCurrentFile(Filename); | 325 CTContext->setCurrentFile(Filename); |
307 CTChecks = CTFactories.createChecks(CTContext.getPointer()); | 326 CTChecks = CTFactories.createChecks(CTContext.getPointer()); |
308 ASTDiags.setLevelAdjuster([&CTContext](DiagnosticsEngine::Level DiagLevel, | 327 llvm::erase_if(CTChecks, [&](const auto &Check) { |
309 const clang::Diagnostic &Info) { | 328 return !Check->isLanguageVersionSupported(CTContext->getLangOpts()); |
310 if (CTContext) { | 329 }); |
330 Preprocessor *PP = &Clang->getPreprocessor(); | |
331 for (const auto &Check : CTChecks) { | |
332 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP); | |
333 Check->registerMatchers(&CTFinder); | |
334 } | |
335 | |
336 const Config &Cfg = Config::current(); | |
337 ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, | |
338 const clang::Diagnostic &Info) { | |
339 if (Cfg.Diagnostics.SuppressAll || | |
340 isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress)) | |
341 return DiagnosticsEngine::Ignored; | |
342 if (!CTChecks.empty()) { | |
311 std::string CheckName = CTContext->getCheckName(Info.getID()); | 343 std::string CheckName = CTContext->getCheckName(Info.getID()); |
312 bool IsClangTidyDiag = !CheckName.empty(); | 344 bool IsClangTidyDiag = !CheckName.empty(); |
313 if (IsClangTidyDiag) { | 345 if (IsClangTidyDiag) { |
346 if (Cfg.Diagnostics.Suppress.contains(CheckName)) | |
347 return DiagnosticsEngine::Ignored; | |
314 // Check for suppression comment. Skip the check for diagnostics not | 348 // Check for suppression comment. Skip the check for diagnostics not |
315 // in the main file, because we don't want that function to query the | 349 // in the main file, because we don't want that function to query the |
316 // source buffer for preamble files. For the same reason, we ask | 350 // source buffer for preamble files. For the same reason, we ask |
317 // shouldSuppressDiagnostic to avoid I/O. | 351 // shouldSuppressDiagnostic to avoid I/O. |
318 // We let suppression comments take precedence over warning-as-error | 352 // We let suppression comments take precedence over warning-as-error |
333 } | 367 } |
334 } | 368 } |
335 } | 369 } |
336 return DiagLevel; | 370 return DiagLevel; |
337 }); | 371 }); |
338 Preprocessor *PP = &Clang->getPreprocessor(); | |
339 for (const auto &Check : CTChecks) { | |
340 if (!Check->isLanguageVersionSupported(CTContext->getLangOpts())) | |
341 continue; | |
342 // FIXME: the PP callbacks skip the entire preamble. | |
343 // Checks that want to see #includes in the main file do not see them. | |
344 Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP); | |
345 Check->registerMatchers(&CTFinder); | |
346 } | |
347 } | 372 } |
348 | 373 |
349 // Add IncludeFixer which can recover diagnostics caused by missing includes | 374 // Add IncludeFixer which can recover diagnostics caused by missing includes |
350 // (e.g. incomplete type) and attach include insertion fixes to diagnostics. | 375 // (e.g. incomplete type) and attach include insertion fixes to diagnostics. |
351 llvm::Optional<IncludeFixer> FixIncludes; | 376 llvm::Optional<IncludeFixer> FixIncludes; |
352 auto BuildDir = VFS->getCurrentWorkingDirectory(); | 377 auto BuildDir = VFS->getCurrentWorkingDirectory(); |
353 if (Inputs.Opts.SuggestMissingIncludes && Inputs.Index && | 378 if (Inputs.Index && !BuildDir.getError()) { |
354 !BuildDir.getError()) { | 379 auto Style = getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS); |
355 auto Style = getFormatStyleForFile(Filename, Inputs.Contents, VFS.get()); | |
356 auto Inserter = std::make_shared<IncludeInserter>( | 380 auto Inserter = std::make_shared<IncludeInserter>( |
357 Filename, Inputs.Contents, Style, BuildDir.get(), | 381 Filename, Inputs.Contents, Style, BuildDir.get(), |
358 &Clang->getPreprocessor().getHeaderSearchInfo()); | 382 &Clang->getPreprocessor().getHeaderSearchInfo()); |
359 if (Preamble) { | 383 if (Preamble) { |
360 for (const auto &Inc : Preamble->Includes.MainFileIncludes) | 384 for (const auto &Inc : Preamble->Includes.MainFileIncludes) |
367 return FixIncludes->fix(DiagLevl, Info); | 391 return FixIncludes->fix(DiagLevl, Info); |
368 }); | 392 }); |
369 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder()); | 393 Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder()); |
370 } | 394 } |
371 | 395 |
372 // Copy over the includes from the preamble, then combine with the | 396 IncludeStructure Includes; |
373 // non-preamble includes below. | 397 // If we are using a preamble, copy existing includes. |
374 auto Includes = Preamble ? Preamble->Includes : IncludeStructure{}; | 398 if (Preamble) { |
375 // Replay the preamble includes so that clang-tidy checks can see them. | 399 Includes = Preamble->Includes; |
376 if (Preamble) | 400 Includes.MainFileIncludes = Patch->preambleIncludes(); |
377 ReplayPreamble::attach(Includes, *Clang, Preamble->Preamble.getBounds()); | 401 // Replay the preamble includes so that clang-tidy checks can see them. |
402 ReplayPreamble::attach(Patch->preambleIncludes(), *Clang, | |
403 Patch->modifiedBounds()); | |
404 } | |
378 // Important: collectIncludeStructure is registered *after* ReplayPreamble! | 405 // Important: collectIncludeStructure is registered *after* ReplayPreamble! |
379 // Otherwise we would collect the replayed includes again... | 406 // Otherwise we would collect the replayed includes again... |
380 // (We can't *just* use the replayed includes, they don't have Resolved path). | 407 // (We can't *just* use the replayed includes, they don't have Resolved path). |
381 Clang->getPreprocessor().addPPCallbacks( | 408 Clang->getPreprocessor().addPPCallbacks( |
382 collectIncludeStructureCallback(Clang->getSourceManager(), &Includes)); | 409 collectIncludeStructureCallback(Clang->getSourceManager(), &Includes)); |
409 | 436 |
410 // We have to consume the tokens before running clang-tidy to avoid collecting | 437 // We have to consume the tokens before running clang-tidy to avoid collecting |
411 // tokens from running the preprocessor inside the checks (only | 438 // tokens from running the preprocessor inside the checks (only |
412 // modernize-use-trailing-return-type does that today). | 439 // modernize-use-trailing-return-type does that today). |
413 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume(); | 440 syntax::TokenBuffer Tokens = std::move(CollectTokens).consume(); |
441 // Makes SelectionTree build much faster. | |
442 Tokens.indexExpandedTokens(); | |
414 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls(); | 443 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls(); |
415 // AST traversals should exclude the preamble, to avoid performance cliffs. | 444 // AST traversals should exclude the preamble, to avoid performance cliffs. |
416 Clang->getASTContext().setTraversalScope(ParsedDecls); | 445 Clang->getASTContext().setTraversalScope(ParsedDecls); |
417 { | 446 if (!CTChecks.empty()) { |
418 // Run the AST-dependent part of the clang-tidy checks. | 447 // Run the AST-dependent part of the clang-tidy checks. |
419 // (The preprocessor part ran already, via PPCallbacks). | 448 // (The preprocessor part ran already, via PPCallbacks). |
420 trace::Span Tracer("ClangTidyMatch"); | 449 trace::Span Tracer("ClangTidyMatch"); |
421 CTFinder.matchAST(Clang->getASTContext()); | 450 CTFinder.matchAST(Clang->getASTContext()); |
422 } | 451 } |
423 | 452 |
453 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF. | |
454 // However Action->EndSourceFile() would destroy the ASTContext! | |
455 // So just inform the preprocessor of EOF, while keeping everything alive. | |
456 Clang->getPreprocessor().EndSourceFile(); | |
424 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that | 457 // UnitDiagsConsumer is local, we can not store it in CompilerInstance that |
425 // has a longer lifetime. | 458 // has a longer lifetime. |
426 Clang->getDiagnostics().setClient(new IgnoreDiagnostics); | 459 Clang->getDiagnostics().setClient(new IgnoreDiagnostics); |
427 // CompilerInstance won't run this callback, do it directly. | 460 // CompilerInstance won't run this callback, do it directly. |
428 ASTDiags.EndSourceFile(); | 461 ASTDiags.EndSourceFile(); |
429 // XXX: This is messy: clang-tidy checks flush some diagnostics at EOF. | 462 |
430 // However Action->EndSourceFile() would destroy the ASTContext! | 463 llvm::Optional<std::vector<Diag>> Diags; |
431 // So just inform the preprocessor of EOF, while keeping everything alive. | 464 // FIXME: Also skip generation of diagnostics alltogether to speed up ast |
432 Clang->getPreprocessor().EndSourceFile(); | 465 // builds when we are patching a stale preamble. |
433 | 466 if (PreserveDiags) { |
434 std::vector<Diag> Diags = CompilerInvocationDiags; | 467 Diags = CompilerInvocationDiags; |
435 // Add diagnostics from the preamble, if any. | 468 // Add diagnostics from the preamble, if any. |
436 if (Preamble) | 469 if (Preamble) |
437 Diags.insert(Diags.end(), Preamble->Diags.begin(), Preamble->Diags.end()); | 470 Diags->insert(Diags->end(), Preamble->Diags.begin(), |
438 // Finally, add diagnostics coming from the AST. | 471 Preamble->Diags.end()); |
439 { | 472 // Finally, add diagnostics coming from the AST. |
440 std::vector<Diag> D = ASTDiags.take(CTContext.getPointer()); | 473 { |
441 Diags.insert(Diags.end(), D.begin(), D.end()); | 474 std::vector<Diag> D = ASTDiags.take(CTContext.getPointer()); |
475 Diags->insert(Diags->end(), D.begin(), D.end()); | |
476 } | |
442 } | 477 } |
443 return ParsedAST(Inputs.Version, std::move(Preamble), std::move(Clang), | 478 return ParsedAST(Inputs.Version, std::move(Preamble), std::move(Clang), |
444 std::move(Action), std::move(Tokens), std::move(Macros), | 479 std::move(Action), std::move(Tokens), std::move(Macros), |
445 std::move(ParsedDecls), std::move(Diags), | 480 std::move(ParsedDecls), std::move(Diags), |
446 std::move(Includes), std::move(CanonIncludes)); | 481 std::move(Includes), std::move(CanonIncludes)); |
481 return LocalTopLevelDecls; | 516 return LocalTopLevelDecls; |
482 } | 517 } |
483 | 518 |
484 const MainFileMacros &ParsedAST::getMacros() const { return Macros; } | 519 const MainFileMacros &ParsedAST::getMacros() const { return Macros; } |
485 | 520 |
486 const std::vector<Diag> &ParsedAST::getDiagnostics() const { return Diags; } | |
487 | |
488 std::size_t ParsedAST::getUsedBytes() const { | 521 std::size_t ParsedAST::getUsedBytes() const { |
489 auto &AST = getASTContext(); | 522 auto &AST = getASTContext(); |
490 // FIXME(ibiryukov): we do not account for the dynamically allocated part of | 523 // FIXME(ibiryukov): we do not account for the dynamically allocated part of |
491 // Message and Fixes inside each diagnostic. | 524 // Message and Fixes inside each diagnostic. |
492 std::size_t Total = | 525 std::size_t Total = clangd::getUsedBytes(LocalTopLevelDecls) + |
493 clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags); | 526 (Diags ? clangd::getUsedBytes(*Diags) : 0); |
494 | 527 |
495 // FIXME: the rest of the function is almost a direct copy-paste from | 528 // FIXME: the rest of the function is almost a direct copy-paste from |
496 // libclang's clang_getCXTUResourceUsage. We could share the implementation. | 529 // libclang's clang_getCXTUResourceUsage. We could share the implementation. |
497 | 530 |
498 // Sum up various allocators inside the ast context and the preprocessor. | 531 // Sum up various allocators inside the ast context and the preprocessor. |
529 std::shared_ptr<const PreambleData> Preamble, | 562 std::shared_ptr<const PreambleData> Preamble, |
530 std::unique_ptr<CompilerInstance> Clang, | 563 std::unique_ptr<CompilerInstance> Clang, |
531 std::unique_ptr<FrontendAction> Action, | 564 std::unique_ptr<FrontendAction> Action, |
532 syntax::TokenBuffer Tokens, MainFileMacros Macros, | 565 syntax::TokenBuffer Tokens, MainFileMacros Macros, |
533 std::vector<Decl *> LocalTopLevelDecls, | 566 std::vector<Decl *> LocalTopLevelDecls, |
534 std::vector<Diag> Diags, IncludeStructure Includes, | 567 llvm::Optional<std::vector<Diag>> Diags, |
535 CanonicalIncludes CanonIncludes) | 568 IncludeStructure Includes, CanonicalIncludes CanonIncludes) |
536 : Version(Version), Preamble(std::move(Preamble)), Clang(std::move(Clang)), | 569 : Version(Version), Preamble(std::move(Preamble)), Clang(std::move(Clang)), |
537 Action(std::move(Action)), Tokens(std::move(Tokens)), | 570 Action(std::move(Action)), Tokens(std::move(Tokens)), |
538 Macros(std::move(Macros)), Diags(std::move(Diags)), | 571 Macros(std::move(Macros)), Diags(std::move(Diags)), |
539 LocalTopLevelDecls(std::move(LocalTopLevelDecls)), | 572 LocalTopLevelDecls(std::move(LocalTopLevelDecls)), |
540 Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) { | 573 Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) { |
574 Resolver = std::make_unique<HeuristicResolver>(getASTContext()); | |
541 assert(this->Clang); | 575 assert(this->Clang); |
542 assert(this->Action); | 576 assert(this->Action); |
543 } | 577 } |
544 | 578 |
579 llvm::Optional<llvm::StringRef> ParsedAST::preambleVersion() const { | |
580 if (!Preamble) | |
581 return llvm::None; | |
582 return llvm::StringRef(Preamble->Version); | |
583 } | |
545 } // namespace clangd | 584 } // namespace clangd |
546 } // namespace clang | 585 } // namespace clang |