diff --git a/prism/config.yml b/prism/config.yml index 7e71e4e50b3775..d3b6b08709c492 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -345,6 +345,8 @@ flags: comment: "&. operator" - name: VARIABLE_CALL comment: "a call that could have been a local variable" + - name: ATTRIBUTE_WRITE + comment: "a call that is an attribute write, so the value being written should be returned" comment: Flags for call nodes. - name: EncodingFlags values: diff --git a/prism/prism.c b/prism/prism.c index 1474a1854f49ed..2b74152cce1884 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -10856,6 +10856,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod call->base.location.end = arguments->base.location.end; parse_write_name(parser, &call->name); + call->base.flags |= PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE; return (pm_node_t *) call; } } @@ -10873,6 +10874,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod // Replace the name with "[]=". call->name = pm_parser_constant_id_constant(parser, "[]=", 3); + call->base.flags |= PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE; return target; } diff --git a/test/prism/attribute_write_test.rb b/test/prism/attribute_write_test.rb new file mode 100644 index 00000000000000..bd83d72da35591 --- /dev/null +++ b/test/prism/attribute_write_test.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +module Prism + class AttributeWriteTest < TestCase + module Target + def self.value + 2 + end + + def self.value=(value) + 2 + end + + def self.[]=(index, value) + 2 + end + end + + def test_named_call_with_operator + assert_attribute_write("Target.value = 1") + end + + def test_named_call_without_operator + assert_attribute_write("Target.value=(1)") + end + + def test_indexed_call_with_operator + assert_attribute_write("Target[0] = 1") + end + + def test_indexed_call_without_operator + refute_attribute_write("Target.[]=(0, 1)") + end + + def test_comparison_operators + refute_attribute_write("Target.value == 1") + refute_attribute_write("Target.value === 1") + end + + private + + def parse(source) + Prism.parse(source).value.statements.body.first + end + + def assert_attribute_write(source) + call = parse(source) + assert(call.attribute_write?) + assert_equal(1, eval(source)) + end + + def refute_attribute_write(source) + call = parse(source) + refute(call.attribute_write?) + refute_equal(1, eval(source)) + end + end +end diff --git a/test/prism/snapshots/arrays.txt b/test/prism/snapshots/arrays.txt index 7601fc38d9526d..d31cd7afc857a7 100644 --- a/test/prism/snapshots/arrays.txt +++ b/test/prism/snapshots/arrays.txt @@ -22,7 +22,7 @@ │ ├── opening_loc: (1,0)-(1,1) = "[" │ └── closing_loc: (1,3)-(1,4) = "]" ├── @ CallNode (location: (3,0)-(3,23)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (3,0)-(3,3)) │ │ ├── flags: variable_call @@ -205,7 +205,7 @@ │ ├── opening_loc: (28,0)-(28,1) = "[" │ └── closing_loc: (28,11)-(28,12) = "]" ├── @ CallNode (location: (30,0)-(30,19)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (30,0)-(30,8)) │ │ ├── flags: ∅ @@ -375,7 +375,7 @@ │ ├── closing_loc: (37,12)-(37,13) = "]" │ └── block: ∅ ├── @ CallNode (location: (39,0)-(39,19)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (39,0)-(39,3)) │ │ ├── flags: variable_call @@ -510,7 +510,7 @@ │ │ ├── flags: ∅ │ │ └── arguments: (length: 1) │ │ └── @ CallNode (location: (43,4)-(43,18)) - │ │ ├── flags: ∅ + │ │ ├── flags: attribute_write │ │ ├── receiver: │ │ │ @ CallNode (location: (43,4)-(43,7)) │ │ │ ├── flags: variable_call @@ -588,7 +588,7 @@ │ ├── closing_loc: (45,7)-(45,8) = "]" │ └── block: ∅ ├── @ CallNode (location: (47,0)-(47,14)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (47,0)-(47,3)) │ │ ├── flags: variable_call @@ -932,7 +932,7 @@ │ ├── opening_loc: (82,0)-(82,3) = "%w[" │ └── closing_loc: (82,6)-(82,7) = "]" ├── @ CallNode (location: (84,0)-(84,13)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (84,0)-(84,3)) │ │ ├── flags: variable_call @@ -970,7 +970,7 @@ │ │ └── block: ∅ │ └── operator_loc: (84,4)-(84,5) = "&" ├── @ CallNode (location: (86,0)-(86,17)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (86,0)-(86,7)) │ │ ├── flags: ∅ @@ -1038,7 +1038,7 @@ │ │ @ StatementsNode (location: (89,2)-(89,12)) │ │ └── body: (length: 1) │ │ └── @ CallNode (location: (89,2)-(89,12)) - │ │ ├── flags: ∅ + │ │ ├── flags: attribute_write │ │ ├── receiver: │ │ │ @ CallNode (location: (89,2)-(89,5)) │ │ │ ├── flags: variable_call @@ -1930,7 +1930,7 @@ │ │ @ StatementsNode (location: (132,10)-(132,18)) │ │ └── body: (length: 1) │ │ └── @ CallNode (location: (132,10)-(132,18)) - │ │ ├── flags: ∅ + │ │ ├── flags: attribute_write │ │ ├── receiver: │ │ │ @ CallNode (location: (132,10)-(132,11)) │ │ │ ├── flags: variable_call @@ -1986,7 +1986,7 @@ │ │ @ StatementsNode (location: (134,10)-(134,21)) │ │ └── body: (length: 1) │ │ └── @ CallNode (location: (134,10)-(134,21)) - │ │ ├── flags: ∅ + │ │ ├── flags: attribute_write │ │ ├── receiver: │ │ │ @ CallNode (location: (134,10)-(134,11)) │ │ │ ├── flags: variable_call diff --git a/test/prism/snapshots/method_calls.txt b/test/prism/snapshots/method_calls.txt index 772d4cadbfc53d..65f0d1df165adb 100644 --- a/test/prism/snapshots/method_calls.txt +++ b/test/prism/snapshots/method_calls.txt @@ -238,7 +238,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (21,0)-(21,11)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (21,0)-(21,3)) │ │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt b/test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt index c8478c368bb70b..c869af46072bb0 100644 --- a/test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt +++ b/test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,8)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,8)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ ConstantReadNode (location: (1,0)-(1,1)) │ └── name: :A diff --git a/test/prism/snapshots/seattlerb/attrasgn_array_arg.txt b/test/prism/snapshots/seattlerb/attrasgn_array_arg.txt index 3b09e172e76cf2..d9e557229210f4 100644 --- a/test/prism/snapshots/seattlerb/attrasgn_array_arg.txt +++ b/test/prism/snapshots/seattlerb/attrasgn_array_arg.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,13)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,13)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt b/test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt index 13615477dfcc69..9a41409dbb0a03 100644 --- a/test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt +++ b/test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,42)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,42)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ ArrayNode (location: (1,0)-(1,12)) │ ├── flags: ∅ diff --git a/test/prism/snapshots/seattlerb/attrasgn_primary_dot_constant.txt b/test/prism/snapshots/seattlerb/attrasgn_primary_dot_constant.txt index 4f22f3380a42e6..74faad33032cf3 100644 --- a/test/prism/snapshots/seattlerb/attrasgn_primary_dot_constant.txt +++ b/test/prism/snapshots/seattlerb/attrasgn_primary_dot_constant.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,7)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,7)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt b/test/prism/snapshots/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt index 3b53fee11e9f01..545f29a5324bf2 100644 --- a/test/prism/snapshots/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt +++ b/test/prism/snapshots/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(3,8)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(3,8)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/index_0.txt b/test/prism/snapshots/seattlerb/index_0.txt index 3be81b5435da6c..38a7d5d5c9cd22 100644 --- a/test/prism/snapshots/seattlerb/index_0.txt +++ b/test/prism/snapshots/seattlerb/index_0.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,7)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,7)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/safe_attrasgn.txt b/test/prism/snapshots/seattlerb/safe_attrasgn.txt index b29fef3febeb78..530ae743627e39 100644 --- a/test/prism/snapshots/seattlerb/safe_attrasgn.txt +++ b/test/prism/snapshots/seattlerb/safe_attrasgn.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,8)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,8)) - ├── flags: safe_navigation + ├── flags: safe_navigation, attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/seattlerb/safe_attrasgn_constant.txt b/test/prism/snapshots/seattlerb/safe_attrasgn_constant.txt index 39fb489e5eb3fe..c34b981d9d9d67 100644 --- a/test/prism/snapshots/seattlerb/safe_attrasgn_constant.txt +++ b/test/prism/snapshots/seattlerb/safe_attrasgn_constant.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,8)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,8)) - ├── flags: safe_navigation + ├── flags: safe_navigation, attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/unparser/corpus/literal/assignment.txt b/test/prism/snapshots/unparser/corpus/literal/assignment.txt index 7855e269743ba1..18edafe4153884 100644 --- a/test/prism/snapshots/unparser/corpus/literal/assignment.txt +++ b/test/prism/snapshots/unparser/corpus/literal/assignment.txt @@ -596,7 +596,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (29,0)-(29,19)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (29,0)-(29,3)) │ │ ├── name: :foo @@ -635,7 +635,7 @@ │ ├── closing_loc: (29,10)-(29,11) = "]" │ └── block: ∅ ├── @ CallNode (location: (30,0)-(30,17)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (30,0)-(30,3)) │ │ ├── name: :foo @@ -670,7 +670,7 @@ │ ├── closing_loc: (30,8)-(30,9) = "]" │ └── block: ∅ ├── @ CallNode (location: (31,0)-(31,9)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (31,0)-(31,3)) │ │ ├── name: :foo @@ -688,7 +688,7 @@ │ ├── closing_loc: (31,4)-(31,5) = "]" │ └── block: ∅ ├── @ CallNode (location: (32,0)-(32,17)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (32,0)-(32,3)) │ │ ├── name: :foo @@ -720,7 +720,7 @@ │ ├── closing_loc: (32,8)-(32,9) = "]" │ └── block: ∅ ├── @ CallNode (location: (33,0)-(33,18)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (33,0)-(33,3)) │ │ ├── name: :foo @@ -768,7 +768,7 @@ │ │ └── unescaped: "" │ └── operator_loc: (34,2)-(34,3) = "=" ├── @ CallNode (location: (35,0)-(35,7)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (35,0)-(35,1)) │ │ ├── name: :x @@ -790,7 +790,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (36,0)-(36,12)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (36,0)-(36,1)) │ │ ├── name: :x @@ -891,7 +891,7 @@ │ │ └── closing_loc: (41,0)-(42,0) = "HEREDOC\n" │ └── operator_loc: (39,2)-(39,3) = "=" ├── @ CallNode (location: (42,0)-(42,14)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (42,0)-(42,1)) │ │ ├── name: :x @@ -927,7 +927,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (45,0)-(45,16)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ LocalVariableReadNode (location: (45,0)-(45,1)) │ │ ├── name: :x diff --git a/test/prism/snapshots/unparser/corpus/literal/case.txt b/test/prism/snapshots/unparser/corpus/literal/case.txt index a228c4af407f57..be095579560e79 100644 --- a/test/prism/snapshots/unparser/corpus/literal/case.txt +++ b/test/prism/snapshots/unparser/corpus/literal/case.txt @@ -404,7 +404,7 @@ │ │ ├── operator_loc: (36,5)-(36,6) = "*" │ │ └── expression: │ │ @ CallNode (location: (36,6)-(36,15)) - │ │ ├── flags: ∅ + │ │ ├── flags: attribute_write │ │ ├── receiver: │ │ │ @ CallNode (location: (36,6)-(36,9)) │ │ │ ├── flags: variable_call diff --git a/test/prism/snapshots/unparser/corpus/literal/opasgn.txt b/test/prism/snapshots/unparser/corpus/literal/opasgn.txt index 764ae3adc2f1b9..cf7de993c1caaf 100644 --- a/test/prism/snapshots/unparser/corpus/literal/opasgn.txt +++ b/test/prism/snapshots/unparser/corpus/literal/opasgn.txt @@ -97,7 +97,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (9,0)-(9,17)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ ParenthesesNode (location: (9,0)-(9,10)) │ │ ├── body: diff --git a/test/prism/snapshots/unparser/corpus/literal/send.txt b/test/prism/snapshots/unparser/corpus/literal/send.txt index e0e27bc522aa2f..a96937e87ee7e6 100644 --- a/test/prism/snapshots/unparser/corpus/literal/send.txt +++ b/test/prism/snapshots/unparser/corpus/literal/send.txt @@ -1529,7 +1529,7 @@ │ ├── closing_loc: (68,25)-(68,26) = ")" │ └── block: ∅ ├── @ CallNode (location: (69,0)-(69,12)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (69,0)-(69,3)) │ │ ├── flags: variable_call @@ -1773,7 +1773,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (77,0)-(77,13)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ SelfNode (location: (77,0)-(77,4)) │ ├── call_operator_loc: (77,4)-(77,5) = "." diff --git a/test/prism/snapshots/whitequark/send_attr_asgn.txt b/test/prism/snapshots/whitequark/send_attr_asgn.txt index 948e52808b8b53..938fcf7541c8e6 100644 --- a/test/prism/snapshots/whitequark/send_attr_asgn.txt +++ b/test/prism/snapshots/whitequark/send_attr_asgn.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(7,10)) └── body: (length: 4) ├── @ CallNode (location: (1,0)-(1,9)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (1,0)-(1,3)) │ │ ├── flags: variable_call @@ -29,7 +29,7 @@ │ ├── closing_loc: ∅ │ └── block: ∅ ├── @ CallNode (location: (3,0)-(3,9)) - │ ├── flags: ∅ + │ ├── flags: attribute_write │ ├── receiver: │ │ @ CallNode (location: (3,0)-(3,3)) │ │ ├── flags: variable_call @@ -76,7 +76,7 @@ │ @ IntegerNode (location: (5,9)-(5,10)) │ └── flags: decimal └── @ CallNode (location: (7,0)-(7,10)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (7,0)-(7,3)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/whitequark/send_attr_asgn_conditional.txt b/test/prism/snapshots/whitequark/send_attr_asgn_conditional.txt index b29fef3febeb78..530ae743627e39 100644 --- a/test/prism/snapshots/whitequark/send_attr_asgn_conditional.txt +++ b/test/prism/snapshots/whitequark/send_attr_asgn_conditional.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,8)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,8)) - ├── flags: safe_navigation + ├── flags: safe_navigation, attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,1)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/whitequark/send_index_asgn.txt b/test/prism/snapshots/whitequark/send_index_asgn.txt index 3f550ea420ab22..34adbb1dde66c3 100644 --- a/test/prism/snapshots/whitequark/send_index_asgn.txt +++ b/test/prism/snapshots/whitequark/send_index_asgn.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,13)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,13)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,3)) │ ├── flags: variable_call diff --git a/test/prism/snapshots/whitequark/send_index_asgn_legacy.txt b/test/prism/snapshots/whitequark/send_index_asgn_legacy.txt index 3f550ea420ab22..34adbb1dde66c3 100644 --- a/test/prism/snapshots/whitequark/send_index_asgn_legacy.txt +++ b/test/prism/snapshots/whitequark/send_index_asgn_legacy.txt @@ -4,7 +4,7 @@ @ StatementsNode (location: (1,0)-(1,13)) └── body: (length: 1) └── @ CallNode (location: (1,0)-(1,13)) - ├── flags: ∅ + ├── flags: attribute_write ├── receiver: │ @ CallNode (location: (1,0)-(1,3)) │ ├── flags: variable_call