llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Bill Wendling (isanbard) <details> <summary>Changes</summary> Inside a class template, references to members of a dependent base, such as 'this->size()' where the base is 'A<T>', aren't bound to a declaration until instantiation, so clang_getCursorReferenced() returned a null cursor for them. Fall back to HeuristicResolver, which clangd uses for the same purpose, to look the name up in the primary template, and return the result if it's a single declaration. This also resolves 'type_trait<T>::value' in a requires-clause or concept to the primary template's static member. 'A<T>::size()' (a qualified reference to an instance member) still isn't resolved, because HeuristicResolver only considers static members for a DependentScopeDeclRefExpr. Addresses part of #<!-- -->15370. Assisted-by: Claude Opus 5.5 --- Full diff: https://github.com/llvm/llvm-project/pull/235116.diff 3 Files Affected: - (added) clang/test/Index/cursor-ref-dependent-member.cpp (+33) - (modified) clang/test/Index/index-concepts.cpp (+3-3) - (modified) clang/tools/libclang/CIndex.cpp (+20) ``````````diff diff --git a/clang/test/Index/cursor-ref-dependent-member.cpp b/clang/test/Index/cursor-ref-dependent-member.cpp new file mode 100644 index 00000000000000..0f2093a2491b26 --- /dev/null +++ b/clang/test/Index/cursor-ref-dependent-member.cpp @@ -0,0 +1,33 @@ +// Check that clang_getCursorReferenced() resolves member references through a +// dependent base class to the member of the primary template. + +template <typename T> +class A { +public: + int size() const { return 1; } + int field; + void ov(int); + void ov(float); +}; + +template <typename T> +class B : public A<T> { +public: + int f1() const { return this->size(); } + int f2() const { return this->field; } + void f3() { this->ov(1); } + int f4() const { return A<T>::size(); } +}; + +// RUN: c-index-test -test-load-source local %s | FileCheck %s + +// CHECK: 16:27: CallExpr=:7:7 Extent=[16:27 - 16:39] +// CHECK: 16:27: MemberRefExpr=:7:7 Extent=[16:27 - 16:37] +// CHECK: 17:27: MemberRefExpr=:8:7 Extent=[17:27 - 17:38] + +// An overloaded member can't be resolved to a single declaration. +// CHECK: 18:15: MemberRefExpr= Extent=[18:15 - 18:23] + +// HeuristicResolver only considers static members for a qualified dependent +// name, so 'A<T>::size()' isn't resolved yet. +// CHECK: 19:27: DeclRefExpr= Extent=[19:27 - 19:37] diff --git a/clang/test/Index/index-concepts.cpp b/clang/test/Index/index-concepts.cpp index 17fbd02f34fe8f..04a814ca4894d8 100644 --- a/clang/test/Index/index-concepts.cpp +++ b/clang/test/Index/index-concepts.cpp @@ -13,7 +13,7 @@ struct type_trait<int> { template <class T> requires (type_trait<T>::value) // CHECK: index-concepts.cpp:[[@LINE-1]]:10: ParenExpr= Extent=[[[@LINE-1]]:10 - [[@LINE-1]]:32] -// CHECK: index-concepts.cpp:[[@LINE-2]]:11: DeclRefExpr= Extent=[[[@LINE-2]]:11 - [[@LINE-2]]:31] +// CHECK: index-concepts.cpp:[[@LINE-2]]:11: DeclRefExpr=:5:23 Extent=[[[@LINE-2]]:11 - [[@LINE-2]]:31] // CHECK: index-concepts.cpp:[[@LINE-3]]:11: TemplateRef=type_trait:4:8 Extent=[[[@LINE-3]]:11 - [[@LINE-3]]:21] // CHECK: index-concepts.cpp:[[@LINE-4]]:22: TypeRef=T:13:17 Extent=[[[@LINE-4]]:22 - [[@LINE-4]]:23] void indexRequiresClause() { @@ -22,7 +22,7 @@ void indexRequiresClause() { template<class T> requires (type_trait<T>::value) // CHECK: index-concepts.cpp:[[@LINE-1]]:10: ParenExpr= Extent=[[[@LINE-1]]:10 - [[@LINE-1]]:32] -// CHECK: index-concepts.cpp:[[@LINE-2]]:11: DeclRefExpr= Extent=[[[@LINE-2]]:11 - [[@LINE-2]]:31] +// CHECK: index-concepts.cpp:[[@LINE-2]]:11: DeclRefExpr=:5:23 Extent=[[[@LINE-2]]:11 - [[@LINE-2]]:31] // CHECK: index-concepts.cpp:[[@LINE-3]]:11: TemplateRef=type_trait:4:8 Extent=[[[@LINE-3]]:11 - [[@LINE-3]]:21] // CHECK: index-concepts.cpp:[[@LINE-4]]:22: TypeRef=T:22:16 Extent=[[[@LINE-4]]:22 - [[@LINE-4]]:23] class IndexRequiresClauseInClass {}; @@ -31,7 +31,7 @@ template <class T> concept Con1 = type_trait<T>::value; // CHECK: index-concepts.cpp:[[@LINE-1]]:9: ConceptDecl=Con1:[[@LINE-1]]:9 (Definition) Extent=[[[@LINE-2]]:1 - [[@LINE-1]]:36] // CHECK: index-concepts.cpp:[[@LINE-3]]:17: TemplateTypeParameter=T:[[@LINE-3]]:17 (Definition) Extent=[[[@LINE-3]]:11 - [[@LINE-3]]:18] [access=public] -// CHECK: index-concepts.cpp:[[@LINE-3]]:16: DeclRefExpr= Extent=[[[@LINE-3]]:16 - [[@LINE-3]]:36] +// CHECK: index-concepts.cpp:[[@LINE-3]]:16: DeclRefExpr=:5:23 Extent=[[[@LINE-3]]:16 - [[@LINE-3]]:36] // CHECK: index-concepts.cpp:[[@LINE-4]]:16: TemplateRef=type_trait:4:8 Extent=[[[@LINE-4]]:16 - [[@LINE-4]]:26] // CHECK: index-concepts.cpp:[[@LINE-5]]:27: TypeRef=T:30:17 Extent=[[[@LINE-5]]:27 - [[@LINE-5]]:28] diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 8d246d41f31f66..6f4dc06691ca7f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -46,6 +46,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/HeuristicResolver.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" @@ -5281,6 +5282,23 @@ static const Decl *getDeclFromExpr(const Stmt *E) { return nullptr; } +// Resolve a reference through a dependent name, such as 'A<T>::size()' or +// 'this->size()' in a class template deriving from 'A<T>'. The AST doesn't bind +// these to a declaration until instantiation, so use the same heuristics as +// clangd to look the name up in the primary template. Return null unless +// exactly one declaration is found, since the cursor can only name one. +static const Decl *getDeclFromDependentExpr(const Expr *E, ASTContext &Ctx) { + HeuristicResolver Resolver(Ctx); + std::vector<const NamedDecl *> Decls; + if (const auto *CE = dyn_cast<CallExpr>(E)) + Decls = Resolver.resolveCalleeOfCallExpr(CE); + else if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) + Decls = Resolver.resolveMemberExpr(ME); + else if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) + Decls = Resolver.resolveDeclRefExpr(RE); + return Decls.size() == 1 ? Decls.front() : nullptr; +} + static SourceLocation getLocationFromExpr(const Expr *E) { if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) return getLocationFromExpr(CE->getSubExpr()); @@ -7173,6 +7191,8 @@ CXCursor clang_getCursorReferenced(CXCursor C) { if (clang_isExpression(C.kind)) { const Expr *E = getCursorExpr(C); const Decl *D = getDeclFromExpr(E); + if (!D && E) + D = getDeclFromDependentExpr(E, getCursorContext(C)); if (D) { CXCursor declCursor = MakeCXCursor(D, tu); declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C), `````````` </details> https://github.com/llvm/llvm-project/pull/235116 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
