[clang] [clang-tools-extra] [clang] Compute accurate begin location for CallExpr with explicit object parameter (PR #117841)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 28 21:05:06 PST 2024
https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/117841
>From 367a0cc6b3e1e1f67d023c96e06ae438f8f37f37 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Tue, 26 Nov 2024 22:41:43 -0500
Subject: [PATCH] [clang] Compute accurate begin location for CallExpr with
explicit object parameter
The explicit object parameter is written before the callee expression,
so the begin location should come from the explicit object parameter.
---
.../clangd/unittests/XRefsTests.cpp | 148 ++++++++++--------
clang/lib/AST/Expr.cpp | 8 +
clang/lib/Sema/SemaOverload.cpp | 2 +-
.../test/AST/ast-dump-cxx2b-deducing-this.cpp | 4 +-
4 files changed, 90 insertions(+), 72 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index d393c72974d447..87efb42be47121 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -450,7 +450,7 @@ TEST(LocateSymbol, All) {
// $def is the definition location (if absent, symbol has no definition)
// unnamed range becomes both $decl and $def.
const char *Tests[] = {
- R"cpp(
+ R"cpp(
struct X {
union {
int [[a]];
@@ -462,7 +462,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Local variable
+ R"cpp(// Local variable
int main() {
int [[bonjour]];
^bonjour = 2;
@@ -470,7 +470,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Struct
+ R"cpp(// Struct
namespace ns1 {
struct [[MyClass]] {};
} // namespace ns1
@@ -479,21 +479,21 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Function definition via pointer
+ R"cpp(// Function definition via pointer
void [[foo]](int) {}
int main() {
auto *X = &^foo;
}
)cpp",
- R"cpp(// Function declaration via call
+ R"cpp(// Function declaration via call
int $decl[[foo]](int);
int main() {
return ^foo(42);
}
)cpp",
- R"cpp(// Field
+ R"cpp(// Field
struct Foo { int [[x]]; };
int main() {
Foo bar;
@@ -501,21 +501,21 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Field, member initializer
+ R"cpp(// Field, member initializer
struct Foo {
int [[x]];
Foo() : ^x(0) {}
};
)cpp",
- R"cpp(// Field, field designator
+ R"cpp(// Field, field designator
struct Foo { int [[x]]; };
int main() {
Foo bar = { .^x = 2 };
}
)cpp",
- R"cpp(// Method call
+ R"cpp(// Method call
struct Foo { int $decl[[x]](); };
int main() {
Foo bar;
@@ -523,31 +523,31 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Typedef
+ R"cpp(// Typedef
typedef int $decl[[Foo]];
int main() {
^Foo bar;
}
)cpp",
- R"cpp(// Template type parameter
+ R"cpp(// Template type parameter
template <typename [[T]]>
void foo() { ^T t; }
)cpp",
- R"cpp(// Template template type parameter
+ R"cpp(// Template template type parameter
template <template<typename> class [[T]]>
void foo() { ^T<int> t; }
)cpp",
- R"cpp(// Namespace
+ R"cpp(// Namespace
namespace $decl[[ns]] {
struct Foo { static void bar(); };
} // namespace ns
int main() { ^ns::Foo::bar(); }
)cpp",
- R"cpp(// Macro
+ R"cpp(// Macro
class TTT { public: int a; };
#define [[FF]](S) if (int b = S.a) {}
void f() {
@@ -556,12 +556,12 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Macro argument
+ R"cpp(// Macro argument
int [[i]];
#define ADDRESSOF(X) &X;
int *j = ADDRESSOF(^i);
)cpp",
- R"cpp(// Macro argument appearing multiple times in expansion
+ R"cpp(// Macro argument appearing multiple times in expansion
#define VALIDATE_TYPE(x) (void)x;
#define ASSERT(expr) \
do { \
@@ -573,37 +573,37 @@ TEST(LocateSymbol, All) {
ASSERT(wa^ldo());
}
)cpp",
- R"cpp(// Symbol concatenated inside macro (not supported)
+ R"cpp(// Symbol concatenated inside macro (not supported)
int *pi;
#define POINTER(X) p ## X;
int x = *POINTER(^i);
)cpp",
- R"cpp(// Forward class declaration
+ R"cpp(// Forward class declaration
class $decl[[Foo]];
class $def[[Foo]] {};
F^oo* foo();
)cpp",
- R"cpp(// Function declaration
+ R"cpp(// Function declaration
void $decl[[foo]]();
void g() { f^oo(); }
void $def[[foo]]() {}
)cpp",
- R"cpp(
+ R"cpp(
#define FF(name) class name##_Test {};
[[FF]](my);
void f() { my^_Test a; }
)cpp",
- R"cpp(
+ R"cpp(
#define FF() class [[Test]] {};
FF();
void f() { T^est a; }
)cpp",
- R"cpp(// explicit template specialization
+ R"cpp(// explicit template specialization
template <typename T>
struct Foo { void bar() {} };
@@ -616,7 +616,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// implicit template specialization
+ R"cpp(// implicit template specialization
template <typename T>
struct [[Foo]] { void bar() {} };
template <>
@@ -627,7 +627,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// partial template specialization
+ R"cpp(// partial template specialization
template <typename T>
struct Foo { void bar() {} };
template <typename T>
@@ -635,7 +635,7 @@ TEST(LocateSymbol, All) {
^Foo<int*> x;
)cpp",
- R"cpp(// function template specializations
+ R"cpp(// function template specializations
template <class T>
void foo(T) {}
template <>
@@ -645,7 +645,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// variable template decls
+ R"cpp(// variable template decls
template <class T>
T var = T();
@@ -655,7 +655,7 @@ TEST(LocateSymbol, All) {
double y = va^r<int>;
)cpp",
- R"cpp(// No implicit constructors
+ R"cpp(// No implicit constructors
struct X {
X(X&& x) = default;
};
@@ -665,7 +665,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(
+ R"cpp(
struct X {
X& $decl[[operator]]++();
};
@@ -674,7 +674,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(
+ R"cpp(
struct S1 { void f(); };
struct S2 { S1 * $decl[[operator]]->(); };
void test(S2 s2) {
@@ -682,7 +682,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Declaration of explicit template specialization
+ R"cpp(// Declaration of explicit template specialization
template <typename T>
struct $decl[[$def[[Foo]]]] {};
@@ -690,7 +690,7 @@ TEST(LocateSymbol, All) {
struct Fo^o<int> {};
)cpp",
- R"cpp(// Declaration of partial template specialization
+ R"cpp(// Declaration of partial template specialization
template <typename T>
struct $decl[[$def[[Foo]]]] {};
@@ -698,7 +698,7 @@ TEST(LocateSymbol, All) {
struct Fo^o<T*> {};
)cpp",
- R"cpp(// Definition on ClassTemplateDecl
+ R"cpp(// Definition on ClassTemplateDecl
namespace ns {
// Forward declaration.
template<typename T>
@@ -711,16 +711,16 @@ TEST(LocateSymbol, All) {
using ::ns::Fo^o;
)cpp",
- R"cpp(// auto builtin type (not supported)
+ R"cpp(// auto builtin type (not supported)
^auto x = 42;
)cpp",
- R"cpp(// auto on lambda
+ R"cpp(// auto on lambda
auto x = [[[]]]{};
^auto y = x;
)cpp",
- R"cpp(// auto on struct
+ R"cpp(// auto on struct
namespace ns1 {
struct [[S1]] {};
} // namespace ns1
@@ -728,7 +728,7 @@ TEST(LocateSymbol, All) {
^auto x = ns1::S1{};
)cpp",
- R"cpp(// decltype on struct
+ R"cpp(// decltype on struct
namespace ns1 {
struct [[S1]] {};
} // namespace ns1
@@ -737,7 +737,7 @@ TEST(LocateSymbol, All) {
^decltype(i) j;
)cpp",
- R"cpp(// decltype(auto) on struct
+ R"cpp(// decltype(auto) on struct
namespace ns1 {
struct [[S1]] {};
} // namespace ns1
@@ -747,27 +747,27 @@ TEST(LocateSymbol, All) {
^decltype(auto) k = j;
)cpp",
- R"cpp(// auto on template class
+ R"cpp(// auto on template class
template<typename T> class [[Foo]] {};
^auto x = Foo<int>();
)cpp",
- R"cpp(// auto on template class with forward declared class
+ R"cpp(// auto on template class with forward declared class
template<typename T> class [[Foo]] {};
class X;
^auto x = Foo<X>();
)cpp",
- R"cpp(// auto on specialized template class
+ R"cpp(// auto on specialized template class
template<typename T> class Foo {};
template<> class [[Foo]]<int> {};
^auto x = Foo<int>();
)cpp",
- R"cpp(// auto on initializer list.
+ R"cpp(// auto on initializer list.
namespace std
{
template<class _E>
@@ -777,28 +777,28 @@ TEST(LocateSymbol, All) {
^auto i = {1,2};
)cpp",
- R"cpp(// auto function return with trailing type
+ R"cpp(// auto function return with trailing type
struct [[Bar]] {};
^auto test() -> decltype(Bar()) {
return Bar();
}
)cpp",
- R"cpp(// decltype in trailing return type
+ R"cpp(// decltype in trailing return type
struct [[Bar]] {};
auto test() -> ^decltype(Bar()) {
return Bar();
}
)cpp",
- R"cpp(// auto in function return
+ R"cpp(// auto in function return
struct [[Bar]] {};
^auto test() {
return Bar();
}
)cpp",
- R"cpp(// auto& in function return
+ R"cpp(// auto& in function return
struct [[Bar]] {};
^auto& test() {
static Bar x;
@@ -806,7 +806,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// auto* in function return
+ R"cpp(// auto* in function return
struct [[Bar]] {};
^auto* test() {
Bar* x;
@@ -814,7 +814,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// const auto& in function return
+ R"cpp(// const auto& in function return
struct [[Bar]] {};
const ^auto& test() {
static Bar x;
@@ -822,20 +822,20 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// auto lambda param where there's a single instantiation
+ R"cpp(// auto lambda param where there's a single instantiation
struct [[Bar]] {};
auto Lambda = [](^auto){ return 0; };
int x = Lambda(Bar{});
)cpp",
- R"cpp(// decltype(auto) in function return
+ R"cpp(// decltype(auto) in function return
struct [[Bar]] {};
^decltype(auto) test() {
return Bar();
}
)cpp",
- R"cpp(// decltype of function with trailing return type.
+ R"cpp(// decltype of function with trailing return type.
struct [[Bar]] {};
auto test() -> decltype(Bar()) {
return Bar();
@@ -845,17 +845,17 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Override specifier jumps to overridden method
+ R"cpp(// Override specifier jumps to overridden method
class Y { virtual void $decl[[a]]() = 0; };
class X : Y { void a() ^override {} };
)cpp",
- R"cpp(// Final specifier jumps to overridden method
+ R"cpp(// Final specifier jumps to overridden method
class Y { virtual void $decl[[a]]() = 0; };
class X : Y { void a() ^final {} };
)cpp",
- R"cpp(// Heuristic resolution of dependent method
+ R"cpp(// Heuristic resolution of dependent method
template <typename T>
struct S {
void [[bar]]() {}
@@ -867,7 +867,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Heuristic resolution of dependent method via this->
+ R"cpp(// Heuristic resolution of dependent method via this->
template <typename T>
struct S {
void [[foo]]() {
@@ -876,7 +876,7 @@ TEST(LocateSymbol, All) {
};
)cpp",
- R"cpp(// Heuristic resolution of dependent static method
+ R"cpp(// Heuristic resolution of dependent static method
template <typename T>
struct S {
static void [[bar]]() {}
@@ -888,7 +888,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Heuristic resolution of dependent method
+ R"cpp(// Heuristic resolution of dependent method
// invoked via smart pointer
template <typename> struct S { void [[foo]]() {} };
template <typename T> struct unique_ptr {
@@ -900,7 +900,7 @@ TEST(LocateSymbol, All) {
}
)cpp",
- R"cpp(// Heuristic resolution of dependent enumerator
+ R"cpp(// Heuristic resolution of dependent enumerator
template <typename T>
struct Foo {
enum class E { [[A]], B };
@@ -908,20 +908,20 @@ TEST(LocateSymbol, All) {
};
)cpp",
- R"cpp(// Enum base
+ R"cpp(// Enum base
typedef int $decl[[MyTypeDef]];
enum Foo : My^TypeDef {};
)cpp",
- R"cpp(// Enum base
+ R"cpp(// Enum base
typedef int $decl[[MyTypeDef]];
enum Foo : My^TypeDef;
)cpp",
- R"cpp(// Enum base
+ R"cpp(// Enum base
using $decl[[MyTypeDef]] = int;
enum Foo : My^TypeDef {};
)cpp",
- R"objc(
+ R"objc(
@protocol Dog;
@protocol $decl[[Dog]]
- (void)bark;
@@ -931,7 +931,7 @@ TEST(LocateSymbol, All) {
}
)objc",
- R"objc(
+ R"objc(
@interface Cat
@end
@implementation Cat
@@ -944,14 +944,14 @@ TEST(LocateSymbol, All) {
@end
)objc",
- R"objc(
+ R"objc(
@class $decl[[Foo]];
Fo^o * getFoo() {
return 0;
}
)objc",
- R"objc(// Prefer interface definition over forward declaration
+ R"objc(// Prefer interface definition over forward declaration
@class Foo;
@interface $decl[[Foo]]
@end
@@ -960,7 +960,7 @@ TEST(LocateSymbol, All) {
}
)objc",
- R"objc(
+ R"objc(
@class Foo;
@interface $decl[[Foo]]
@end
@@ -971,7 +971,7 @@ TEST(LocateSymbol, All) {
}
)objc",
- R"objc(// Method decl and definition for ObjC class.
+ R"objc(// Method decl and definition for ObjC class.
@interface Cat
- (void)$decl[[meow]];
@end
@@ -983,7 +983,7 @@ TEST(LocateSymbol, All) {
}
)objc",
- R"objc(// Method decl and definition for ObjC category.
+ R"objc(// Method decl and definition for ObjC category.
@interface Dog
@end
@interface Dog (Play)
@@ -997,7 +997,7 @@ TEST(LocateSymbol, All) {
}
)objc",
- R"objc(// Method decl and definition for ObjC class extension.
+ R"objc(// Method decl and definition for ObjC class extension.
@interface Dog
@end
@interface Dog ()
@@ -1010,7 +1010,7 @@ TEST(LocateSymbol, All) {
[dog ho^wl];
}
)objc",
- R"cpp(
+ R"cpp(
struct PointerIntPairInfo {
static void *getPointer(void *Value);
};
@@ -1019,6 +1019,15 @@ TEST(LocateSymbol, All) {
void *Value;
void *getPointer() const { return Info::get^Pointer(Value); }
};
+ )cpp",
+ R"cpp(// Deducing this
+ struct S {
+ int bar(this S&);
+ };
+ void foo() {
+ S [[waldo]];
+ int x = wa^ldo.bar();
+ }
)cpp"};
for (const char *Test : Tests) {
Annotations T(Test);
@@ -1035,6 +1044,7 @@ TEST(LocateSymbol, All) {
TU.Code = std::string(T.code());
TU.ExtraArgs.push_back("-xobjective-c++");
+ TU.ExtraArgs.push_back("-std=c++23");
auto AST = TU.build();
auto Results = locateSymbolAt(AST, T.point());
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index a4fb4d5a1f2ec4..5a6738196d2890 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1639,11 +1639,19 @@ SourceLocation CallExpr::getBeginLoc() const {
if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
return OCE->getBeginLoc();
+ if (const auto *Method =
+ dyn_cast_if_present<const CXXMethodDecl>(getCalleeDecl());
+ Method && Method->isExplicitObjectMemberFunction()) {
+ assert(getNumArgs() > 0 && getArg(0));
+ return getArg(0)->getBeginLoc();
+ }
+
SourceLocation begin = getCallee()->getBeginLoc();
if (begin.isInvalid() && getNumArgs() > 0 && getArg(0))
begin = getArg(0)->getBeginLoc();
return begin;
}
+
SourceLocation CallExpr::getEndLoc() const {
if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(this))
return OCE->getEndLoc();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4c9e37bd286dee..e4bf9aa521224b 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -15565,7 +15565,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// Build the actual expression node.
ExprResult FnExpr =
CreateFunctionRefExpr(*this, Method, FoundDecl, MemExpr,
- HadMultipleCandidates, MemExpr->getBeginLoc());
+ HadMultipleCandidates, MemExpr->getExprLoc());
if (FnExpr.isInvalid())
return ExprError();
diff --git a/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp b/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp
index 04cff07376885a..1b385e0fc33319 100644
--- a/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp
+++ b/clang/test/AST/ast-dump-cxx2b-deducing-this.cpp
@@ -9,7 +9,7 @@ int main() {
S s;
int x = s.f();
// CHECK: CallExpr 0x{{[^ ]*}} <col:11, col:15> 'int
- // CHECK-NEXT: |-ImplicitCastExpr 0x{{[^ ]*}} <col:11> 'int (*)(S &)' <FunctionToPointerDecay>
- // CHECK-NEXT: | `-DeclRefExpr 0x{{[^ ]*}} <col:11> 'int (S &)' lvalue CXXMethod 0x{{[^ ]*}} 'f' 'int (S &)'
+ // CHECK-NEXT: |-ImplicitCastExpr 0x{{[^ ]*}} <col:13> 'int (*)(S &)' <FunctionToPointerDecay>
+ // CHECK-NEXT: | `-DeclRefExpr 0x{{[^ ]*}} <col:13> 'int (S &)' lvalue CXXMethod 0x{{[^ ]*}} 'f' 'int (S &)'
}
}
More information about the cfe-commits
mailing list