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,7 @@ enum class HighlightingKind { Variable = 0, Function, + Class, 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 @@ -12,6 +12,7 @@ #include "SourceCode.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TypeLoc.h" namespace clang { namespace clangd { @@ -56,6 +57,36 @@ return true; } + bool VisitTypeLoc(TypeLoc &TL) { + // The check for DependentName is so namespace qualifiers are not + // highlighted. The check for elaborated type is for not getting two entries + // whenever there is an anonymous struct. + if (TL.getTypeLocClass() == TypeLoc::TypeLocClass::DependentName || + TL.getTypeLocClass() == TypeLoc::TypeLocClass::Elaborated) { + return true; + } + + TagDecl *D = TL.getTypePtr()->getAsTagDecl(); + if (!D) + return true; + + if (const auto *RD = dyn_cast(D)) { + if (const auto *DC = RD->getDestructor()) { + auto Range = DC->getSourceRange(); + // Destructors appear as a TagTypeLoc RecordDecl. To not highlight + // destructors incorrectly the TagTypeLoc is skipped if it is wrapped + // inside the actual destructor. + if (Range.isValid() && Range.getBegin() < TL.getBeginLoc() && + TL.getBeginLoc() < Range.getEnd()) { + return true; + } + } + } + + addToken(TL.getBeginLoc(), D); + return true; + } + private: void addToken(SourceLocation Loc, const Decl *D) { if (isa(D)) { @@ -66,6 +97,10 @@ addToken(Loc, HighlightingKind::Function); return; } + if (isa(D)) { + addToken(Loc, HighlightingKind::Class); + return; + } } void addToken(SourceLocation Loc, HighlightingKind Kind) { @@ -176,6 +211,8 @@ return "entity.name.function.cpp"; case HighlightingKind::Variable: return "variable.cpp"; + case HighlightingKind::Class: + return "entity.name.type.class.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,9 @@ # 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: }, --- 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,12 @@ auto AST = TestTU::withCode(Test.code()).build(); static const std::map KindToString{ {HighlightingKind::Variable, "Variable"}, - {HighlightingKind::Function, "Function"}}; + {HighlightingKind::Function, "Function"}, + {HighlightingKind::Class, "Class"}}; 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 +50,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,11 +71,28 @@ } )cpp", R"cpp( - struct A { + namespace abc { + template + struct $Class[[A]] { + T t; + }; + } + abc::$Class[[A]] $Variable[[AA]]; + typedef abc::$Class[[A]] AAA; + enum class E {}; + enum EE {}; + struct $Class[[B]] { + E EEE; + EE EEEE; + $Class[[AAA]] AA; + }; + )cpp", + R"cpp( + struct $Class[[A]] { A(); ~A(); void $Function[[abc]](); - void operator<<(int); + void operator<<($Class[[A]]); }; )cpp"}; for (const auto &TestCase : TestCases) {