rubocop/rubocop-ast

Unification does not work inside any-order node

Opened this issue · 2 comments

I'm trying to match something along the lines of:

(or <(send _receiver :bar) (send _receiver :baz)>)

However, the unification matches foo.baz || foo.bar but not foo.bar || foo.baz.

If the unification is removed:

(or <send _ :bar) (send _ :baz)>)

both forms match.

I tried looking into this but I'm not really sure how to fix it. I wrote some test cases though:

Index: spec/rubocop/ast/node_pattern_spec.rb
<+>UTF-8
===================================================================
diff --git a/spec/rubocop/ast/node_pattern_spec.rb b/spec/rubocop/ast/node_pattern_spec.rb
--- a/spec/rubocop/ast/node_pattern_spec.rb	(revision 1feb3b8216f0eb1079fd4f0c91480df8e63906d9)
+++ b/spec/rubocop/ast/node_pattern_spec.rb	(date 1731087767421)
@@ -1696,6 +1696,44 @@
       end
     end
 
+    context 'with unification' do
+      let(:ruby) { 'foo.bar || foo.baz' }
+
+      context 'without capture' do
+        let(:pattern) { '(or <(send _receiver :bar) (send _receiver :baz)>)' }
+
+        it { expect(pattern).to match_code(node) }
+      end
+
+      context 'when reference matches in reverse' do
+        let(:ruby) { 'foo.baz || foo.bar' }
+        let(:pattern) { '(or <(send _receiver :bar) (send _receiver :baz)>)' }
+
+        it { expect(pattern).to match_code(node) }
+      end
+
+      context 'when reference does not match' do
+        let(:ruby) { 'foo.bar || bar.baz' }
+        let(:pattern) { '(or <(send _receiver :bar) (send _receiver :baz)>)' }
+
+        it_behaves_like 'nonmatching'
+      end
+
+      context 'with single capture' do
+        let(:pattern) { '(or <(send $_receiver :bar) (send _receiver :baz)>)' }
+        let(:captured_val) { s(:send, nil, :foo) }
+
+        it_behaves_like 'single capture'
+      end
+
+      context 'with multiple capture' do
+        let(:pattern) { '(or <(send $_receiver :bar) (send $_receiver :baz)>)' }
+        let(:captured_vals) { [s(:send, nil, :foo), s(:send, nil, :foo)] }
+
+        it_behaves_like 'multiple capture'
+      end
+    end
+

Good catch. Agreed it's a bug. I'll have to check the code. Thanks for the issue and the test