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 @@ -230,6 +230,11 @@ dyn_cast(D)) { // Treat ObjC{Category,CategoryImpl}Decl as if they were a decl/def pair. D = CID->getCategoryDecl(); + } else if (const TemplateTypeParmDecl *TTPD = + dyn_cast(D)) { + if (auto *TC = TTPD->getTypeConstraint()) { + D = TC->getNamedConcept(); + } } if (!D) return; 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 @@ -559,7 +559,7 @@ template <[[Fooable]] T> void bar(T t); )cpp"; - EXPECT_DECLS("ConceptSpecializationExpr", + EXPECT_DECLS("TemplateTypeParmTypeLoc", {"template concept Fooable = true"}); // partial-concept-id @@ -570,7 +570,17 @@ template <[[Fooable]] T> void bar(T t); )cpp"; - EXPECT_DECLS("ConceptSpecializationExpr", + EXPECT_DECLS("TemplateTypeParmTypeLoc", + {"template concept Fooable = true"}); + + // Constrained function parameter + Code = R"cpp( + template + concept Fooable = true; + + void Foo([[Fooable]] auto t); + )cpp"; + EXPECT_DECLS("TemplateTypeParmTypeLoc", {"template concept Fooable = true"}); } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -487,6 +487,29 @@ HI.Kind = index::SymbolKind::TypeAlias; HI.Definition = "int"; }}, + // constrained function parameter + {R"cpp( + template concept Fooable = true; + void Foo([[Fooa^ble]] auto x) {} + )cpp", + [](HoverInfo &HI) { + HI.NamespaceScope = ""; + HI.Name = "Fooable"; + HI.Kind = index::SymbolKind::Concept; + HI.Definition = "template \nconcept Fooable = true"; + }}, + // constrained template parameter + {R"cpp( + template concept Fooable = true; + template <[[Foo^able]] T> + void bar(T t) {} + )cpp", + [](HoverInfo &HI) { + HI.NamespaceScope = ""; + HI.Name = "Fooable"; + HI.Kind = index::SymbolKind::Concept; + HI.Definition = "template \nconcept Fooable = true"; + }}, // auto on lambda {R"cpp( void foo() { @@ -3024,58 +3047,59 @@ struct { const char *Code; const std::function ExpectedBuilder; - } Cases[] = {{R"cpp( - struct Foo {}; + } Cases[] = { + {R"cpp( + struct Foo {}; Foo F = Fo^o{}; )cpp", - [](HoverInfo &HI) { HI.Provider = ""; }}, - {R"cpp( - #include "foo.h" + [](HoverInfo &HI) { HI.Provider = ""; }}, + {R"cpp( + #include "foo.h" Foo F = Fo^o{}; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - {R"cpp( - #include "all.h" + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + {R"cpp( + #include "all.h" Foo F = Fo^o{}; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - {R"cpp( + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + {R"cpp( #define FOO 5 int F = ^FOO; )cpp", - [](HoverInfo &HI) { HI.Provider = ""; }}, - {R"cpp( + [](HoverInfo &HI) { HI.Provider = ""; }}, + {R"cpp( #include "foo.h" int F = ^FOO; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - {R"cpp( + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + {R"cpp( #include "all.h" int F = ^FOO; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - {R"cpp( - #include "foo.h" + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + {R"cpp( + #include "foo.h" Foo A; Foo B; Foo C = A ^+ B; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - // Hover selects the underlying decl of the using decl - {R"cpp( + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + // Hover selects the underlying decl of the using decl + {R"cpp( #include "foo.h" namespace ns { using ::Foo; } ns::F^oo d; )cpp", - [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, - {R"cpp( + [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}, + {R"cpp( namespace foo {}; using namespace fo^o; )cpp", - [](HoverInfo &HI) { HI.Provider = ""; }}, - }; + [](HoverInfo &HI) { HI.Provider = ""; }}, + }; for (const auto &Case : Cases) { Annotations Code{Case.Code}; diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -751,6 +751,8 @@ TemplateTypeParmType> { public: TemplateTypeParmDecl *getDecl() const { return getTypePtr()->getDecl(); } + + SourceRange getLocalSourceRange() const; }; struct ObjCTypeParamTypeLocInfo { diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -11,9 +11,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TypeLoc.h" -#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -718,3 +719,21 @@ return AutoTypeLoc(); return Res.getAs(); } + +SourceRange TemplateTypeParmTypeLoc::getLocalSourceRange() const { + SourceRange SR = + InheritingConcreteTypeLoc::getLocalSourceRange(); + SourceLocation StartLoc = SR.getBegin(); + + if (auto *D = getDecl()) { + if (auto *TC = D->getTypeConstraint()) { + if (TC->getNestedNameSpecifierLoc()) { + StartLoc = TC->getNestedNameSpecifierLoc().getBeginLoc(); + } else { + StartLoc = TC->getConceptNameLoc(); + } + } + } + return SourceRange(StartLoc, getNameLoc()); +} diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Testing/CommandLineArgs.h" #include "clang/Tooling/Tooling.h" #include "llvm/Testing/Annotations/Annotations.h" #include "gtest/gtest.h" @@ -263,6 +264,19 @@ EXPECT_TRUE(Verifier.match(Code, typeLoc(loc(autoType())), Lang_CXX20)); } +TEST(TypeLoc, TemplateTypeParmTypeLocRange) { + RangeVerifier Verifier; + Verifier.expectRange(2, 10, 2, 18); + EXPECT_TRUE(Verifier.match("template concept Fooable = true;\n" + "void Bar(Fooable auto x) {}", + typeLoc(loc(templateTypeParmType())), Lang_CXX20)); + + Verifier.expectRange(2, 11, 2, 31); + EXPECT_TRUE(Verifier.match("template concept Fooable = true;\n" + "template void bar(T t) {}", + typeLoc(loc(templateTypeParmType())), Lang_CXX20)); +} + TEST(TypeLoc, LongDoubleRange) { RangeVerifier Verifier; Verifier.expectRange(1, 1, 1, 6); @@ -370,10 +384,10 @@ TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) { RangeVerifier Verifier; Verifier.expectRange(2, 20, 2, 31); - EXPECT_TRUE(Verifier.match( - "typedef int int2 __attribute__((ext_vector_type(2)));\n" - "constant int2 i2 = (int2)(1, 2);", - compoundLiteralExpr(), Lang_OpenCL)); + EXPECT_TRUE( + Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n" + "constant int2 i2 = (int2)(1, 2);", + compoundLiteralExpr(), Lang_OpenCL)); } TEST(InitListExpr, VectorLiteralListBraceRange) {