Class: RuboCop::Cop::Lint::MissingSuper

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

Overview

Checks for the presence of constructors and lifecycle callbacks without calls to super.

This cop does not consider method_missing (and respond_to_missing?) because in some cases it makes sense to overtake what is considered a missing method. In other cases, the theoretical ideal handling could be challenging or verbose for no actual gain.

Autocorrection is not supported because the position of super cannot be determined automatically.

Object and BasicObject are allowed by this cop because of their stateless nature. However, sometimes you might want to allow other parent classes from this cop, for example in the case of an abstract class that is not meant to be called with super. In those cases, you can use the AllowedParentClasses option to specify which classes should be allowed in addition to Object and BasicObject.

When AllCops/UseProjectIndex is enabled and the rubydex gem is installed, the constructor check additionally consults the project-wide index: if the class' entire ancestry is resolvable and no ancestor defines initialize, no offense is registered, since super would only reach the no-op Object#initialize. Classes whose ancestry contains an unresolvable superclass or mixin (e.g. one defined in a gem) are still reported.

Examples:

# bad
class Employee < Person
  def initialize(name, salary)
    @salary = salary
  end
end

# good
class Employee < Person
  def initialize(name, salary)
    super(name)
    @salary = salary
  end
end

# bad
Employee = Class.new(Person) do
  def initialize(name, salary)
    @salary = salary
  end
end

# good
Employee = Class.new(Person) do
  def initialize(name, salary)
    super(name)
    @salary = salary
  end
end

# bad
class Parent
  def self.inherited(base)
    do_something
  end
end

# good
class Parent
  def self.inherited(base)
    super
    do_something
  end
end

# good
class ClassWithNoParent
  def initialize
    do_something
  end
end

AllowedParentClasses: [MyAbstractClass]

# good
class MyConcreteClass < MyAbstractClass
  def initialize
    do_something
  end
end

Constant Summary collapse

CONSTRUCTOR_MSG =
'Call `super` to initialize state of the parent class.'
CALLBACK_MSG =
'Call `super` to invoke callback defined in the parent class.'
STATELESS_CLASSES =
%w[BasicObject Object].freeze
CLASS_LIFECYCLE_CALLBACKS =
%i[inherited].freeze
METHOD_LIFECYCLE_CALLBACKS =
%i[method_added method_removed method_undefined
singleton_method_added singleton_method_removed
singleton_method_undefined].freeze
CALLBACKS =
(CLASS_LIFECYCLE_CALLBACKS + METHOD_LIFECYCLE_CALLBACKS).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

Instance Attribute Summary

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_new_investigation, #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?

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

Instance Method Details

#class_new_block(node) ⇒ Object



108
109
110
111
112
# File 'lib/rubocop/cop/lint/missing_super.rb', line 108

def_node_matcher :class_new_block, <<~RUBY
  (any_block
    (send
      (const {nil? cbase} :Class) :new $_) ...)
RUBY

#on_def(node) ⇒ Object



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

def on_def(node)
  return unless offender?(node)

  if node.method?(:initialize) && inside_class_with_stateful_parent?(node)
    add_offense(node, message: CONSTRUCTOR_MSG)
  elsif callback_method_def?(node)
    add_offense(node, message: CALLBACK_MSG)
  end
end

#on_defs(node) ⇒ Object



124
125
126
127
128
# File 'lib/rubocop/cop/lint/missing_super.rb', line 124

def on_defs(node)
  return if !callback_method_def?(node) || contains_super?(node)

  add_offense(node, message: CALLBACK_MSG)
end