diff --git a/changelog/fix_a_false_positive_double_negation.md b/changelog/fix_a_false_positive_double_negation.md new file mode 100644 index 00000000000..ce5d279c0dc --- /dev/null +++ b/changelog/fix_a_false_positive_double_negation.md @@ -0,0 +1 @@ +* [#10586](https://github.com/rubocop/rubocop/issues/10586): Fix a false positive for `Style/DoubleNegation` when using `define_method` or `define_singleton_method`. ([@ydah][]) diff --git a/lib/rubocop/cop/style/double_negation.rb b/lib/rubocop/cop/style/double_negation.rb index 9d0e0182194..a302cb03a6b 100644 --- a/lib/rubocop/cop/style/double_negation.rb +++ b/lib/rubocop/cop/style/double_negation.rb @@ -37,11 +37,27 @@ module Style # !!return_value # end # + # define_method :foo? do + # !!return_value + # end + # + # define_singleton_method :foo? do + # !!return_value + # end + # # @example EnforcedStyle: forbidden # # bad # def foo? # !!return_value # end + # + # define_method :foo? do + # !!return_value + # end + # + # define_singleton_method :foo? do + # !!return_value + # end class DoubleNegation < Base include ConfigurableEnforcedStyle extend AutoCorrector @@ -73,22 +89,32 @@ def end_of_method_definition?(node) return false unless (def_node = find_def_node_from_ascendant(node)) conditional_node = find_conditional_node_from_ascendant(node) - last_child = find_last_child(def_node.body) + last_child = find_last_child(def_node.send_type? ? def_node : def_node.body) if conditional_node double_negative_condition_return_value?(node, last_child, conditional_node) else - last_child.last_line == node.last_line + last_child.last_line <= node.last_line end end def find_def_node_from_ascendant(node) return unless (parent = node.parent) return parent if parent.def_type? || parent.defs_type? + return node.parent.child_nodes.first if define_mehod?(parent) find_def_node_from_ascendant(node.parent) end + def define_mehod?(node) + return false unless node.block_type? + + child = node.child_nodes.first + return false unless child.send_type? + + child.method?(:define_method) || child.method?(:define_singleton_method) + end + def find_conditional_node_from_ascendant(node) return unless (parent = node.parent) return parent if parent.conditional? diff --git a/spec/rubocop/cop/style/double_negation_spec.rb b/spec/rubocop/cop/style/double_negation_spec.rb index 149ff602eef..780fde67b29 100644 --- a/spec/rubocop/cop/style/double_negation_spec.rb +++ b/spec/rubocop/cop/style/double_negation_spec.rb @@ -352,6 +352,24 @@ def foo? RUBY end + it 'does not register an offense for `!!` when return location by `define_method`' do + expect_no_offenses(<<~RUBY) + define_method :foo? do + bar + !!qux + end + RUBY + end + + it 'does not register an offense for `!!` when return location by `define_singleton_method`' do + expect_no_offenses(<<~RUBY) + define_singleton_method :foo? do + bar + !!qux + end + RUBY + end + it 'does not register an offense for `!!` when return location and using `rescue`' do expect_no_offenses(<<~RUBY) def foo?