[clangd] Added highlighting for class and enum types.
Summary: Added highlighting for non-builtin types using VisitTypeLoc. Ignoring namespace qualifiers as for now. Reviewers: hokein, sammccall, ilya-biryukov Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64257 llvm-svn: 365602
This commit is contained in:
parent
4e09ef030e
commit
eff868fdef
|
@ -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 @@ public:
|
|||
}
|
||||
|
||||
bool VisitNamedDecl(NamedDecl *ND) {
|
||||
// FIXME: (De)Constructors/operator need to be highlighted some other way.
|
||||
// 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().getNameKind() != DeclarationName::Identifier)
|
||||
return true;
|
||||
|
||||
if (ND->getDeclName().isEmpty())
|
||||
// Don't add symbols that don't have any length.
|
||||
return true;
|
||||
addToken(ND->getLocation(), ND);
|
||||
return true;
|
||||
}
|
||||
|
@ -56,8 +63,39 @@ public:
|
|||
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<RecordDecl>(D)) {
|
||||
addToken(Loc, HighlightingKind::Class);
|
||||
return;
|
||||
}
|
||||
if (isa<CXXConstructorDecl>(D)) {
|
||||
addToken(Loc, HighlightingKind::Class);
|
||||
return;
|
||||
}
|
||||
if (isa<EnumDecl>(D)) {
|
||||
addToken(Loc, HighlightingKind::Enum);
|
||||
return;
|
||||
}
|
||||
if (isa<VarDecl>(D)) {
|
||||
addToken(Loc, HighlightingKind::Variable);
|
||||
return;
|
||||
|
@ -176,6 +214,10 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) {
|
|||
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");
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace clangd {
|
|||
enum class HighlightingKind {
|
||||
Variable = 0,
|
||||
Function,
|
||||
Class,
|
||||
Enum,
|
||||
|
||||
NumKinds,
|
||||
};
|
||||
|
|
|
@ -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: },
|
||||
---
|
||||
|
|
|
@ -34,11 +34,13 @@ void checkHighlightings(llvm::StringRef Code) {
|
|||
auto AST = TestTU::withCode(Test.code()).build();
|
||||
static const std::map<HighlightingKind, std::string> KindToString{
|
||||
{HighlightingKind::Variable, "Variable"},
|
||||
{HighlightingKind::Function, "Function"}};
|
||||
{HighlightingKind::Function, "Function"},
|
||||
{HighlightingKind::Class, "Class"},
|
||||
{HighlightingKind::Enum, "Enum"}};
|
||||
std::vector<HighlightingToken> ExpectedTokens;
|
||||
for (const auto &KindString : KindToString) {
|
||||
std::vector<HighlightingToken> Toks =
|
||||
makeHighlightingTokens(Test.ranges(KindString.second), KindString.first);
|
||||
std::vector<HighlightingToken> Toks = makeHighlightingTokens(
|
||||
Test.ranges(KindString.second), KindString.first);
|
||||
ExpectedTokens.insert(ExpectedTokens.end(), Toks.begin(), Toks.end());
|
||||
}
|
||||
|
||||
|
@ -49,14 +51,14 @@ void checkHighlightings(llvm::StringRef Code) {
|
|||
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 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
|
|||
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<typename T>
|
||||
struct $Class[[A]] {
|
||||
T t;
|
||||
};
|
||||
}
|
||||
template<typename T>
|
||||
struct $Class[[C]] : abc::A<T> {
|
||||
typename T::A* D;
|
||||
};
|
||||
abc::$Class[[A]]<int> $Variable[[AA]];
|
||||
typedef abc::$Class[[A]]<int> 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) {
|
||||
|
|
Loading…
Reference in New Issue