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_METHODS =
nil.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_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
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
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Method Details
#conversion_with_default?(node) ⇒ Object
183 184 185 186 187 188 189 190 191 192 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 183 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
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 195 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_method?(node) end add_offense(range) { |corrector| corrector.replace(range, '.') } end |
#on_or(node) ⇒ Object
rubocop:disable Metrics/AbcSize
217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 217 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_method?(node) ⇒ Object
178 179 180 |
# File 'lib/rubocop/cop/lint/redundant_safe_navigation.rb', line 178 def_node_matcher :respond_to_nil_method?, <<~PATTERN (csend _ :respond_to? (sym %NIL_METHODS)) PATTERN |