[clang-tools-extra] a8c9b9f - [clangd] Support ConceptReference in generic AST wrangling code
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 4 06:09:16 PDT 2023
Author: Sam McCall
Date: 2023-09-04T14:58:25+02:00
New Revision: a8c9b9f1402ccf93955a26d5933cd8c3150c3845
URL: https://github.com/llvm/llvm-project/commit/a8c9b9f1402ccf93955a26d5933cd8c3150c3845
DIFF: https://github.com/llvm/llvm-project/commit/a8c9b9f1402ccf93955a26d5933cd8c3150c3845.diff
LOG: [clangd] Support ConceptReference in generic AST wrangling code
Now we can store it in DynTypedNode, we can target these nodes
(SelectionTree) and resolve them (FindTarget).
This makes Hover, go-to-def etc work in all(?) cases.
Also support it in DumpAST.
Differential Revision: https://reviews.llvm.org/D159299
Added:
Modified:
clang-tools-extra/clangd/DumpAST.cpp
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/Selection.cpp
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
clang-tools-extra/clangd/unittests/HoverTests.cpp
clang-tools-extra/clangd/unittests/SelectionTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp
index 2bf75e65a9efb22..85f2592445f2a52 100644
--- a/clang-tools-extra/clangd/DumpAST.cpp
+++ b/clang-tools-extra/clangd/DumpAST.cpp
@@ -205,6 +205,11 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
// To avoid special cases in the API/UI, use public/private as the kind.
return getAccessSpelling(CBS.getAccessSpecifier()).str();
}
+ std::string getKind(const ConceptReference *CR) {
+ // Again there are no variants here.
+ // Kind is "Concept", role is "reference"
+ return "Concept";
+ }
// Detail is the single most important fact about the node.
// Often this is the name, sometimes a "kind" enum like operators or casts.
@@ -305,6 +310,9 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
std::string getDetail(const CXXBaseSpecifier &CBS) {
return CBS.isVirtual() ? "virtual" : "";
}
+ std::string getDetail(const ConceptReference *CR) {
+ return CR->getNamedConcept()->getNameAsString();
+ }
/// Arcana is produced by TextNodeDumper, for the types it supports.
@@ -365,6 +373,10 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
bool TraverseAttr(Attr *A) {
return !A || traverseNode("attribute", A, [&] { Base::TraverseAttr(A); });
}
+ bool TraverseConceptReference(ConceptReference *C) {
+ return !C || traverseNode("reference", C,
+ [&] { Base::TraverseConceptReference(C); });
+ }
bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &CBS) {
return traverseNode("base", CBS,
[&] { Base::TraverseCXXBaseSpecifier(CBS); });
@@ -422,6 +434,8 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens,
V.TraverseTemplateArgumentLoc(*const_cast<TemplateArgumentLoc *>(TAL));
else if (const auto *CBS = N.get<CXXBaseSpecifier>())
V.TraverseCXXBaseSpecifier(*const_cast<CXXBaseSpecifier *>(CBS));
+ else if (const auto *CR = N.get<ConceptReference>())
+ V.TraverseConceptReference(const_cast<ConceptReference *>(CR));
else
elog("dumpAST: unhandled DynTypedNode kind {0}",
N.getNodeKind().asStringRef());
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index c1ec030275c4f63..a766122ad3deee9 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -10,6 +10,7 @@
#include "AST.h"
#include "HeuristicResolver.h"
#include "support/Logger.h"
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
@@ -257,7 +258,7 @@ struct TargetFinder {
Outer.add(CE->getCalleeDecl(), Flags);
}
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) {
- Outer.add(E->getNamedConcept(), Flags);
+ Outer.add(E->getConceptReference(), Flags);
}
void VisitDeclRefExpr(const DeclRefExpr *DRE) {
const Decl *D = DRE->getDecl();
@@ -532,6 +533,10 @@ struct TargetFinder {
add(USD, Flags);
}
}
+
+ void add(const ConceptReference *CR, RelSet Flags) {
+ add(CR->getNamedConcept(), Flags);
+ }
};
} // namespace
@@ -561,6 +566,8 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) {
Finder.add(CBS->getTypeSourceInfo()->getType(), Flags);
else if (const ObjCProtocolLoc *PL = N.get<ObjCProtocolLoc>())
Finder.add(PL->getProtocol(), Flags);
+ else if (const ConceptReference *CR = N.get<ConceptReference>())
+ Finder.add(CR, Flags);
return Finder.takeDecls();
}
@@ -1056,11 +1063,8 @@ class ExplicitReferenceCollector
return RecursiveASTVisitor::TraverseConstructorInitializer(Init);
}
- bool VisitConceptReference(ConceptReference *ConceptRef) {
- Out(ReferenceLoc{ConceptRef->getNestedNameSpecifierLoc(),
- ConceptRef->getConceptNameLoc(),
- /*IsDecl=*/false,
- {ConceptRef->getNamedConcept()}});
+ bool VisitConceptReference(const ConceptReference *CR) {
+ visitNode(DynTypedNode::create(*CR));
return true;
}
@@ -1109,6 +1113,11 @@ class ExplicitReferenceCollector
PL->getLocation(),
/*IsDecl=*/false,
{PL->getProtocol()}}};
+ if (const ConceptReference *CR = N.get<ConceptReference>())
+ return {ReferenceLoc{CR->getNestedNameSpecifierLoc(),
+ CR->getConceptNameLoc(),
+ /*IsDecl=*/false,
+ {CR->getNamedConcept()}}};
// We do not have location information for other nodes (QualType, etc)
return {};
diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index 233a3c7cd313df7..8c6d5750ecefdba 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -635,8 +635,12 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
if (llvm::isa_and_nonnull<TranslationUnitDecl>(X))
return Base::TraverseDecl(X); // Already pushed by constructor.
// Base::TraverseDecl will suppress children, but not this node itself.
- if (X && X->isImplicit())
- return true;
+ if (X && X->isImplicit()) {
+ // Most implicit nodes have only implicit children and can be skipped.
+ // However there are exceptions (`void foo(Concept auto x)`), and
+ // the base implementation knows how to find them.
+ return Base::TraverseDecl(X);
+ }
return traverseNode(X, [&] { return Base::TraverseDecl(X); });
}
bool TraverseTypeLoc(TypeLoc X) {
@@ -660,6 +664,9 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> {
bool TraverseAttr(Attr *X) {
return traverseNode(X, [&] { return Base::TraverseAttr(X); });
}
+ bool TraverseConceptReference(ConceptReference *X) {
+ return traverseNode(X, [&] { return Base::TraverseConceptReference(X); });
+ }
// Stmt is the same, but this form allows the data recursion optimization.
bool dataTraverseStmtPre(Stmt *X) {
if (!X || isImplicit(X))
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 19e80658de063ce..fbd10c4a47a793d 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -537,7 +537,7 @@ TEST_F(TargetDeclTest, Concept) {
}
)cpp";
EXPECT_DECLS(
- "ConceptSpecializationExpr",
+ "ConceptReference",
{"template <typename T> concept Fooable = requires (T t) { t.foo(); }"});
// trailing requires clause
@@ -548,7 +548,7 @@ TEST_F(TargetDeclTest, Concept) {
template <typename T>
void foo() requires [[Fooable]]<T>;
)cpp";
- EXPECT_DECLS("ConceptSpecializationExpr",
+ EXPECT_DECLS("ConceptReference",
{"template <typename T> concept Fooable = true"});
// constrained-parameter
@@ -559,7 +559,7 @@ TEST_F(TargetDeclTest, Concept) {
template <[[Fooable]] T>
void bar(T t);
)cpp";
- EXPECT_DECLS("ConceptSpecializationExpr",
+ EXPECT_DECLS("ConceptReference",
{"template <typename T> concept Fooable = true"});
// partial-concept-id
@@ -570,7 +570,7 @@ TEST_F(TargetDeclTest, Concept) {
template <[[Fooable]]<int> T>
void bar(T t);
)cpp";
- EXPECT_DECLS("ConceptSpecializationExpr",
+ EXPECT_DECLS("ConceptReference",
{"template <typename T, typename U> concept Fooable = true"});
}
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index c26bda898687cb1..8c88cd52574536c 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -487,6 +487,16 @@ class Foo final {})cpp";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "int";
}},
+ {R"cpp(
+ template <class T> concept F = true;
+ [[^F]] auto x = 1;
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "F";
+ HI.Kind = index::SymbolKind::Concept;
+ HI.Definition = "template <class T>\nconcept F = true";
+ }},
// auto on lambda
{R"cpp(
void foo() {
@@ -535,7 +545,7 @@ class Foo final {})cpp";
HI.Kind = index::SymbolKind::Concept;
HI.Definition = "template <class T>\nconcept Fooable = true";
}},
- {R"cpp(
+ {R"cpp(
template<class T> concept Fooable = true;
template<Fooable [[T^T]]>
void bar(TT t) {}
@@ -549,6 +559,28 @@ class Foo final {})cpp";
HI.Kind = index::SymbolKind::TemplateTypeParm;
HI.Definition = "Fooable TT";
}},
+ {R"cpp(
+ template<class T> concept Fooable = true;
+ void bar([[Foo^able]] auto t) {}
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Fooable";
+ HI.Kind = index::SymbolKind::Concept;
+ HI.Definition = "template <class T>\nconcept Fooable = true";
+ }},
+ // concept reference
+ {R"cpp(
+ template<class T> concept Fooable = true;
+ auto X = [[Fooa^ble]]<int>;
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Fooable";
+ HI.Kind = index::SymbolKind::Concept;
+ HI.Definition = "template <class T>\nconcept Fooable = true";
+ HI.Value = "true";
+ }},
// empty macro
{R"cpp(
diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index 422a89a49630d33..4c019a1524f3c39 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -561,6 +561,33 @@ TEST(SelectionTest, CommonAncestor) {
[[^using enum ns::A]];
)cpp",
"UsingEnumDecl"},
+
+ // concepts
+ {R"cpp(
+ template <class> concept C = true;
+ auto x = [[^C<int>]];
+ )cpp",
+ "ConceptReference"},
+ {R"cpp(
+ template <class> concept C = true;
+ [[^C]] auto x = 0;
+ )cpp",
+ "ConceptReference"},
+ {R"cpp(
+ template <class> concept C = true;
+ void foo([[^C]] auto x) {}
+ )cpp",
+ "ConceptReference"},
+ {R"cpp(
+ template <class> concept C = true;
+ template <[[^C]] x> int i = 0;
+ )cpp",
+ "ConceptReference"},
+ {R"cpp(
+ namespace ns { template <class> concept C = true; }
+ auto x = [[ns::^C<int>]];
+ )cpp",
+ "ConceptReference"},
};
for (const Case &C : Cases) {
More information about the cfe-commits
mailing list