Class: RuboCop::Cop::Lint::RedundantTypeConversion

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Defined in:
lib/rubocop/cop/lint/redundant_type_conversion.rb

Overview

Checks for redundant uses of ‘to_s`, `to_sym`, `to_i`, `to_f`, `to_d`, `to_r`, `to_c`, `to_a`, `to_h`, and `to_set`.

When one of these methods is called on an object of the same type, that object is returned, making the call unnecessary. The cop detects conversion methods called on object literals, class constructors, class ‘[]` methods, and the `Kernel` methods `String()`, `Integer()`, `Float()`, BigDecimal(), `Rational()`, `Complex()`, and `Array()`.

Specifically, these cases are detected for each conversion method:

  • ‘to_s` when called on a string literal, interpolated string, heredoc, or with `String.new` or `String()`.

  • ‘to_sym` when called on a symbol literal or interpolated symbol.

  • ‘to_i` when called on an integer literal or with `Integer()`.

  • ‘to_f` when called on a float literal of with `Float()`.

  • ‘to_r` when called on a rational literal or with `Rational()`.

  • ‘to_c` when called on a complex literal of with `Complex()`.

  • ‘to_a` when called on an array literal, or with `Array.new`, `Array()` or `Array[]`.

  • ‘to_h` when called on a hash literal, or with `Hash.new`, `Hash()` or `Hash[]`.

  • ‘to_set` when called on `Set.new` or `Set[]`.

In all cases, chaining one same ‘to_*` conversion methods listed above is redundant.

The cop can also register an offense for chaining conversion methods on methods that are expected to return a specific type regardless of receiver (eg. ‘foo.inspect.to_s` and `foo.to_json.to_s`).

Examples:

# bad
"text".to_s
:sym.to_sym
42.to_i
8.5.to_f
12r.to_r
1i.to_c
[].to_a
{}.to_h
Set.new.to_set

# good
"text"
:sym
42
8.5
12r
1i
[]
{}
Set.new

# bad
Integer(var).to_i

# good
Integer(var)

# good - chaining to a type constructor with exceptions suppressed
# in this case, `Integer()` could return `nil`
Integer(var, exception: false).to_i

# bad - chaining the same conversion
foo.to_s.to_s

# good
foo.to_s

# bad - chaining a conversion to a method that is expected to return the same type
foo.inspect.to_s
foo.to_json.to_s

# good
foo.inspect
foo.to_json

Constant Summary collapse

MSG =
'Redundant `%<method>s` detected.'
TYPED_METHODS =

Methods that already are expected to return a given type, which makes a further conversion redundant.

{ to_s: %i[inspect to_json] }.freeze
CONVERSION_METHODS =
Set[*LITERAL_NODE_TYPES.keys].freeze
RESTRICT_ON_SEND =
CONVERSION_METHODS + [:to_d]

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

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

#exclude_limit

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

#array_constructor?(node) ⇒ Object



160
161
162
163
164
165
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 160

def_node_matcher :array_constructor?, <<~PATTERN
  {
    (send (const {cbase nil?} :Array) {:new :[]} ...)
    #type_constructor?(:Array)
  }
PATTERN

#bigdecimal_constructor?(node) ⇒ Object



145
146
147
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 145

def_node_matcher :bigdecimal_constructor?, <<~PATTERN
  #type_constructor?(:BigDecimal)
PATTERN

#complex_constructor?(node) ⇒ Object



155
156
157
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 155

def_node_matcher :complex_constructor?, <<~PATTERN
  #type_constructor?(:Complex)
PATTERN

#exception_false_keyword_argument?(node) ⇒ Object



184
185
186
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 184

def_node_matcher :exception_false_keyword_argument?, <<~PATTERN
  (hash (pair (sym :exception) false))
PATTERN

#float_constructor?(node) ⇒ Object



140
141
142
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 140

def_node_matcher :float_constructor?, <<~PATTERN
  #type_constructor?(:Float)
PATTERN

#hash_constructor?(node) ⇒ Object



168
169
170
171
172
173
174
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 168

def_node_matcher :hash_constructor?, <<~PATTERN
  {
    (block (send (const {cbase nil?} :Hash) :new) ...)
    (send (const {cbase nil?} :Hash) {:new :[]} ...)
    (send {nil? (const {cbase nil?} :Kernel)} :Hash ...)
  }
PATTERN

#integer_constructor?(node) ⇒ Object



135
136
137
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 135

def_node_matcher :integer_constructor?, <<~PATTERN
  #type_constructor?(:Integer)
PATTERN

#on_send(node) ⇒ Object Also known as: on_csend

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 189

def on_send(node)
  return if node.arguments.any? || hash_or_set_with_block?(node)

  receiver = find_receiver(node)
  return unless literal_receiver?(node, receiver) ||
                constructor?(node, receiver) ||
                chained_conversion?(node, receiver) ||
                chained_to_typed_method?(node, receiver)

  message = format(MSG, method: node.method_name)

  add_offense(node.loc.selector, message: message) do |corrector|
    corrector.remove(node.loc.dot.join(node.loc.end || node.loc.selector))
  end
end

#rational_constructor?(node) ⇒ Object



150
151
152
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 150

def_node_matcher :rational_constructor?, <<~PATTERN
  #type_constructor?(:Rational)
PATTERN

#set_constructor?(node) ⇒ Object



177
178
179
180
181
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 177

def_node_matcher :set_constructor?, <<~PATTERN
  {
    (send (const {cbase nil?} :Set) {:new :[]} ...)
  }
PATTERN

#string_constructor?(node) ⇒ Object



127
128
129
130
131
132
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 127

def_node_matcher :string_constructor?, <<~PATTERN
  {
    (send (const {cbase nil?} :String) :new ...)
    #type_constructor?(:String)
  }
PATTERN

#type_constructor?(node, type_symbol) ⇒ Object



122
123
124
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 122

def_node_matcher :type_constructor?, <<~PATTERN
  (send {nil? (const {cbase nil?} :Kernel)} %1 ...)
PATTERN