forked from OSchip/llvm-project
[clangd] Improve semantic highlighting in dependent contexts (fixes #154)
Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67901 llvm-svn: 374799
This commit is contained in:
parent
76f9869bf2
commit
37e31e629d
|
@ -37,6 +37,10 @@ bool canHighlightName(DeclarationName Name) {
|
|||
|
||||
llvm::Optional<HighlightingKind> kindForType(const Type *TP);
|
||||
llvm::Optional<HighlightingKind> kindForDecl(const NamedDecl *D) {
|
||||
if (auto *TD = dyn_cast<TemplateDecl>(D)) {
|
||||
if (auto *Templated = TD->getTemplatedDecl())
|
||||
D = Templated;
|
||||
}
|
||||
if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
|
||||
// We try to highlight typedefs as their underlying type.
|
||||
if (auto K = kindForType(TD->getUnderlyingType().getTypePtrOrNull()))
|
||||
|
@ -95,6 +99,20 @@ llvm::Optional<HighlightingKind> kindForType(const Type *TP) {
|
|||
return kindForDecl(TD);
|
||||
return llvm::None;
|
||||
}
|
||||
// Given a set of candidate declarations for an unresolved name,
|
||||
// if the declarations all have the same highlighting kind, return
|
||||
// that highlighting kind, otherwise return None.
|
||||
llvm::Optional<HighlightingKind>
|
||||
kindForCandidateDecls(llvm::iterator_range<UnresolvedSetIterator> Decls) {
|
||||
llvm::Optional<HighlightingKind> Result;
|
||||
for (NamedDecl *Decl : Decls) {
|
||||
auto Kind = kindForDecl(Decl);
|
||||
if (!Kind || (Result && Kind != Result))
|
||||
return llvm::None;
|
||||
Result = Kind;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Collects all semantic tokens in an ASTContext.
|
||||
class HighlightingTokenCollector
|
||||
|
@ -152,6 +170,26 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VisitOverloadExpr(OverloadExpr *E) {
|
||||
if (canHighlightName(E->getName()))
|
||||
addToken(E->getNameLoc(),
|
||||
kindForCandidateDecls(E->decls())
|
||||
.getValueOr(HighlightingKind::DependentName));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
|
||||
if (canHighlightName(E->getDeclName()))
|
||||
addToken(E->getLocation(), HighlightingKind::DependentName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
|
||||
if (canHighlightName(E->getMember()))
|
||||
addToken(E->getMemberLoc(), HighlightingKind::DependentName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitNamedDecl(NamedDecl *ND) {
|
||||
if (canHighlightName(ND->getDeclName()))
|
||||
addToken(ND->getLocation(), ND);
|
||||
|
@ -187,6 +225,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WalkUpFromDependentNameTypeLoc(DependentNameTypeLoc L) {
|
||||
addToken(L.getNameLoc(), HighlightingKind::DependentType);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTypeLoc(TypeLoc TL) {
|
||||
if (auto K = kindForType(TL.getTypePtr()))
|
||||
addToken(TL.getBeginLoc(), *K);
|
||||
|
@ -339,6 +382,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
|
|||
return OS << "EnumConstant";
|
||||
case HighlightingKind::Typedef:
|
||||
return OS << "Typedef";
|
||||
case HighlightingKind::DependentType:
|
||||
return OS << "DependentType";
|
||||
case HighlightingKind::DependentName:
|
||||
return OS << "DependentName";
|
||||
case HighlightingKind::Namespace:
|
||||
return OS << "Namespace";
|
||||
case HighlightingKind::TemplateParameter:
|
||||
|
@ -468,6 +515,10 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) {
|
|||
return "variable.other.enummember.cpp";
|
||||
case HighlightingKind::Typedef:
|
||||
return "entity.name.type.typedef.cpp";
|
||||
case HighlightingKind::DependentType:
|
||||
return "entity.name.type.dependent.cpp";
|
||||
case HighlightingKind::DependentName:
|
||||
return "entity.name.other.dependent.cpp";
|
||||
case HighlightingKind::Namespace:
|
||||
return "entity.name.namespace.cpp";
|
||||
case HighlightingKind::TemplateParameter:
|
||||
|
|
|
@ -37,6 +37,8 @@ enum class HighlightingKind {
|
|||
Enum,
|
||||
EnumConstant,
|
||||
Typedef,
|
||||
DependentType,
|
||||
DependentName,
|
||||
Namespace,
|
||||
TemplateParameter,
|
||||
Primitive,
|
||||
|
|
|
@ -41,6 +41,12 @@
|
|||
# CHECK-NEXT: "entity.name.type.typedef.cpp"
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: [
|
||||
# CHECK-NEXT: "entity.name.type.dependent.cpp"
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: [
|
||||
# CHECK-NEXT: "entity.name.other.dependent.cpp"
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: [
|
||||
# CHECK-NEXT: "entity.name.namespace.cpp"
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: [
|
||||
|
@ -61,7 +67,7 @@
|
|||
# CHECK-NEXT: "lines": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "line": 0,
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADAA4AAAAEAAEAAA=="
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADABAAAAAEAAEAAA=="
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: "textDocument": {
|
||||
|
@ -76,11 +82,11 @@
|
|||
# CHECK-NEXT: "lines": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "line": 0,
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADAA4AAAAEAAEAAA=="
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADABAAAAAEAAEAAA=="
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "line": 1,
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADAA4AAAAEAAEAAA=="
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADABAAAAAEAAEAAA=="
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: "textDocument": {
|
||||
|
@ -95,7 +101,7 @@
|
|||
# CHECK-NEXT: "lines": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "line": 1,
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADAA4AAAAEAAEAAA=="
|
||||
# CHECK-NEXT: "tokens": "AAAAAAADABAAAAAEAAEAAA=="
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ],
|
||||
# CHECK-NEXT: "textDocument": {
|
||||
|
|
|
@ -51,6 +51,9 @@ std::vector<HighlightingToken> getExpectedTokens(Annotations &Test) {
|
|||
{HighlightingKind::StaticField, "StaticField"},
|
||||
{HighlightingKind::Method, "Method"},
|
||||
{HighlightingKind::StaticMethod, "StaticMethod"},
|
||||
{HighlightingKind::Typedef, "Typedef"},
|
||||
{HighlightingKind::DependentType, "DependentType"},
|
||||
{HighlightingKind::DependentName, "DependentName"},
|
||||
{HighlightingKind::TemplateParameter, "TemplateParameter"},
|
||||
{HighlightingKind::Primitive, "Primitive"},
|
||||
{HighlightingKind::Macro, "Macro"}};
|
||||
|
@ -181,7 +184,7 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
|
|||
}
|
||||
template<typename $TemplateParameter[[T]]>
|
||||
struct $Class[[C]] : $Namespace[[abc]]::$Class[[A]]<$TemplateParameter[[T]]> {
|
||||
typename $TemplateParameter[[T]]::A* $Field[[D]];
|
||||
typename $TemplateParameter[[T]]::$DependentType[[A]]* $Field[[D]];
|
||||
};
|
||||
$Namespace[[abc]]::$Class[[A]]<$Primitive[[int]]> $Variable[[AA]];
|
||||
typedef $Namespace[[abc]]::$Class[[A]]<$Primitive[[int]]> $Class[[AAA]];
|
||||
|
@ -529,6 +532,58 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
|
|||
$Typedef[[Pointer]], $Typedef[[LVReference]], $Typedef[[RVReference]],
|
||||
$Typedef[[Array]], $Typedef[[MemberPointer]]);
|
||||
};
|
||||
)cpp",
|
||||
R"cpp(
|
||||
template <class $TemplateParameter[[T]]>
|
||||
$Primitive[[void]] $Function[[phase1]]($TemplateParameter[[T]]);
|
||||
template <class $TemplateParameter[[T]]>
|
||||
$Primitive[[void]] $Function[[foo]]($TemplateParameter[[T]] $Parameter[[P]]) {
|
||||
$Function[[phase1]]($Parameter[[P]]);
|
||||
$DependentName[[phase2]]($Parameter[[P]]);
|
||||
}
|
||||
)cpp",
|
||||
R"cpp(
|
||||
class $Class[[A]] {
|
||||
template <class $TemplateParameter[[T]]>
|
||||
$Primitive[[void]] $Method[[bar]]($TemplateParameter[[T]]);
|
||||
};
|
||||
|
||||
template <class $TemplateParameter[[U]]>
|
||||
$Primitive[[void]] $Function[[foo]]($TemplateParameter[[U]] $Parameter[[P]]) {
|
||||
$Class[[A]]().$Method[[bar]]($Parameter[[P]]);
|
||||
}
|
||||
)cpp",
|
||||
R"cpp(
|
||||
struct $Class[[A]] {
|
||||
template <class $TemplateParameter[[T]]>
|
||||
static $Primitive[[void]] $StaticMethod[[foo]]($TemplateParameter[[T]]);
|
||||
};
|
||||
|
||||
template <class $TemplateParameter[[T]]>
|
||||
struct $Class[[B]] {
|
||||
$Primitive[[void]] $Method[[bar]]() {
|
||||
$Class[[A]]::$StaticMethod[[foo]]($TemplateParameter[[T]]());
|
||||
}
|
||||
};
|
||||
)cpp",
|
||||
R"cpp(
|
||||
template <class $TemplateParameter[[T]]>
|
||||
$Primitive[[void]] $Function[[foo]](typename $TemplateParameter[[T]]::$DependentType[[Type]]
|
||||
= $TemplateParameter[[T]]::$DependentName[[val]]);
|
||||
)cpp",
|
||||
R"cpp(
|
||||
template <class $TemplateParameter[[T]]>
|
||||
$Primitive[[void]] $Function[[foo]]($TemplateParameter[[T]] $Parameter[[P]]) {
|
||||
$Parameter[[P]].$DependentName[[Field]];
|
||||
}
|
||||
)cpp",
|
||||
R"cpp(
|
||||
template <class $TemplateParameter[[T]]>
|
||||
class $Class[[A]] {
|
||||
$Primitive[[int]] $Method[[foo]]() {
|
||||
return $TemplateParameter[[T]]::$DependentName[[Field]];
|
||||
}
|
||||
};
|
||||
)cpp"};
|
||||
for (const auto &TestCase : TestCases) {
|
||||
checkHighlightings(TestCase);
|
||||
|
|
Loading…
Reference in New Issue