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 }