diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -23,6 +23,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -130,37 +131,30 @@ /// Consumes source locations and maps them to text ranges for highlightings. class HighlightingsBuilder { public: - HighlightingsBuilder(const SourceManager &SourceMgr, - const LangOptions &LangOpts) - : SourceMgr(SourceMgr), LangOpts(LangOpts) {} + HighlightingsBuilder(ParsedAST &AST) + : TB(AST.getTokens()), SourceMgr(AST.getSourceManager()), + LangOpts(AST.getLangOpts()) {} void addToken(HighlightingToken T) { Tokens.push_back(T); } void addToken(SourceLocation Loc, HighlightingKind Kind) { - if (Loc.isInvalid()) + // This enables highlighting tokens coming from macro expansions, e.g.: + // #define MACRO SOME_NAME + // int MACRO; + // ~~~~~ -> this will get highlighted as a macro token. + // As `de-conflicting` logic inside `collect` would drop these otherwise. + // There were tests specifically checking for that, not sure if it is needed + // though. + if (!SourceMgr.isMacroArgExpansion(Loc)) return; - if (Loc.isMacroID()) { - // Only intereseted in highlighting arguments in macros (DEF_X(arg)). - if (!SourceMgr.isMacroArgExpansion(Loc)) - return; - Loc = SourceMgr.getSpellingLoc(Loc); - } - - // Non top level decls that are included from a header are not filtered by - // topLevelDecls. (example: method declarations being included from - // another file for a class from another file). - // There are also cases with macros where the spelling loc will not be in - // the main file and the highlighting would be incorrect. - if (!isInsideMainFile(Loc, SourceMgr)) + auto Toks = TB.spelledForExpanded(TB.expandedTokens(Loc)); + if (!Toks || Toks->empty() || + !isInsideMainFile(Toks->front().location(), SourceMgr)) return; - auto Range = getTokenRange(SourceMgr, LangOpts, Loc); - if (!Range) { - // R should always have a value, if it doesn't something is very wrong. - elog("Tried to add semantic token with an invalid range"); - return; - } - Tokens.push_back(HighlightingToken{Kind, *Range}); + auto Range = halfOpenToRange( + SourceMgr, Toks->front().range(SourceMgr).toCharRange(SourceMgr)); + Tokens.push_back(HighlightingToken{Kind, std::move(Range)}); } std::vector collect(ParsedAST &AST) && { @@ -210,6 +204,7 @@ } private: + const syntax::TokenBuffer &TB; const SourceManager &SourceMgr; const LangOptions &LangOpts; std::vector Tokens; @@ -341,7 +336,7 @@ std::vector getSemanticHighlightings(ParsedAST &AST) { auto &C = AST.getASTContext(); // Add highlightings for AST nodes. - HighlightingsBuilder Builder(AST.getSourceManager(), C.getLangOpts()); + HighlightingsBuilder Builder(AST); // Highlight 'decltype' and 'auto' as their underlying types. CollectExtraHighlightings(Builder).TraverseAST(C); // Highlight all decls and references coming from the AST.