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,11 @@ } 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 +60,25 @@ 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 +87,15 @@ 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 +206,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);