Class: RuboCop::Cop::Lint::UnusedPrivateMethod

Inherits:
Base
  • Object
show all
Includes:
AllowedPattern, ProjectIndexHelp
Defined in:
lib/rubocop/cop/lint/unused_private_method.rb

Overview

Checks for private instance methods that are not referenced anywhere in the project.

The check is powered by the project-wide index, so it only runs when AllCops/UseProjectIndex is enabled and the rubydex gem is installed. Without the index the cop does nothing.

A method counts as referenced when a call with its name appears anywhere in the indexed project (regardless of the receiver), when it is the source of an alias, or when its name appears in the same file as a symbol or inside a string literal (covering send(:name) and declarative DSLs like before_action :name). An interpolated symbol or string with a literal prefix (e.g. send(:"format_#{type}")) counts as a reference to every method whose name starts with that prefix; fully dynamic names cannot be detected. Methods defined in classes or modules with descendants are not checked, since they may be invoked through super or inherited dispatch.

Methods whose names are composed by a framework (e.g. Rails attribute_method_suffix generating attribute? methods) can be excluded from the check with AllowedNames (exact names) or AllowedPatterns (regular expressions).

The cop is disabled by default because symbol-based references from other files (e.g. a Rails callback declared in a concern) cannot be detected and would be reported as false positives. It is best suited for occasional dead-code sweeps rather than permanent enforcement.

Examples:

# bad - `helper` is never referenced anywhere in the project
class Service
  def call
    do_something
  end

  private

  def helper
  end
end

# good
class Service
  def call
    do_something(helper)
  end

  private

  def helper
  end
end

AllowedNames: ['attribute?']

# good - the name is explicitly allowed
class Contact
  private

  def attribute?
  end
end

AllowedPatterns: ['_hook\z']

# good - the name matches an allowed pattern
class Service
  private

  def before_save_hook
  end
end

Constant Summary collapse

MSG =
'Private method `%<method>s` appears to be unused.'
IDENTIFIER_PATTERN =
/[a-zA-Z_]\w*[?!=]?/.freeze
NAME_PREFIX_PATTERN =
/[a-zA-Z_]\w*\z/.freeze
IMPLICITLY_INVOKED_METHODS =

Methods invoked implicitly by the Ruby runtime.

%i[
  initialize initialize_copy initialize_clone initialize_dup
  method_missing respond_to_missing? marshal_dump marshal_load
  coerce instance_variables_to_inspect
  inherited included extended prepended
  append_features extend_object prepend_features
  const_missing const_added
  method_added method_removed method_undefined
  singleton_method_added singleton_method_removed singleton_method_undefined
].to_set.freeze

Constants included from ProjectIndexHelp

ProjectIndexHelp::BUILTIN_DOCUMENT_URI, ProjectIndexHelp::FILE_URI_PREFIX, ProjectIndexHelp::WINDOWS_DRIVE_PREFIX

Constants inherited from Base

Base::RESTRICT_ON_SEND

Class Attribute Summary collapse

Attributes inherited from Base

#config, #processed_source, #project_index

Instance Method Summary collapse

Methods included from ProjectIndexHelp

#external_dependency_checksum

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

cop_dir_for, #exclude_limit, read_limits

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?, #skipped_unsafe_correction_with_disable_uncorrectable?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Class Attribute Details

.cached_reference_namesObject

The reference-name set is a property of the index, not of the cop instance, so all per-file instances share one computation. A single-entry cache (instead of a hash keyed by index) avoids retaining stale graphs in long-lived processes.



103
104
105
# File 'lib/rubocop/cop/lint/unused_private_method.rb', line 103

def cached_reference_names
  @cached_reference_names
end

Instance Method Details

#on_def(node) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rubocop/cop/lint/unused_private_method.rb', line 112

def on_def(node)
  return unless project_index

  declaration = checkable_declaration(node)
  return unless declaration
  return if referenced?(node.method_name)
  return if owner_with_descendants?(declaration) || override?(declaration, node.method_name)

  message = format(MSG, method: node.method_name)
  add_offense(node.loc.keyword.join(node.loc.name), message: message)
end

#on_new_investigationObject



106
107
108
109
110
# File 'lib/rubocop/cop/lint/unused_private_method.rb', line 106

def on_new_investigation
  @literal_names = nil
  @literal_name_prefixes = nil
  super
end