diff options
Diffstat (limited to 'clang-tools-extra/clangd/CodeComplete.cpp')
| -rw-r--r-- | clang-tools-extra/clangd/CodeComplete.cpp | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index f8a4a4598f8..77e0a8d5e78 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -44,6 +44,8 @@ #include "clang/Format/Format.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/DeclSpec.h" @@ -1017,6 +1019,24 @@ struct SemaCompleteInput { llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS; }; +void loadMainFilePreambleMacros(const Preprocessor &PP, + const PreambleData &Preamble) { + // The ExternalPreprocessorSource has our macros, if we know where to look. + // We can read all the macros using PreambleMacros->ReadDefinedMacros(), + // but this includes transitively included files, so may deserialize a lot. + ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource(); + // As we have the names of the macros, we can look up their IdentifierInfo + // and then use this to load just the macros we want. + IdentifierInfoLookup *PreambleIdentifiers = + PP.getIdentifierTable().getExternalIdentifierLookup(); + if (!PreambleIdentifiers || !PreambleMacros) + return; + for (const auto& MacroName : Preamble.MainFileMacros) + if (auto *II = PreambleIdentifiers->get(MacroName)) + if (II->isOutOfDate()) + PreambleMacros->updateOutOfDateIdentifier(*II); +} + // Invokes Sema code completion on a file. // If \p Includes is set, it will be updated based on the compiler invocation. bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, @@ -1058,9 +1078,9 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, // However, if we're completing *inside* the preamble section of the draft, // overriding the preamble will break sema completion. Fortunately we can just // skip all includes in this case; these completions are really simple. - bool CompletingInPreamble = - ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0).Size > - Input.Offset; + PreambleBounds PreambleRegion = + ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0); + bool CompletingInPreamble = PreambleRegion.Size > Input.Offset; // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise // the remapped buffers do not get freed. IgnoreDiagnostics DummyDiagsConsumer; @@ -1078,6 +1098,14 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, Input.FileName); return false; } + // Macros can be defined within the preamble region of the main file. + // They don't fall nicely into our index/Sema dichotomy: + // - they're not indexed for completion (they're not available across files) + // - but Sema code complete won't see them: as part of the preamble, they're + // deserialized only when mentioned. + // Force them to be deserialized so SemaCodeComplete sees them. + if (Input.Preamble) + loadMainFilePreambleMacros(Clang->getPreprocessor(), *Input.Preamble); if (Includes) Clang->getPreprocessor().addPPCallbacks( collectIncludeStructureCallback(Clang->getSourceManager(), Includes)); |

