Class: RuboCop::Cop::Lint::DuplicateMethods
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
::RuboCop::Cop::Base,
::RuboCop::ExcludeLimit,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
|
Instance Chain:
self,
::RuboCop::Cop::ProjectIndexHelp,
::RuboCop::Cop::Base,
::RuboCop::Cop::AutocorrectLogic,
::RuboCop::Cop::IgnoredNode,
::RuboCop::Util,
RuboCop::AST::Sexp
|
|
| Inherits: |
RuboCop::Cop::Base
|
| Defined in: | lib/rubocop/cop/lint/duplicate_methods.rb |
Overview
Checks for duplicated instance (or singleton) method definitions.
|
Note
|
Aliasing a method to itself is allowed, as it indicates that the developer intends to suppress Ruby’s method redefinition warnings. See https://bugs.ruby-lang.org/issues/13574. |
By default the cop can only detect duplicates within a single file.
When AllCops/UseProjectIndex is enabled and the rubydex gem is installed,
the cop additionally consults the project-wide index and reports methods
whose duplicate definition lives in another file.
|
Note
|
The project index does not record whether a definition in another file is wrapped in a conditional, so a platform-specific redefinition in another file may still be reported. Aliasing the method to itself (see above) before redefining marks the redefinition as intentional and is respected across files. |
Constant Summary
-
INDEXABLE_METHOD_NAME =
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 140
Method names the cop registers that can be looked up in the project index: a fully qualified namespace followed by
#(instance) or.(singleton) and the method name./\A(?<owner>[A-Z]\w*(?:::[A-Z]\w*)*)(?<separator>[#.])(?<name>[^#.]+)\z/.freeze
-
MSG =
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 135'Method `%<method>s` is defined at both %<defined>s and %<current>s.' -
RESTRICT_ON_SEND =
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 142%i[alias_method attr_reader attr_writer attr_accessor attr delegate def_delegator def_instance_delegator def_delegators def_instance_delegators].freeze
::RuboCop::Cop::Base - Inherited
EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::ProjectIndexHelp - Included
Class Attribute Summary
::RuboCop::Cop::Base - Inherited
| .gem_requirements, .lint?, | |
| .support_autocorrect? | Returns if class supports autocorrect. |
| .support_multiple_source? | Override if your cop should be called repeatedly for multiple investigations Between calls to #on_new_investigation and |
Class Method Summary
::RuboCop::Cop::Base - Inherited
| .autocorrect_incompatible_with | List of cops that should not try to autocorrect at the same time as this cop. |
| .badge | Naming. |
| .callbacks_needed, .cop_name, .department, | |
| .documentation_url | Returns a url to view this cops documentation online. |
| .exclude_from_registry | Call for abstract Cop classes. |
| .inherited, | |
| .joining_forces | Override and return the Force class(es) you need to join. |
| .match? | Returns true if the cop name or the cop namespace matches any of the given names. |
| .new, | |
| .requires_gem | Register a version requirement for the given gem name. |
| .restrict_on_send | |
::RuboCop::ExcludeLimit - Extended
| exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
| transform | |
Instance Attribute Summary
::RuboCop::Cop::Base - Inherited
::RuboCop::Cop::AutocorrectLogic - Included
Instance Method Summary
- #alias_method?(node)
- #class_new_block?(node)
- #class_or_module_new_block?(node)
- #delegate_method?(node)
- #delegator?(node)
- #delegators?(node)
- #method_alias?(node)
- #on_alias(node)
- #on_def(node)
- #on_defs(node)
- #on_new_investigation
-
#on_send(node)
Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity.
- #sym_name(node)
-
#anon_block_identity(anon_block)
private
Internal identity for an anonymous block, used as a scope key.
- #anon_block_scope_id(anon_block) private
- #anonymous_class_block(node) private
- #check_const_receiver(node, name, const_name) private
- #check_cross_file_duplicate(node, method_name) private
- #check_self_receiver(node, name) private
- #cross_file_prior_definition(method_name) private
-
#cross_file_self_alias_trick?(definitions) ⇒ Boolean
private
An alias of the method alongside one of its definitions in another file may be the self-alias trick marking an intentional redefinition there, so no offense is registered.
- #delegate_prefix(node) private
- #first_indexed_definition(definitions) private
- #found_attr(node, args, readable: false, writable: false) private
- #found_instance_method(node, name) private
- #found_method(node, method_name, scope_id: nil) private
- #found_redefinition(node, method_name, key, scope) private
- #found_sclass_method(node, name) private
- #hash_value(node, key) private
- #humanize_scope(scope) private
- #index_source_location(definition) private
- #indexed_declaration_definitions(namespace, name) private
- #indexed_definitions(owner, separator, name) private
- #inside_condition?(node) ⇒ Boolean private
-
#intentional_cross_file_redefinition?(node, method_name, key) ⇒ Boolean
private
The self-alias trick (
alias foo foooralias_method :foo, :fooright before adef) suppresses Ruby’s method redefinition warning, signaling an intentional redefinition of a method defined in another file. - #location(node) private
- #lookup_constant(node, const_name) private
- #message_for_dup(node, method_name, key) private
- #method_key(node, method_name) private
- #named_receiver(node) private
- #on_attr(node, attr_name, args) private
- #on_delegate(node, method_names) private
- #qualified_name(enclosing, namespace, mod_name) private
-
#scope_receiver(parent, anon_block)
private
When a Class.new block is passed as an argument to a named-receiver method call (e.g. T.cast(Class.new(Base) do …
- #source_location(node) private
- #track_self_alias(node, name) private
- #writer_attr_definition?(definition) ⇒ Boolean private
::RuboCop::Cop::ProjectIndexHelp - Included
| #external_dependency_checksum, #compute_project_index_signature, | |
| #definitions_in_other_files | Returns the definitions among |
| #indexed_singleton_member | A namespace without any singleton method has no singleton-class declaration of its own, so the lookup starts from the first ancestor that has one; its |
| #indexed_singleton_of | The declaration of `declaration’s singleton class, or nil when no singleton method is defined on it anywhere in the project. |
| #inherited_index_member? | Whether an ancestor of |
| #lexical_nesting_of | The lexical nesting the node’s constants resolve through, outermost first. |
| #prior_definition_in_other_file, #project_index_signature, | |
| #resolve_constant_in_index | Resolves a constant node the way Ruby does: the first segment through the lexical nesting and every following segment inside the previous one. |
| #same_file? | |
::RuboCop::Cop::Base - Inherited
| #add_global_offense | Adds an offense that has no particular location. |
| #add_offense | Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense. |
| #begin_investigation | Called before any investigation. |
| #callbacks_needed, | |
| #cop_config | Configuration Helpers. |
| #cop_name, #excluded_file?, | |
| #external_dependency_checksum | This method should be overridden when a cop’s behavior depends on state that lives outside of these locations: |
| #inspect, | |
| #message | Gets called if no message is specified when calling |
| #name | Alias for Base#cop_name. |
| #offenses, | |
| #on_investigation_end | Called after all on_… |
| #on_new_investigation | Called before all on_… |
| #on_other_file | Called instead of all on_… |
| #parse | There should be very limited reasons for a Cop to do it’s own parsing. |
| #parser_engine, | |
| #ready | Called between investigations. |
| #relevant_file?, | |
| #target_gem_version | Returns a gems locked versions (i.e. |
| #target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
| #callback_argument | Reserved for Cop::Cop. |
| #complete_investigation | Called to complete an investigation. |
| #correct, #current_corrector, | |
| #current_offense_locations | Reserved for Commissioner: |
| #current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #matches_absolute_include_pattern?, #range_for_original, #range_from_node_or_range, | |
| #reset_investigation | Actually private methods. |
| #use_corrector | |
::RuboCop::Cop::AutocorrectLogic - Included
::RuboCop::Cop::IgnoredNode - Included
Constructor Details
.new(config = nil, options = nil) ⇒ DuplicateMethods
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 146
def initialize(config = nil, = nil) super @definitions = {} @scopes = Hash.new { |hash, key| hash[key] = [] } @self_aliased = Set.new end
Instance Method Details
#alias_method?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 198
def_node_matcher :alias_method?, <<~PATTERN (send nil? :alias_method (sym $_name) (sym $_original_name)) PATTERN
#anon_block_identity(anon_block) (private)
Internal identity for an anonymous block, used as a scope key.
Includes the source range’s begin position to distinguish blocks
that share the same line (e.g. two Class.new calls separated by ;).
The user-facing offense message still uses #source_location, which
shows only path:line.
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 589
def anon_block_identity(anon_block) range = anon_block.source_range "#{smart_path(range.source_buffer.name)}:#{range.line}:#{range.begin_pos}" end
#anon_block_scope_id(anon_block) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 358
def anon_block_scope_id(anon_block) parent = anon_block.parent return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def) if (receiver = scope_receiver(parent, anon_block)) "#{receiver.source}.#{parent.method_name}" elsif !parent.begin_type? || parent.parent&.any_block_type? anon_block_identity(anon_block) end end
#anonymous_class_block(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 349
def anonymous_class_block(node) first_block = node.each_ancestor(:block).first return unless class_or_module_new_block?(first_block) return if first_block.parent&.type?(:lvasgn) return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? } first_block end
#check_const_receiver(node, name, const_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 275
def check_const_receiver(node, name, const_name) qualified = lookup_constant(node, const_name) return unless qualified found_method(node, "#{qualified}.#{name}") end
#check_cross_file_duplicate(node, method_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 516
def check_cross_file_duplicate(node, method_name) return unless project_index return if @self_aliased.include?(method_name) return if node.each_ancestor(:any_def).any? return unless (prior = cross_file_prior_definition(method_name)) = format(MSG, method: method_name, defined: index_source_location(prior), current: source_location(node)) add_offense(location(node), message: ) end
#check_self_receiver(node, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 282
def check_self_receiver(node, name) enclosing = node.parent_module_name if enclosing found_method(node, "#{enclosing}.#{name}") elsif (anon_block = anonymous_class_block(node)) scope = qualified_name(anon_block.parent_module_name, nil, 'Object') found_method(node, "#{scope}.#{name}", scope_id: anon_block_scope_id(anon_block)) end end
#class_new_block?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 239
def_node_matcher :class_new_block?, <<~PATTERN (block (send (const _ :Class) :new ...) ...) PATTERN
#class_or_module_new_block?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 232
def_node_matcher :class_or_module_new_block?, <<~PATTERN (block (send (const _ {:Class :Module}) :new ...) ...) PATTERN
#cross_file_prior_definition(method_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 528
def cross_file_prior_definition(method_name) return unless (match = INDEXABLE_METHOD_NAME.match(method_name)) definitions = definitions_in_other_files( indexed_definitions(match[:owner], match[:separator], match[:name]) ) return if definitions.empty? || cross_file_self_alias_trick?(definitions) first_indexed_definition(definitions) end
#cross_file_self_alias_trick?(definitions) ⇒ Boolean (private)
An alias of the method alongside one of its definitions in another file may be
the self-alias trick marking an intentional redefinition there, so no offense
is registered. A genuine alias duplicate is still reported when the alias
itself is inspected.
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 566
def cross_file_self_alias_trick?(definitions) aliases, others = definitions.partition do |definition| definition.is_a?(Rubydex::MethodAliasDefinition) end alias_paths = aliases.map { |definition| definition.location.to_file_path } others.any? { |definition| alias_paths.include?(definition.location.to_file_path) } end
#delegate_method?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 203
def_node_matcher :delegate_method?, <<~PATTERN (send nil? :delegate ({sym str} $_)+ (hash <(pair (sym :to) {sym str}) ...>) ) PATTERN
#delegate_prefix(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 311
def delegate_prefix(node) kwargs_node = node.last_argument return unless (prefix = hash_value(kwargs_node, :prefix)) if prefix.true_type? hash_value(kwargs_node, :to).value elsif prefix.type?(:sym, :str) prefix.value end end
#delegator?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 211
def_node_matcher :delegator?, <<~PATTERN (send nil? {:def_delegator :def_instance_delegator} { {sym str} ({sym str} $_) | {sym str} {sym str} ({sym str} $_) } ) PATTERN
#delegators?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 221
def_node_matcher :delegators?, <<~PATTERN (send nil? {:def_delegators :def_instance_delegators} {sym str} ({sym str} $_)+ ) PATTERN
#first_indexed_definition(definitions) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 575
def first_indexed_definition(definitions) definitions.find { |definition| !definition.is_a?(Rubydex::MethodAliasDefinition) } end
#found_attr(node, args, readable: false, writable: false) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 468
def found_attr(node, args, readable: false, writable: false) args.each do |arg| name = sym_name(arg) next unless name found_instance_method(node, name) if readable found_instance_method(node, "#{name}=") if writable end end
#found_instance_method(node, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 327
def found_instance_method(node, name) if (scope = node.parent_module_name) found_method(node, "#{humanize_scope(scope)}#{name}") elsif (anon_block = anonymous_class_block(node)) base = qualified_name(anon_block.parent_module_name, nil, 'Object') scope = node.each_ancestor(:sclass).any? ? "#<Class:#{base}>" : base found_method( node, "#{humanize_scope(scope)}#{name}", scope_id: anon_block_scope_id(anon_block) ) else found_sclass_method(node, name) end end
#found_method(node, method_name, scope_id: nil) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 398
def found_method(node, method_name, scope_id: nil) key = method_key(node, method_name) key = "#{key}@#{scope_id}" if scope_id scope = node.each_ancestor(:rescue, :ensure).first&.type if @definitions.key?(key) found_redefinition(node, method_name, key, scope) else @definitions[key] = node check_cross_file_duplicate(node, method_name) if scope_id.nil? && scope.nil? end end
#found_redefinition(node, method_name, key, scope) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 411
def found_redefinition(node, method_name, key, scope) if scope && !@scopes[scope].include?(key) @definitions[key] = node @scopes[scope] << key elsif intentional_cross_file_redefinition?(node, method_name, key) @definitions[key] = node else add_offense(location(node), message: (node, method_name, key)) end end
#found_sclass_method(node, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 388
def found_sclass_method(node, name) singleton_ancestor = node.each_ancestor.find(&:sclass_type?) return unless singleton_ancestor singleton_receiver_node = singleton_ancestor.children[0] return unless singleton_receiver_node.send_type? found_method(node, "#{singleton_receiver_node.method_name}.#{name}") end
#hash_value(node, key) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 323
def hash_value(node, key) node.pairs.find { |pair| pair.key.value == key }&.value end
#humanize_scope(scope) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 341
def humanize_scope(scope) scope = scope.sub( /(?:(?<name>.*)::)#<Class:\k<name>>|#<Class:(?<name>.*)>(?:::)?/, '\k<name>.' ) scope.end_with?('.') ? scope : "#{scope}#" end
#index_source_location(definition) (private)
[ GitHub ]#indexed_declaration_definitions(namespace, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 553
def indexed_declaration_definitions(namespace, name) project_index["#{namespace}##{name}()"]&.definitions.to_a end
#indexed_definitions(owner, separator, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 539
def indexed_definitions(owner, separator, name) namespace = separator == '.' ? "#{owner}::<#{owner.split('::').last}>" : owner if name.match?(/\A\w+=\z/) # Rubydex indexes `attr_writer :foo` under `foo` rather than `foo=`, so # writer definitions come from both the `foo=` and the `foo` declarations. indexed_declaration_definitions(namespace, name) + indexed_declaration_definitions(namespace, name.delete_suffix('=')) .select { |definition| writer_attr_definition?(definition) } else indexed_declaration_definitions(namespace, name).grep_v(Rubydex::AttrWriterDefinition) end end
#inside_condition?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 292
def inside_condition?(node) node.ancestors.any?(&:if_type?) end
#intentional_cross_file_redefinition?(node, method_name, key) ⇒ Boolean (private)
The self-alias trick (alias foo foo or alias_method :foo, :foo right before
a def) suppresses Ruby’s method redefinition warning, signaling an intentional
redefinition of a method defined in another file.
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 425
def intentional_cross_file_redefinition?(node, method_name, key) @self_aliased.include?(method_name) && @definitions[key].source_range.source_buffer.name != node.source_range.source_buffer.name end
#location(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 446
def location(node) if node.any_def_type? node.loc.keyword.join(node.loc.name) else node.source_range end end
#lookup_constant(node, const_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 478
def lookup_constant(node, const_name) # this method is quite imperfect and can be fooled # to do much better, we would need to do global analysis of the whole # codebase node.each_ancestor(:class, :module, :casgn) do |ancestor| namespace, mod_name = *ancestor.defined_module loop do if mod_name == const_name return qualified_name(ancestor.parent_module_name, namespace, mod_name) end break if namespace.nil? namespace, mod_name = *namespace end end end
#message_for_dup(node, method_name, key) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 296
def (node, method_name, key) format(MSG, method: method_name, defined: source_location(@definitions[key]), current: source_location(node)) end
#method_alias?(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 180
def_node_matcher :method_alias?, <<~PATTERN (alias (sym $_name) (sym $_original_name)) PATTERN
#method_key(node, method_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 438
def method_key(node, method_name) if (ancestor_def = node.each_ancestor(:any_def).first) "#{ancestor_def.method_name}.#{method_name}" else method_name end end
#named_receiver(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 383
def named_receiver(node) receiver = node.receiver receiver unless class_or_module_new_block?(receiver) end
#on_alias(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 184
def on_alias(node) name, original_name = method_alias?(node) return unless name && original_name if name == original_name track_self_alias(node, name) return end return if node.ancestors.any?(&:if_type?) found_instance_method(node, name) end
#on_attr(node, attr_name, args) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 454
def on_attr(node, attr_name, args) case attr_name when :attr writable = args.size == 2 && args.last.true_type? found_attr(node, [args.first], readable: true, writable: writable) when :attr_reader found_attr(node, args, readable: true) when :attr_writer found_attr(node, args, writable: true) when :attr_accessor found_attr(node, args, readable: true, writable: true) end end
#on_def(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 160
def on_def(node) # if a method definition is inside an if, it is very likely # that a different definition is used depending on platform, etc. return if node.each_ancestor.any?(&:if_type?) found_instance_method(node, node.method_name) end
#on_defs(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 168
def on_defs(node) return if node.each_ancestor.any?(&:if_type?) if node.receiver.const_type? _, const_name = *node.receiver check_const_receiver(node, node.method_name, const_name) elsif node.receiver.self_type? check_self_receiver(node, node.method_name) end end
#on_delegate(node, method_names) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 301
def on_delegate(node, method_names) name_prefix = delegate_prefix(node) method_names.each do |name| name = "#{name_prefix}_#{name}" if name_prefix found_instance_method(node, name) end end
#on_new_investigation
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 153
def on_new_investigation # The self-alias trick declares an intentional redefinition only within # the file that uses it, so the tracked names do not carry over. @self_aliased = Set.new super end
#on_send(node)
Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 245
def on_send(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity name, original_name = alias_method?(node) if name && original_name if name == original_name track_self_alias(node, name) return end return if inside_condition?(node) found_instance_method(node, name) elsif (attr = node.attribute_accessor?) on_attr(node, *attr) elsif active_support_extensions_enabled? && (names = delegate_method?(node)) return if inside_condition?(node) on_delegate(node, names) elsif (name = delegator?(node)) return if inside_condition?(node) found_instance_method(node, name) elsif (names = delegators?(node)) return if inside_condition?(node) names.each { |name| found_instance_method(node, name) } end end
#qualified_name(enclosing, namespace, mod_name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 496
def qualified_name(enclosing, namespace, mod_name) if enclosing != 'Object' if namespace "#{enclosing}::#{namespace.const_name}::#{mod_name}" else "#{enclosing}::#{mod_name}" end elsif namespace "#{namespace.const_name}::#{mod_name}" else mod_name end end
#scope_receiver(parent, anon_block) (private)
When a Class.new block is passed as an argument to a named-receiver method call (e.g. T.cast(Class.new(Base) do … end, …)), the receiver-based scope id (e.g. "T.cast") is the same for every call, causing false positives for methods defined in distinct anonymous classes. Return nil so the block falls through to the unique source-location-based scope id. Module.new blocks are excluded because they may be intentionally mixed into the same target via prepend/include/extend.
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 377
def scope_receiver(parent, anon_block) return if class_new_block?(anon_block) && parent.call_type? named_receiver(parent) end
#source_location(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 510
def source_location(node) range = node.source_range path = smart_path(range.source_buffer.name) "#{path}:#{range.line}" end
#sym_name(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 229
def_node_matcher :sym_name, '(sym $_name)'
#track_self_alias(node, name) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 431
def track_self_alias(node, name) scope = node.parent_module_name return unless scope @self_aliased << "#{humanize_scope(scope)}#{name}" end
#writer_attr_definition?(definition) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/duplicate_methods.rb', line 557
def writer_attr_definition?(definition) definition.is_a?(Rubydex::AttrWriterDefinition) || definition.is_a?(Rubydex::AttrAccessorDefinition) end