From 257805104ab21666085d5f12a3d3f8802c9880b0 Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Wed, 15 Jan 2020 21:34:37 +0900 Subject: [PATCH] Detect safe navigation operator as a method call --- lib/querly/pattern/expr.rb | 12 +++++++----- test/pattern_test_test.rb | 39 ++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/lib/querly/pattern/expr.rb b/lib/querly/pattern/expr.rb index dd78762..a65c8c8 100644 --- a/lib/querly/pattern/expr.rb +++ b/lib/querly/pattern/expr.rb @@ -147,7 +147,8 @@ def initialize(receiver:, name:, block:, args: Argument::AnySeq.new) def =~(pair) # Skip send node with block - if pair.node.type == :send && pair.parent + type = pair.node.type + if (type == :send || type == :csend) && pair.parent if pair.parent.node.type == :block if pair.parent.node.children.first.equal? pair.node return false @@ -176,7 +177,7 @@ def test_node(node) node = node.children.first if node&.type == :block case node&.type - when :send + when :send, :csend return false unless test_name(node) return false unless test_receiver(node.children[0]) return false unless test_args(node.children.drop(2), args) @@ -290,7 +291,8 @@ def test_node(node) if receiver.test_node(node) true else - node&.type == :send && test_node(node.children[0]) + type = node&.type + (type == :send || type == :csend) && test_node(node.children[0]) end end end @@ -315,7 +317,7 @@ def =~(pair) # We don't want lvar without method call # Skips when the node is not receiver of :send parent_node = pair.parent&.node - if parent_node && parent_node.type == :send && parent_node.children.first.equal?(node) + if parent_node && (parent_node.type == :send || parent_node.type == :csend) && parent_node.children.first.equal?(node) test_node(node) end else @@ -325,7 +327,7 @@ def =~(pair) def test_node(node) case node&.type - when :send + when :send, :csend node.children[1] == name when :lvar node.children.first == name diff --git a/test/pattern_test_test.rb b/test/pattern_test_test.rb index 1367271..7d06fd1 100644 --- a/test/pattern_test_test.rb +++ b/test/pattern_test_test.rb @@ -241,40 +241,42 @@ def test_call_with_names end def test_call_without_receiver - nodes = query_pattern("foo", "foo; bar.foo") - assert_equal 2, nodes.size + nodes = query_pattern("foo", "foo; bar.foo; bar&.foo") + assert_equal 3, nodes.size end def test_call_with_any_receiver - nodes = query_pattern("_.foo", "foo; bar.foo") - assert_equal 1, nodes.size - assert_equal ruby("bar.foo"), nodes.first + nodes = query_pattern("_.foo", "foo; bar.foo; bar&.foo") + assert_equal 2, nodes.size + assert_equal [ruby("bar.foo"), ruby("bar&.foo")], nodes end def test_call_any_method - nodes = query_pattern("foo._", "foo; foo.bar; foo.baz") - assert_equal 2, nodes.size - assert_equal [ruby("foo.bar"), ruby("foo.baz")], nodes + nodes = query_pattern("foo._", "foo; foo.bar; foo.baz; foo&.baz") + assert_equal 3, nodes.size + assert_equal [ruby("foo.bar"), ruby("foo.baz"), ruby("foo&.baz")], nodes end def test_call_any_method_with_args - nodes = query_pattern("foo._(baz)", "foo.bar(baz); foo.bar(bar)") - assert_equal 1, nodes.size - assert_equal ruby("foo.bar(baz)"), nodes.first + nodes = query_pattern("foo._(baz)", "foo.bar(baz); foo.bar(bar); foo&.bar(baz)") + assert_equal 2, nodes.size + assert_equal [ruby("foo.bar(baz)"), ruby("foo&.bar(baz)")], nodes end def test_call_any_method_with_block - nodes = query_pattern("foo._{}", "foo.bar; foo.baz{}") - assert_equal 1, nodes.size - assert_equal ruby("foo.baz{}"), nodes.first + nodes = query_pattern("foo._{}", "foo.bar; foo.baz{}; foo&.foobar{}") + assert_equal 2, nodes.size + assert_equal [ruby("foo.baz{}"), ruby("foo&.foobar{}")], nodes end def test_vcall # Vcall pattern matches with local variable - nodes = query_pattern("foo", "foo = 1; foo.bar") - assert_equal 1, nodes.size + nodes = query_pattern("foo", "foo = 1; foo.bar; foo&.bar") + assert_equal 2, nodes.size assert_equal :lvar, nodes.first.type assert_equal :foo, nodes.first.children.first + assert_equal :lvar, nodes[1].type + assert_equal :foo, nodes[1].children.first end def test_vcall2 @@ -345,6 +347,11 @@ def test_any_receiver5 assert_equal Set.new([ruby("a.b.b"), ruby("a.b")]), Set.new(nodes) end + def test_any_receiver6 + nodes = query_pattern("f...h", "f&.g&.h") + assert_equal [ruby("f&.g&.h")], nodes + end + def test_self nodes = query_pattern("self.f", "f(); self.f(); foo.f()") assert_equal Set.new([ruby("self.f"), ruby("f()")]), Set.new(nodes)