From e95a16e2e32ffb875319fb7521d7664a856bc163 Mon Sep 17 00:00:00 2001 From: Kaan Ozkan Date: Wed, 16 Aug 2023 13:11:16 -0400 Subject: [PATCH] Support block syntax in AllowIncompatibleOverride Co-authored-by: Alexandre Terrasa --- .../signatures/allow_incompatible_override.rb | 38 ++++++++++++++++--- .../allow_incompatible_override_spec.rb | 35 +++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb b/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb index 912da235..570ca8bb 100644 --- a/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb +++ b/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb @@ -23,25 +23,53 @@ class AllowIncompatibleOverride < RuboCop::Cop::Base "Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`" RESTRICT_ON_SEND = [:override].freeze - # @!method allow_incompatible_override?(node) - def_node_matcher(:allow_incompatible_override?, <<~PATTERN) + # @!method sig_dot_override?(node) + def_node_matcher(:sig_dot_override?, <<~PATTERN) (send - #sig? + [!nil? #sig?] :override (hash <$(pair (sym :allow_incompatible) true) ...>) ) PATTERN # @!method sig?(node) - def_node_search :sig?, <<~PATTERN + def_node_search(:sig?, <<~PATTERN) (send _ :sig ...) PATTERN + # @!method override?(node) + def_node_matcher(:override?, <<~PATTERN) + (send + _ + :override + (hash <$(pair (sym :allow_incompatible) true) ...>) + ) + PATTERN + def on_send(node) - allow_incompatible_override?(node) do |allow_incompatible_pair| + sig_dot_override?(node) do |allow_incompatible_pair| add_offense(allow_incompatible_pair) end end + + def on_block(node) + return unless sig?(node.send_node) + + block = node.children.last + return unless block.send_type? + + receiver = block.receiver + while receiver + allow_incompatible_pair = override?(receiver) + if allow_incompatible_pair + add_offense(allow_incompatible_pair) + break + end + receiver = receiver.receiver + end + end + + alias_method :on_numblock, :on_block end end end diff --git a/spec/rubocop/cop/sorbet/signatures/allow_incompatible_override_spec.rb b/spec/rubocop/cop/sorbet/signatures/allow_incompatible_override_spec.rb index 3bc893d5..c3131332 100644 --- a/spec/rubocop/cop/sorbet/signatures/allow_incompatible_override_spec.rb +++ b/spec/rubocop/cop/sorbet/signatures/allow_incompatible_override_spec.rb @@ -5,6 +5,14 @@ RSpec.describe(RuboCop::Cop::Sorbet::AllowIncompatibleOverride, :config) do let(:message) { RuboCop::Cop::Sorbet::AllowIncompatibleOverride::MSG } + it("allows using override(allow_incompatible: true) outside of sig") do + expect_no_offenses(<<~RUBY) + class Foo + override(allow_incompatible: true) + end + RUBY + end + it("disallows using override(allow_incompatible: true)") do expect_offense(<<~RUBY) class Foo @@ -14,6 +22,33 @@ class Foo RUBY end + it("disallows using override(allow_incompatible: true) with block syntax") do + expect_offense(<<~RUBY) + class Foo + sig { override(allow_incompatible: true).void } + ^^^^^^^^^^^^^^^^^^^^^^^^ #{message} + end + RUBY + end + + it("disallows using receiver and override(allow_incompatible: true) with block syntax") do + expect_offense(<<~RUBY) + class Foo + sig { recv.override(allow_incompatible: true).void } + ^^^^^^^^^^^^^^^^^^^^^^^^ #{message} + end + RUBY + end + + it("disallows using override(allow_incompatible: true) with block syntax and params") do + expect_offense(<<~RUBY) + class Foo + sig { override(allow_incompatible: true).params(a: Integer).void } + ^^^^^^^^^^^^^^^^^^^^^^^^ #{message} + end + RUBY + end + it("disallows using override(allow_incompatible: true) even when other keywords are present") do expect_offense(<<~RUBY) class Foo