Class: RuboCop::Cop::Lint::RedundantSafeNavigation
- Extended by:
- AutoCorrector
- Includes:
- AllowedMethods
- Defined in:
- lib/rubocop/cop/lint/redundant_safe_navigation.rb
Overview
Checks for redundant safe navigation calls. Use cases where a constant, named in camel case for classes and modules is ‘nil` are rare, and an offense is not detected when the receiver is a constant. The detection also applies to `self`, and to literal receivers, except for `nil`.
For all receivers, the ‘instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods are checked by default. These are customizable with `AllowedMethods` option.
The ‘AllowedMethods` option specifies nil-safe methods, in other words, it is a method that is allowed to skip safe navigation. Note that the `AllowedMethod` option is not an option that specifies methods for which to suppress (allow) this cop’s check.
In the example below, the safe navigation operator (‘&.`) is unnecessary because `NilClass` has methods like `respond_to?` and `is_a?`.
The ‘InferNonNilReceiver` option specifies whether to look into previous code paths to infer if the receiver can’t be nil. This check is unsafe because the receiver can be redefined between the safe navigation call and previous regular method call. It does the inference only in the current scope, e.g. within the same method definition etc.
The ‘AdditionalNilMethods` option specifies additional custom methods which are defined on `NilClass`. When `InferNonNilReceiver` is set, they are used to determine whether the receiver can be nil.
Constant Summary collapse
- MSG =
'Redundant safe navigation detected, use `.` instead.'
- MSG_LITERAL =
'Redundant safe navigation with default literal detected.'
- MSG_NON_NIL =
'Redundant safe navigation on non-nil receiver (detected by analyzing ' \ 'previous code/method invocations).'
- NIL_SPECIFIC_METHODS =
(nil.methods - Object.new.methods).to_set.freeze
- SNAKE_CASE =
/\A[[:digit:][:upper:]_]+\z/.freeze
- GUARANTEED_INSTANCE_METHODS =
%i[to_s to_i to_f to_a to_h].freeze
Constants inherited from Base
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
- #conversion_with_default?(node) ⇒ Object
-
#on_csend(node) ⇒ Object
rubocop:disable Metrics/AbcSize.
-
#on_or(node) ⇒ Object
rubocop:disable Metrics/AbcSize.
- #respond_to_nil_specific_method?(node) ⇒ Object
Methods included from AutoCorrector
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
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
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Method Details
#conversion_with_default?(node) ⇒ Object
166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 166 def_node_matcher :conversion_with_default?, <<~PATTERN { (or $(csend _ :to_h) (hash)) (or (block $(csend _ :to_h) ...) (hash)) (or $(csend _ :to_a) (array)) (or $(csend _ :to_i) (int 0)) (or $(csend _ :to_f) (float 0.0)) (or $(csend _ :to_s) (str empty?)) } PATTERN |
#on_csend(node) ⇒ Object
rubocop:disable Metrics/AbcSize
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 178 def on_csend(node) range = node.loc.dot if infer_non_nil_receiver? checker = Lint::Utils::NilReceiverChecker.new(node.receiver, additional_nil_methods) if checker.cant_be_nil? add_offense(range, message: MSG_NON_NIL) { |corrector| corrector.replace(range, '.') } return end end unless assume_receiver_instance_exists?(node.receiver) return if !guaranteed_instance?(node.receiver) && !check?(node) return if respond_to_nil_specific_method?(node) end add_offense(range) { |corrector| corrector.replace(range, '.') } end |
#on_or(node) ⇒ Object
rubocop:disable Metrics/AbcSize
200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 200 def on_or(node) conversion_with_default?(node) do |send_node| range = send_node.loc.dot.begin.join(node.source_range.end) add_offense(range, message: MSG_LITERAL) do |corrector| corrector.replace(send_node.loc.dot, '.') range_with_default = node.lhs.source_range.end.begin.join(node.source_range.end) corrector.remove(range_with_default) end end end |
#respond_to_nil_specific_method?(node) ⇒ Object
161 162 163 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 161 def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN (csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS)) PATTERN |