From db4d699aaad7fbcb70339d6e9d671ac048596c4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?=
 <70830482+FnControlOption@users.noreply.github.com>
Date: Thu, 11 May 2023 11:42:15 -0700
Subject: [PATCH] Fix AST location of call name in operator assignment

In `@foo.bar += 1`, `Call#name_location` refers to `bar`, and
`OpAssign#name_location` refers to `+=`
---
 spec/compiler/parser/parser_spec.cr   | 6 ++++++
 src/compiler/crystal/syntax/parser.cr | 6 +++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 93c2a98d3d55..d11097616c5e 100644
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -2513,6 +2513,12 @@ module Crystal
         source_between(source, node.name_location, node.name_end_location).should eq("foo")
       end
 
+      it "sets correct location of call name in operator assignment" do
+        source = "@foo.bar += 1"
+        node = Parser.parse(source).as(OpAssign).target.as(Call)
+        source_between(source, node.name_location, node.name_end_location).should eq("bar")
+      end
+
       it "sets correct location of element in array literal" do
         source = "%i(foo bar)"
         elements = Parser.new(source).parse.as(ArrayLiteral).elements
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index 4d18ce7ef1aa..4dbdb0c45313 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -696,7 +696,6 @@ module Crystal
           end
 
           check AtomicWithMethodCheck
-          name_location = @token.location
 
           if @token.value == Keyword::IS_A_QUESTION
             atomic = parse_is_a(atomic).at(location)
@@ -720,6 +719,7 @@ module Crystal
                    else
                      @token.type.to_s
                    end
+            name_location = @token.location
             end_location = token_end_location
 
             @wants_regex = false
@@ -763,14 +763,14 @@ module Crystal
               atomic.name_location = name_location
               next
             when .assignment_operator?
-              name_location = @token.location
+              op_name_location = @token.location
               method = @token.type.to_s.byte_slice(0, @token.type.to_s.size - 1)
               next_token_skip_space_or_newline
               value = parse_op_assign
               call = Call.new(atomic, name).at(location)
               call.name_location = name_location
               atomic = OpAssign.new(call, method, value).at(location)
-              atomic.name_location = name_location
+              atomic.name_location = op_name_location
               next
             else
               call_args = preserve_stop_on_do { space_consumed ? parse_call_args_space_consumed : parse_call_args }