[clangd] Add C++20 concepts support to findExplicitReferences() and semantic highlighting

Summary: Fixes https://github.com/clangd/clangd/issues/259

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D73124
This commit is contained in:
Nathan Ridge 2020-01-21 13:21:08 -05:00
parent 210f0882c9
commit c6c5dbc824
6 changed files with 53 additions and 2 deletions

View File

@ -618,6 +618,12 @@ llvm::SmallVector<ReferenceLoc, 2> refInExpr(const Expr *E) {
// FIXME: handle more complicated cases, e.g. ObjC, designated initializers.
llvm::SmallVector<ReferenceLoc, 2> Refs;
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) {
Refs.push_back(ReferenceLoc{E->getNestedNameSpecifierLoc(),
E->getConceptNameLoc(),
/*IsDecl=*/false,
{E->getNamedConcept()}});
}
void VisitDeclRefExpr(const DeclRefExpr *E) {
Refs.push_back(ReferenceLoc{E->getQualifierLoc(),
E->getNameInfo().getLoc(),

View File

@ -98,6 +98,8 @@ llvm::Optional<HighlightingKind> kindForDecl(const NamedDecl *D) {
if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
isa<NonTypeTemplateParmDecl>(D))
return HighlightingKind::TemplateParameter;
if (isa<ConceptDecl>(D))
return HighlightingKind::Concept;
return llvm::None;
}
llvm::Optional<HighlightingKind> kindForType(const Type *TP) {
@ -392,6 +394,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
return OS << "Namespace";
case HighlightingKind::TemplateParameter:
return OS << "TemplateParameter";
case HighlightingKind::Concept:
return OS << "Concept";
case HighlightingKind::Primitive:
return OS << "Primitive";
case HighlightingKind::Macro:
@ -534,6 +538,8 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) {
return "entity.name.namespace.cpp";
case HighlightingKind::TemplateParameter:
return "entity.name.type.template.cpp";
case HighlightingKind::Concept:
return "entity.name.type.concept.cpp";
case HighlightingKind::Primitive:
return "storage.type.primitive.cpp";
case HighlightingKind::Macro:

View File

@ -41,6 +41,7 @@ enum class HighlightingKind {
DependentName,
Namespace,
TemplateParameter,
Concept,
Primitive,
Macro,

View File

@ -53,6 +53,9 @@
# CHECK-NEXT: "entity.name.type.template.cpp"
# CHECK-NEXT: ],
# CHECK-NEXT: [
# CHECK-NEXT: "entity.name.type.concept.cpp"
# CHECK-NEXT: ],
# CHECK-NEXT: [
# CHECK-NEXT: "storage.type.primitive.cpp"
# CHECK-NEXT: ],
# CHECK-NEXT: [

View File

@ -571,7 +571,7 @@ protected:
// FIXME: Auto-completion in a template requires disabling delayed template
// parsing.
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
TU.ExtraArgs.push_back("-std=c++17");
TU.ExtraArgs.push_back("-std=c++2a");
auto AST = TU.build();
for (auto &D : AST.getDiagnostics()) {
@ -1091,7 +1091,27 @@ TEST_F(FindExplicitReferencesTest, All) {
"0: targets = {foo::T}, decl\n"
"1: targets = {foo::V}, decl\n"
"2: targets = {vector}\n"
"3: targets = {foo::T}\n"}};
"3: targets = {foo::T}\n"},
// Concept
{
R"cpp(
template <typename T>
concept Drawable = requires (T t) { t.draw(); };
namespace foo {
template <typename $0^T> requires $1^Drawable<$2^T>
void $3^bar($4^T $5^t) {
$6^t.draw();
}
}
)cpp",
"0: targets = {T}, decl\n"
"1: targets = {Drawable}\n"
"2: targets = {T}\n"
"3: targets = {foo::bar}, decl\n"
"4: targets = {T}\n"
"5: targets = {t}, decl\n"
"6: targets = {t}\n"}};
for (const auto &C : Cases) {
llvm::StringRef ExpectedCode = C.first;

View File

@ -55,6 +55,7 @@ std::vector<HighlightingToken> getExpectedTokens(Annotations &Test) {
{HighlightingKind::DependentType, "DependentType"},
{HighlightingKind::DependentName, "DependentName"},
{HighlightingKind::TemplateParameter, "TemplateParameter"},
{HighlightingKind::Concept, "Concept"},
{HighlightingKind::Primitive, "Primitive"},
{HighlightingKind::Macro, "Macro"}};
std::vector<HighlightingToken> ExpectedTokens;
@ -108,6 +109,7 @@ void checkHighlightings(llvm::StringRef Code,
// FIXME: Auto-completion in a template requires disabling delayed template
// parsing.
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
TU.ExtraArgs.push_back("-std=c++2a");
for (auto File : AdditionalFiles)
TU.AdditionalFiles.insert({File.first, File.second});
@ -649,6 +651,19 @@ sizeof...($TemplateParameter[[Elements]]);
static const int $StaticField[[Value]] = $TemplateParameter[[T]]
::$DependentType[[Resolver]]::$DependentName[[Value]];
};
)cpp",
// Concepts
R"cpp(
template <typename $TemplateParameter[[T]]>
concept $Concept[[Fooable]] =
requires($TemplateParameter[[T]] $Parameter[[F]]) {
$Parameter[[F]].$DependentName[[foo]]();
};
template <typename $TemplateParameter[[T]]>
requires $Concept[[Fooable]]<$TemplateParameter[[T]]>
void $Function[[bar]]($TemplateParameter[[T]] $Parameter[[F]]) {
$Parameter[[F]].$DependentName[[foo]]();
}
)cpp"};
for (const auto &TestCase : TestCases) {
checkHighlightings(TestCase);