diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -606,6 +606,12 @@ // FIXME: handle more complicated cases, e.g. ObjC, designated initializers. llvm::SmallVector 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(), 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 @@ -41,6 +41,7 @@ DependentName, Namespace, TemplateParameter, + Concept, Primitive, Macro, 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 @@ -98,6 +98,8 @@ if (isa(D) || isa(D) || isa(D)) return HighlightingKind::TemplateParameter; + if (isa(D)) + return HighlightingKind::Concept; return llvm::None; } llvm::Optional kindForType(const Type *TP) { @@ -392,6 +394,8 @@ 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 @@ 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: 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 @@ -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: [ diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -563,7 +563,7 @@ // 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()) { @@ -1047,7 +1047,31 @@ } )cpp", "0: targets = {Test}\n" - "1: targets = {a}, decl\n"}}; + "1: targets = {a}, decl\n"}, + // Concept + { + R"cpp( + template + concept Drawable = requires (T t) { t.draw(); }; + + namespace foo { + template requires $1^Drawable<$2^T> + void $3^$4^bar($5^T $6^t) { + $7^t.draw(); + } + } + )cpp", + "0: targets = {T}, decl\n" + "1: targets = {Drawable}\n" + "2: targets = {T}\n" + // FIXME: avoid the 2 duplicated foo::bar references below, the first + // one comes from FunctionTemplateDecl; the second comes from the + // underlying FunctionDecl. + "3: targets = {foo::bar}, decl\n" + "4: targets = {foo::bar}, decl\n" + "5: targets = {T}\n" + "6: targets = {t}, decl\n" + "7: targets = {t}\n"}}; for (const auto &C : Cases) { llvm::StringRef ExpectedCode = C.first; 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 @@ -55,6 +55,7 @@ {HighlightingKind::DependentType, "DependentType"}, {HighlightingKind::DependentName, "DependentName"}, {HighlightingKind::TemplateParameter, "TemplateParameter"}, + {HighlightingKind::Concept, "Concept"}, {HighlightingKind::Primitive, "Primitive"}, {HighlightingKind::Macro, "Macro"}}; std::vector ExpectedTokens; @@ -108,6 +109,7 @@ // 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 @@ static const int $StaticField[[Value]] = $TemplateParameter[[T]] ::$DependentType[[Resolver]]::$DependentName[[Value]]; }; + )cpp", + // Concepts + R"cpp( + template + concept $Concept[[Fooable]] = + requires($TemplateParameter[[T]] $Parameter[[F]]) { + $Parameter[[F]].$DependentName[[foo]](); + }; + template + requires $Concept[[Fooable]]<$TemplateParameter[[T]]> + void $Function[[bar]]($TemplateParameter[[T]] $Parameter[[F]]) { + $Parameter[[F]].$DependentName[[foo]](); + } )cpp"}; for (const auto &TestCase : TestCases) { checkHighlightings(TestCase);