[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