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 @@ -26,6 +26,8 @@ enum class HighlightingKind { Variable = 0, Function, + Class, + Enum, NumKinds, }; 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 @@ -35,7 +35,12 @@ } bool VisitNamedDecl(NamedDecl *ND) { - // FIXME: (De)Constructors/operator need to be highlighted some other way. + if (ND->getDeclName().getNameKind() == + DeclarationName::CXXConstructorName) { + addToken(ND->getLocation(), ND); + return true; + } + if (ND->getDeclName().getNameKind() != DeclarationName::Identifier) return true; @@ -56,8 +61,27 @@ return true; } + bool VisitTypeLoc(TypeLoc &TL) { + // This check is for not getting two entries when there are anonymous + // structs. It also makes us not highlight namespace qualifiers. For + // elaborated types the actual type is highlighted as an inner TypeLoc. + if (TL.getTypeLocClass() == TypeLoc::TypeLocClass::Elaborated) + return true; + + TagDecl *D = TL.getTypePtr()->getAsTagDecl(); + if (!D) + return true; + + addToken(TL.getBeginLoc(), D); + return true; + } + private: void addToken(SourceLocation Loc, const Decl *D) { + if (isa(D)) { + addToken(Loc, HighlightingKind::Class); + return; + } if (isa(D)) { addToken(Loc, HighlightingKind::Variable); return; @@ -66,6 +90,14 @@ addToken(Loc, HighlightingKind::Function); return; } + if (isa(D)) { + addToken(Loc, HighlightingKind::Class); + return; + } + if (isa(D)) { + addToken(Loc, HighlightingKind::Enum); + return; + } } void addToken(SourceLocation Loc, HighlightingKind Kind) { @@ -176,6 +208,10 @@ return "entity.name.function.cpp"; case HighlightingKind::Variable: return "variable.cpp"; + case HighlightingKind::Class: + return "entity.name.type.class.cpp"; + case HighlightingKind::Enum: + return "entity.name.type.enum.cpp"; case HighlightingKind::NumKinds: llvm_unreachable("must not pass NumKinds to the function"); } diff --git a/clang-tools-extra/clangd/test/semantic-highlighting.test b/clang-tools-extra/clangd/test/semantic-highlighting.test --- a/clang-tools-extra/clangd/test/semantic-highlighting.test +++ b/clang-tools-extra/clangd/test/semantic-highlighting.test @@ -10,6 +10,12 @@ # CHECK-NEXT: [ # CHECK-NEXT: "entity.name.function.cpp" # CHECK-NEXT: ] +# CHECK-NEXT: [ +# CHECK-NEXT: "entity.name.type.class.cpp" +# CHECK-NEXT: ], +# CHECK-NEXT: [ +# CHECK-NEXT: "entity.name.type.enum.cpp" +# CHECK-NEXT: ] # CHECK-NEXT: ] # CHECK-NEXT: }, --- diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -34,11 +34,13 @@ auto AST = TestTU::withCode(Test.code()).build(); static const std::map KindToString{ {HighlightingKind::Variable, "Variable"}, - {HighlightingKind::Function, "Function"}}; + {HighlightingKind::Function, "Function"}, + {HighlightingKind::Class, "Class"}, + {HighlightingKind::Enum, "Enum"}}; std::vector ExpectedTokens; for (const auto &KindString : KindToString) { - std::vector Toks = - makeHighlightingTokens(Test.ranges(KindString.second), KindString.first); + std::vector Toks = makeHighlightingTokens( + Test.ranges(KindString.second), KindString.first); ExpectedTokens.insert(ExpectedTokens.end(), Toks.begin(), Toks.end()); } @@ -49,14 +51,14 @@ TEST(SemanticHighlighting, GetsCorrectTokens) { const char *TestCases[] = { R"cpp( - struct AS { + struct $Class[[AS]] { double SomeMember; }; - struct { + $Class[[struct]] { } $Variable[[S]]; - void $Function[[foo]](int $Variable[[A]]) { + void $Function[[foo]](int $Variable[[A]], $Class[[AS]] $Variable[[As]]) { auto $Variable[[VeryLongVariableName]] = 12312; - AS $Variable[[AA]]; + $Class[[AS]] $Variable[[AA]]; auto $Variable[[L]] = $Variable[[AA]].SomeMember + $Variable[[A]]; auto $Variable[[FN]] = [ $Variable[[AA]]](int $Variable[[A]]) -> void {}; $Variable[[FN]](12312); @@ -70,12 +72,40 @@ } )cpp", R"cpp( - struct A { - A(); - ~A(); + namespace abc { + template + struct $Class[[A]] { + T t; + }; + } + template + struct $Class[[C]] : abc::A { + typename T::A* D; + }; + abc::$Class[[A]] $Variable[[AA]]; + typedef abc::$Class[[A]] AAA; + enum class $Enum[[E]] {}; + enum $Enum[[EE]] {}; + struct $Class[[B]] { + $Enum[[E]] EEE; + $Enum[[EE]] EEEE; + $Class[[AAA]] AA; + }; + void $Function[[f]] () { + $Class[[B]] $Variable[[BB]] = $Class[[B]](); + $Variable[[BB]].~$Class[[B]](); + $Class[[B]](); + } + )cpp", + R"cpp( + struct $Class[[A]] { + $Class[[A]](); + ~$Class[[A]](); void $Function[[abc]](); - void operator<<(int); + void operator<<($Class[[A]]); }; + $Class[[A]]::$Class[[A]]() {} + $Class[[A]]::~$Class[[A]]() {} )cpp"}; for (const auto &TestCase : TestCases) { checkHighlightings(TestCase);