Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -90,13 +90,14 @@ void onPreambleAST(PathRef Path, ASTContext &Ctx, std::shared_ptr PP) override { - This->PreambleIdx.update(Path, &Ctx, std::move(PP)); + This->PreambleIdx.update(Path, &Ctx, std::move(PP), + /*IndexMacros=*/true); } void onMainAST(PathRef Path, ParsedAST &AST) override { - This->MainFileIdx.update(Path, &AST.getASTContext(), - AST.getPreprocessorPtr(), - AST.getLocalTopLevelDecls()); + This->MainFileIdx.update( + Path, &AST.getASTContext(), AST.getPreprocessorPtr(), + /*IndexMacros=*/false, AST.getLocalTopLevelDecls()); } }; return llvm::make_unique(this); Index: clangd/index/FileIndex.h =================================================================== --- clangd/index/FileIndex.h +++ clangd/index/FileIndex.h @@ -67,10 +67,12 @@ /// nullptr, this removes all symbols in the file. /// If \p AST is not null, \p PP cannot be null and it should be the /// preprocessor that was used to build \p AST. + /// If \p IndexMacros is true, also collect macro definitions in \p PP. /// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all /// top level decls obtained from \p AST are indexed. void update(PathRef Path, ASTContext *AST, std::shared_ptr PP, + bool IndexMacros = false, llvm::Optional> TopLevelDecls = llvm::None); private: @@ -86,8 +88,10 @@ /// If URISchemes is empty, the default schemes in SymbolCollector will be used. /// If \p TopLevelDecls is set, only these decls are indexed. Otherwise, all top /// level decls obtained from \p AST are indexed. +/// If \p IndexMacros is true, also collect macro definitions in \p PP. std::pair indexAST(ASTContext &AST, std::shared_ptr PP, + bool IndexMacros = false, llvm::Optional> TopLevelDecls = llvm::None, llvm::ArrayRef URISchemes = {}); Index: clangd/index/FileIndex.cpp =================================================================== --- clangd/index/FileIndex.cpp +++ clangd/index/FileIndex.cpp @@ -10,14 +10,17 @@ #include "FileIndex.h" #include "Logger.h" #include "SymbolCollector.h" +#include "index/Index.h" +#include "clang/Index/IndexSymbol.h" #include "clang/Index/IndexingAction.h" +#include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" namespace clang { namespace clangd { std::pair -indexAST(ASTContext &AST, std::shared_ptr PP, +indexAST(ASTContext &AST, std::shared_ptr PP, bool IndexMacros, llvm::Optional> TopLevelDecls, llvm::ArrayRef URISchemes) { SymbolCollector::Options CollectorOpts; @@ -28,6 +31,7 @@ // CommentHandler for IWYU pragma) to canonicalize includes. CollectorOpts.CollectIncludePath = false; CollectorOpts.CountReferences = false; + CollectorOpts.CollectMacro = true; if (!URISchemes.empty()) CollectorOpts.URISchemes = URISchemes; CollectorOpts.Origin = SymbolOrigin::Dynamic; @@ -54,13 +58,33 @@ SymbolCollector Collector(std::move(CollectorOpts)); Collector.setPreprocessor(PP); + Collector.initialize(AST); + + SymbolSlab Macros; + if (IndexMacros) { + // FIXME: also collect macro references? + for (const auto &M : PP->macros()) + if (MacroDirective *MD = M.second.getLatest()) + Collector.handleMacroOccurence( + M.first, MD->getMacroInfo(), + static_cast(index::SymbolRole::Definition), + MD->getLocation()); + Macros = Collector.takeSymbols(); + } + // Collector will be re-initialized. index::indexTopLevelDecls(AST, DeclsToIndex, Collector, IndexOpts); const auto &SM = AST.getSourceManager(); const auto *MainFileEntry = SM.getFileEntryForID(SM.getMainFileID()); std::string FileName = MainFileEntry ? MainFileEntry->getName() : ""; - auto Syms = Collector.takeSymbols(); + SymbolSlab::Builder Merged; + for (const auto &Macro : Macros) + Merged.insert(Macro); + for (const auto &Sym : Collector.takeSymbols()) + Merged.insert(Sym); + auto Syms = std::move(Merged).build(); + auto Refs = Collector.takeRefs(); vlog("index {0}AST for {1}: \n" " symbol slab: {2} symbols, {3} bytes\n" @@ -142,13 +166,13 @@ } void FileIndex::update(PathRef Path, ASTContext *AST, - std::shared_ptr PP, + std::shared_ptr PP, bool IndexMacros, llvm::Optional> TopLevelDecls) { if (!AST) { FSymbols.update(Path, nullptr, nullptr); } else { assert(PP); - auto Contents = indexAST(*AST, PP, TopLevelDecls, URISchemes); + auto Contents = indexAST(*AST, PP, IndexMacros, TopLevelDecls, URISchemes); FSymbols.update(Path, llvm::make_unique(std::move(Contents.first)), llvm::make_unique(std::move(Contents.second))); Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -223,12 +223,13 @@ void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) { auto Results = completions( R"cpp( - #define MACRO X - int global_var; int global_func(); + // Make sure this is not in preamble. + #define MACRO X + struct GlobalClass {}; struct ClassWithMembers { @@ -276,11 +277,12 @@ void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) { auto Results = completions( R"cpp( - #define MACRO X - int global_var; int global_func(); + // Make sure this is not in preamble. + #define MACRO X + struct GlobalClass {}; struct ClassWithMembers { @@ -430,10 +432,11 @@ TEST(CompletionTest, Kinds) { auto Results = completions( R"cpp( - #define MACRO X int variable; struct Struct {}; int function(); + // make sure MACRO is not included in preamble. + #define MACRO 10 int X = ^ )cpp", {func("indexFunction"), var("indexVariable"), cls("indexClass")}); @@ -1905,6 +1908,21 @@ UnorderedElementsAre(Named("Clangd_Macro_Test"))); } +TEST(CompletionTest, NoMacroFromPreambleIfIndexIsSet) { + auto Results = completions( + R"cpp( + #define CLANGD_PREAMBLE x + int x = 0; + #define CLANGD_MAIN x + void f() { CLANGD_^ } + )cpp", + {func("CLANGD_INDEX")}); + // Index is overriden in code completion options, so the preamble symbol is + // not seen. + EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("CLANGD_MAIN"), + Named("CLANGD_INDEX"))); +} + TEST(CompletionTest, DeprecatedResults) { std::string Body = R"cpp( void TestClangd(); Index: unittests/clangd/FileIndexTests.cpp =================================================================== --- unittests/clangd/FileIndexTests.cpp +++ unittests/clangd/FileIndexTests.cpp @@ -15,6 +15,7 @@ #include "index/FileIndex.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/PCHContainerOperations.h" +#include "clang/Index/IndexSymbol.h" #include "clang/Lex/Preprocessor.h" #include "clang/Tooling/CompilationDatabase.h" #include "gtest/gtest.h" @@ -135,7 +136,8 @@ File.HeaderFilename = (Basename + ".h").str(); File.HeaderCode = Code; auto AST = File.build(); - M.update(File.Filename, &AST.getASTContext(), AST.getPreprocessorPtr()); + M.update(File.Filename, &AST.getASTContext(), AST.getPreprocessorPtr(), + /*IndexMacros=*/true); } TEST(FileIndexTest, CustomizedURIScheme) { @@ -333,7 +335,7 @@ Test.Filename = "test.cc"; auto AST = Test.build(); Index.update(Test.Filename, &AST.getASTContext(), AST.getPreprocessorPtr(), - AST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, AST.getLocalTopLevelDecls()); // Add test2.cc TestTU Test2; Test2.HeaderCode = HeaderCode; @@ -341,7 +343,7 @@ Test2.Filename = "test2.cc"; AST = Test2.build(); Index.update(Test2.Filename, &AST.getASTContext(), AST.getPreprocessorPtr(), - AST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, AST.getLocalTopLevelDecls()); EXPECT_THAT(getRefs(Index, Foo.ID), RefsAre({AllOf(RefRange(MainCode.range("foo")), @@ -350,6 +352,21 @@ FileURI("unittest:///test2.cc"))})); } +TEST(FileIndexTest, CollectMacros) { + FileIndex M; + update(M, "f", "#define CLANGD 1"); + + FuzzyFindRequest Req; + Req.Query = ""; + bool SeenSymbol = false; + M.fuzzyFind(Req, [&](const Symbol &Sym) { + EXPECT_EQ(Sym.Name, "CLANGD"); + EXPECT_EQ(Sym.SymInfo.Kind, index::SymbolKind::Macro); + SeenSymbol = true; + }); + EXPECT_TRUE(SeenSymbol); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/IndexTests.cpp =================================================================== --- unittests/clangd/IndexTests.cpp +++ unittests/clangd/IndexTests.cpp @@ -244,7 +244,7 @@ Test.Filename = "test.cc"; auto AST = Test.build(); Dyn.update(Test.Filename, &AST.getASTContext(), AST.getPreprocessorPtr(), - AST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, AST.getLocalTopLevelDecls()); // Build static index for test.cc. Test.HeaderCode = HeaderCode; @@ -254,7 +254,7 @@ // Add stale refs for test.cc. StaticIndex.update(Test.Filename, &StaticAST.getASTContext(), StaticAST.getPreprocessorPtr(), - StaticAST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, StaticAST.getLocalTopLevelDecls()); // Add refs for test2.cc Annotations Test2Code(R"(class $Foo[[Foo]] {};)"); @@ -265,7 +265,7 @@ StaticAST = Test2.build(); StaticIndex.update(Test2.Filename, &StaticAST.getASTContext(), StaticAST.getPreprocessorPtr(), - StaticAST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, StaticAST.getLocalTopLevelDecls()); RefsRequest Request; Request.IDs = {Foo.ID}; Index: unittests/clangd/TestTU.cpp =================================================================== --- unittests/clangd/TestTU.cpp +++ unittests/clangd/TestTU.cpp @@ -51,7 +51,7 @@ std::unique_ptr TestTU::index() const { auto AST = build(); auto Content = indexAST(AST.getASTContext(), AST.getPreprocessorPtr(), - AST.getLocalTopLevelDecls()); + /*IndexMacros=*/false, AST.getLocalTopLevelDecls()); return MemIndex::build(std::move(Content.first), std::move(Content.second)); }