diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -460,6 +460,20 @@ Transp.notify(Method, std::move(Params)); } +static std::vector semanticTokenModifiers() { + std::vector Result; + Result.push_back("0"); + Result.push_back("1"); + Result.push_back("2"); + Result.push_back("3"); + Result.push_back("4"); + Result.push_back("local"); + Result.push_back("static"); + Result.push_back("member"); + // Result.push_back("const"); + return Result; +} + static std::vector semanticTokenTypes() { std::vector Types; for (unsigned I = 0; I <= static_cast(HighlightingKind::LastKind); @@ -600,8 +614,9 @@ {"full", llvm::json::Object{{"delta", true}}}, {"range", false}, {"legend", - llvm::json::Object{{"tokenTypes", semanticTokenTypes()}, - {"tokenModifiers", llvm::json::Array()}}}, + llvm::json::Object{ + {"tokenTypes", semanticTokenTypes()}, + {"tokenModifiers", semanticTokenModifiers()}}}, }}, {"signatureHelpProvider", llvm::json::Object{ diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h --- a/clang-tools-extra/clangd/SemanticHighlighting.h +++ b/clang-tools-extra/clangd/SemanticHighlighting.h @@ -70,6 +70,7 @@ struct HighlightingToken { HighlightingKind Kind; Range R; + unsigned char Index = 0; }; bool operator==(const HighlightingToken &L, const HighlightingToken &R); 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 @@ -131,6 +131,53 @@ return Result; } +unsigned char idxForType(const Type *TP); +unsigned char idxForDecl(const NamedDecl *D) { + if (auto *USD = dyn_cast(D)) { + if (auto *Target = USD->getTargetDecl()) + D = Target; + } + if (auto *TD = dyn_cast(D)) { + if (auto *Templated = TD->getTemplatedDecl()) + D = Templated; + } + if (auto *TD = dyn_cast(D)) { + // We try to highlight typedefs as their underlying type. + if (auto K = idxForType(TD->getUnderlyingType().getTypePtrOrNull())) + return K; + // And fallback to a generic kind if this fails. + return 0; + } + + if (auto ID = getSymbolID(D)) { + return hash_value(*ID) % 255; + } + + return D->getGlobalID() % 255; +} + +unsigned char idxForType(const Type *TP) { + if (!TP) + return 0; + if (TP->isBuiltinType()) // Builtins are special, they do not have decls. + return 0; + if (auto *TD = dyn_cast(TP)) + return idxForDecl(TD->getDecl()); + if (auto *TD = TP->getAsTagDecl()) + return idxForDecl(TD); + return 0; +} + +unsigned char idxForReference(const ReferenceLoc &R) { + unsigned char Result = 0; + for (const NamedDecl *Decl : R.Targets) { + if (!canHighlightName(Decl->getDeclName())) + continue; + Result = idxForDecl(Decl); + } + return Result; +} + // For a macro usage `DUMP(foo)`, we want: // - DUMP --> "macro" // - foo --> "variable". @@ -184,7 +231,8 @@ void addToken(HighlightingToken T) { Tokens.push_back(T); } - void addToken(SourceLocation Loc, HighlightingKind Kind) { + void addToken(SourceLocation Loc, HighlightingKind Kind, + unsigned char idx = 0) { Loc = getHighlightableSpellingToken(Loc, SourceMgr); if (Loc.isInvalid()) return; @@ -193,7 +241,7 @@ auto Range = halfOpenToRange(SourceMgr, Tok->range(SourceMgr).toCharRange(SourceMgr)); - Tokens.push_back(HighlightingToken{Kind, std::move(Range)}); + Tokens.push_back(HighlightingToken{Kind, std::move(Range), idx}); } std::vector collect(ParsedAST &AST) && { @@ -284,7 +332,7 @@ bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) { if (auto K = kindForType(L.getTypePtr())) - H.addToken(L.getBeginLoc(), *K); + H.addToken(L.getBeginLoc(), *K, idxForType(L.getTypePtr())); return true; } @@ -293,7 +341,8 @@ if (!AT) return true; if (auto K = kindForType(AT->getDeducedType().getTypePtrOrNull())) - H.addToken(D->getTypeSpecStartLoc(), *K); + H.addToken(D->getTypeSpecStartLoc(), *K, + idxForType(AT->getDeducedType().getTypePtrOrNull())); return true; } @@ -388,12 +437,14 @@ // Highlight all decls and references coming from the AST. findExplicitReferences(C, [&](ReferenceLoc R) { if (auto Kind = kindForReference(R)) - Builder.addToken(R.NameLoc, *Kind); + Builder.addToken(R.NameLoc, *Kind, idxForReference(R)); }); // Add highlightings for macro references. for (const auto &SIDToRefs : AST.getMacros().MacroRefs) { for (const auto &M : SIDToRefs.second) - Builder.addToken({HighlightingKind::Macro, M}); + Builder.addToken( + {HighlightingKind::Macro, M, + static_cast(hash_value(SIDToRefs.first) % 255)}); } for (const auto &M : AST.getMacros().UnknownMacros) Builder.addToken({HighlightingKind::Macro, M}); @@ -540,6 +591,19 @@ assert(Tok.R.end.line == Tok.R.start.line); Out.length = Tok.R.end.character - Tok.R.start.character; Out.tokenType = static_cast(Tok.Kind); + Out.tokenModifiers = static_cast(1UL << (Tok.Index % 5)); + + if (Tok.Kind == HighlightingKind::LocalVariable) { + Out.tokenModifiers |= 1 << 5; + } else if (Tok.Kind == HighlightingKind::StaticField) { + Out.tokenModifiers |= 1 << 6; + } else if (Tok.Kind == HighlightingKind::StaticMethod) { + Out.tokenModifiers |= 1 << 6; + } else if (Tok.Kind == HighlightingKind::Method) { + Out.tokenModifiers |= 1 << 7; + } else if (Tok.Kind == HighlightingKind::Field) { + Out.tokenModifiers |= 1 << 7; + } Last = &Tok; } @@ -549,19 +613,16 @@ switch (Kind) { case HighlightingKind::Variable: case HighlightingKind::LocalVariable: + case HighlightingKind::Field: case HighlightingKind::StaticField: return "variable"; case HighlightingKind::Parameter: + // should this be a modifier on variable? return "parameter"; - case HighlightingKind::Function: - return "function"; case HighlightingKind::Method: - return "member"; case HighlightingKind::StaticMethod: - // FIXME: better function/member with static modifier? + case HighlightingKind::Function: return "function"; - case HighlightingKind::Field: - return "member"; case HighlightingKind::Class: return "class"; case HighlightingKind::Enum: @@ -584,8 +645,11 @@ return "type"; case HighlightingKind::Macro: return "macro"; + // would be cool to change this into "function" or "variable" + // with "preprocessor" modifier case HighlightingKind::InactiveCode: return "comment"; + // add "preprocessor" modifier } llvm_unreachable("unhandled HighlightingKind"); }