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 or with `Float()`.

  • ‘to_d` when called with `BigDecimal()`.

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

  • ‘to_c` when called on a complex literal or 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 of the 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
BigDecimal(var).to_d

# good
BigDecimal(var)

# 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, #project_index

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

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

#array_constructor?(node) ⇒ Object



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

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

#bigdecimal_constructor?(node) ⇒ Object



152
153
154
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 152

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

#complex_constructor?(node) ⇒ Object



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

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

#exception_false_keyword_argument?(node) ⇒ Object



191
192
193
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 191

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

#float_constructor?(node) ⇒ Object



147
148
149
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 147

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

#hash_constructor?(node) ⇒ Object



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

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



142
143
144
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 142

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



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 196

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



157
158
159
# File 'lib/rubocop/cop/lint/redundant_type_conversion.rb', line 157

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

#set_constructor?(node) ⇒ Object



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

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

#string_constructor?(node) ⇒ Object



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

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

#type_constructor?(node, type_symbol) ⇒ Object



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

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