Index: clang-tools-extra/trunk/clangd/SemanticHighlighting.h =================================================================== --- clang-tools-extra/trunk/clangd/SemanticHighlighting.h +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.h @@ -26,6 +26,8 @@ enum class HighlightingKind { Variable = 0, Function, + Class, + Enum, NumKinds, }; Index: clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp =================================================================== --- clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp +++ clang-tools-extra/trunk/clangd/SemanticHighlighting.cpp @@ -11,6 +11,8 @@ #include "Protocol.h" #include "SourceCode.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/RecursiveASTVisitor.h" namespace clang { @@ -35,13 +37,18 @@ } bool VisitNamedDecl(NamedDecl *ND) { - // FIXME: (De)Constructors/operator need to be highlighted some other way. - if (ND->getDeclName().getNameKind() != DeclarationName::Identifier) + // Constructors' TypeLoc has a TypePtr that is a FunctionProtoType. It has + // no tag decl and therefore constructors must be gotten as NamedDecls + // instead. + if (ND->getDeclName().getNameKind() == + DeclarationName::CXXConstructorName) { + addToken(ND->getLocation(), ND); return true; + } - if (ND->getDeclName().isEmpty()) - // Don't add symbols that don't have any length. + if (ND->getDeclName().getNameKind() != DeclarationName::Identifier) return true; + addToken(ND->getLocation(), ND); return true; } @@ -56,8 +63,39 @@ 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; + + if (const Type *TP = TL.getTypePtr()) + if (const TagDecl *TD = TP->getAsTagDecl()) + addToken(TL.getBeginLoc(), TD); + return true; + } + private: - void addToken(SourceLocation Loc, const Decl *D) { + void addToken(SourceLocation Loc, const NamedDecl *D) { + if (D->getDeclName().isIdentifier() && D->getName().empty()) + // Don't add symbols that don't have any length. + return; + // We highlight class decls, constructor decls and destructor decls as + // `Class` type. The destructor decls are handled in `VisitTypeLoc` (we will + // visit a TypeLoc where the underlying Type is a CXXRecordDecl). + if (isa(D)) { + addToken(Loc, HighlightingKind::Class); + return; + } + if (isa(D)) { + addToken(Loc, HighlightingKind::Class); + return; + } + if (isa(D)) { + addToken(Loc, HighlightingKind::Enum); + return; + } if (isa(D)) { addToken(Loc, HighlightingKind::Variable); return; @@ -176,6 +214,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"); } Index: clang-tools-extra/trunk/clangd/test/semantic-highlighting.test =================================================================== --- clang-tools-extra/trunk/clangd/test/semantic-highlighting.test +++ clang-tools-extra/trunk/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: }, --- Index: clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/SemanticHighlightingTests.cpp +++ clang-tools-extra/trunk/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 { } $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); @@ -68,13 +70,43 @@ void $Function[[foo]]() { auto $Variable[[Bou]] = $Function[[Gah]]; } + struct $Class[[A]] { + void $Function[[abc]](); + }; )cpp", R"cpp( - struct A { - A(); - ~A(); - void $Function[[abc]](); - void operator<<(int); + 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; + struct $Class[[B]] { + $Class[[B]](); + ~$Class[[B]](); + void operator<<($Class[[B]]); + $Class[[AAA]] AA; + }; + $Class[[B]]::$Class[[B]]() {} + $Class[[B]]::~$Class[[B]]() {} + void $Function[[f]] () { + $Class[[B]] $Variable[[BB]] = $Class[[B]](); + $Variable[[BB]].~$Class[[B]](); + $Class[[B]](); + } + )cpp", + R"cpp( + enum class $Enum[[E]] {}; + enum $Enum[[EE]] {}; + struct $Class[[A]] { + $Enum[[E]] EEE; + $Enum[[EE]] EEEE; }; )cpp"}; for (const auto &TestCase : TestCases) {