Author: jvikstrom Date: Fri Aug 30 02:33:27 2019 New Revision: 370452 URL: http://llvm.org/viewvc/llvm-project?rev=370452&view=rev Log: [clangd] Collecting main file macro expansion locations in ParsedAST.
Summary: TokenBuffer does not collect macro expansions inside macro arguments which is needed for semantic higlighting. Therefore collects macro expansions in the main file in a PPCallback when building the ParsedAST instead. Reviewers: hokein, ilya-biryukov Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66928 Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp clang-tools-extra/trunk/clangd/ClangdUnit.h clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=370452&r1=370451&r2=370452&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original) +++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Fri Aug 30 02:33:27 2019 @@ -22,6 +22,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Frontend/CompilerInstance.h" @@ -32,6 +33,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Sema.h" @@ -103,6 +105,28 @@ private: std::vector<Decl *> TopLevelDecls; }; +// CollectMainFileMacroExpansions and CollectMainFileMacros are two different +// classes as CollectMainFileMacroExpansions is only used when building the AST +// for the main file. CollectMainFileMacros is only used when building the +// preamble. +class CollectMainFileMacroExpansions : public PPCallbacks { + const SourceManager &SM; + std::vector<SourceLocation> &MainFileMacroLocs; + +public: + CollectMainFileMacroExpansions(const SourceManager &SM, + std::vector<SourceLocation> &MainFileMacroLocs) + : SM(SM), MainFileMacroLocs(MainFileMacroLocs) {} + + virtual void MacroExpands(const Token &MacroNameTok, + const MacroDefinition &MD, SourceRange Range, + const MacroArgs *Args) { + SourceLocation L = MacroNameTok.getLocation(); + if (!L.isMacroID() && isInsideMainFile(L, SM)) + MainFileMacroLocs.push_back(L); + } +}; + class CollectMainFileMacros : public PPCallbacks { public: explicit CollectMainFileMacros(const SourceManager &SM, @@ -417,6 +441,11 @@ ParsedAST::build(std::unique_ptr<clang:: // (We can't *just* use the replayed includes, they don't have Resolved path). Clang->getPreprocessor().addPPCallbacks( collectIncludeStructureCallback(Clang->getSourceManager(), &Includes)); + // Collect the macro expansions in the main file. + std::vector<SourceLocation> MainFileMacroExpLocs; + Clang->getPreprocessor().addPPCallbacks( + std::make_unique<CollectMainFileMacroExpansions>( + Clang->getSourceManager(), MainFileMacroExpLocs)); // Copy over the includes from the preamble, then combine with the // non-preamble includes below. @@ -470,7 +499,8 @@ ParsedAST::build(std::unique_ptr<clang:: Diags.insert(Diags.end(), D.begin(), D.end()); } return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action), - std::move(Tokens), std::move(ParsedDecls), std::move(Diags), + std::move(Tokens), std::move(MainFileMacroExpLocs), + std::move(ParsedDecls), std::move(Diags), std::move(Includes), std::move(CanonIncludes)); } @@ -509,6 +539,10 @@ llvm::ArrayRef<Decl *> ParsedAST::getLoc return LocalTopLevelDecls; } +llvm::ArrayRef<SourceLocation> ParsedAST::getMainFileExpansions() const { + return MainFileMacroExpLocs; +} + const std::vector<Diag> &ParsedAST::getDiagnostics() const { return Diags; } std::size_t ParsedAST::getUsedBytes() const { @@ -565,11 +599,13 @@ ParsedAST::ParsedAST(std::shared_ptr<con std::unique_ptr<CompilerInstance> Clang, std::unique_ptr<FrontendAction> Action, syntax::TokenBuffer Tokens, + std::vector<SourceLocation> MainFileMacroExpLocs, std::vector<Decl *> LocalTopLevelDecls, std::vector<Diag> Diags, IncludeStructure Includes, CanonicalIncludes CanonIncludes) : Preamble(std::move(Preamble)), Clang(std::move(Clang)), Action(std::move(Action)), Tokens(std::move(Tokens)), + MainFileMacroExpLocs(std::move(MainFileMacroExpLocs)), Diags(std::move(Diags)), LocalTopLevelDecls(std::move(LocalTopLevelDecls)), Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) { Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=370452&r1=370451&r2=370452&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/ClangdUnit.h (original) +++ clang-tools-extra/trunk/clangd/ClangdUnit.h Fri Aug 30 02:33:27 2019 @@ -118,6 +118,9 @@ public: const IncludeStructure &getIncludeStructure() const; const CanonicalIncludes &getCanonicalIncludes() const; + /// The start locations of all macro expansions spelled inside the main file. + /// Does not include expansions from inside other macro expansions. + llvm::ArrayRef<SourceLocation> getMainFileExpansions() const; /// Tokens recorded while parsing the main file. /// (!) does not have tokens from the preamble. const syntax::TokenBuffer &getTokens() const { return Tokens; } @@ -126,6 +129,7 @@ private: ParsedAST(std::shared_ptr<const PreambleData> Preamble, std::unique_ptr<CompilerInstance> Clang, std::unique_ptr<FrontendAction> Action, syntax::TokenBuffer Tokens, + std::vector<SourceLocation> MainFileMacroExpLocs, std::vector<Decl *> LocalTopLevelDecls, std::vector<Diag> Diags, IncludeStructure Includes, CanonicalIncludes CanonIncludes); @@ -145,6 +149,9 @@ private: /// - Does not have spelled or expanded tokens for files from preamble. syntax::TokenBuffer Tokens; + /// The start locations of all macro expansions spelled inside the main file. + /// Does not include expansions from inside other macro expansions. + std::vector<SourceLocation> MainFileMacroExpLocs; // Data, stored after parsing. std::vector<Diag> Diags; // Top-level decls inside the current file. Not that this does not include Modified: clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp?rev=370452&r1=370451&r2=370452&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp (original) +++ clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp Fri Aug 30 02:33:27 2019 @@ -262,6 +262,56 @@ TEST(ClangdUnitTest, CanBuildInvocationW EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr); } +TEST(ClangdUnitTest, CollectsMainFileMacroExpansions) { + Annotations TestCase(R"cpp( + #define MACRO_ARGS(X, Y) X Y + ^ID(int A); + // Macro arguments included. + ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), A), ^ID(= 2)); + + // Macro names inside other macros not included. + #define FOO BAR + #define BAR 1 + int A = ^FOO; + + // Macros from token concatenations not included. + #define CONCAT(X) X##A() + #define PREPEND(X) MACRO##X() + #define MACROA() 123 + int B = ^CONCAT(MACRO); + int D = ^PREPEND(A) + + // Macros included not from preamble not included. + #include "foo.inc" + + #define assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); } + + void test() { + // Includes macro expansions in arguments that are expressions + ^assert(0 <= ^BAR); + } + )cpp"); + auto TU = TestTU::withCode(TestCase.code()); + TU.HeaderCode = R"cpp( + #define ID(X) X + #define MACRO_EXP(X) ID(X) + MACRO_EXP(int B); + )cpp"; + TU.AdditionalFiles["foo.inc"] = R"cpp( + int C = ID(1); + #define DEF 1 + int D = DEF; + )cpp"; + ParsedAST AST = TU.build(); + const std::vector<SourceLocation> &MacroExpansionLocations = + AST.getMainFileExpansions(); + std::vector<Position> MacroExpansionPositions; + for (const auto &L : MacroExpansionLocations) + MacroExpansionPositions.push_back( + sourceLocToPosition(AST.getSourceManager(), L)); + EXPECT_EQ(MacroExpansionPositions, TestCase.points()); +} + } // namespace } // namespace clangd } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits