Class: RuboCop::Cop::Sorbet::RedundantTLetForLiteral
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Sorbet::RedundantTLetForLiteral
- Extended by:
- AutoCorrector
- Includes:
- ConstantScope, TLetCorrection, TargetSorbetVersion
- Defined in:
- lib/rubocop/cop/sorbet/redundant_t_let_for_literal.rb
Overview
Checks for redundant T.let declarations and trailing RBS annotations
where the assigned value is a literal whose type Sorbet can infer
automatically.
Simple literals (strings, symbols, integers, floats, regexps) infer as
their own class. Regexp literals are the only simple literals whose
inference survives a .freeze call (Sorbet 0.6.13304+), so
T.let(/foo/.freeze, Regexp) is also redundant; other frozen simple
literals (e.g. "hello".freeze) are not inferred and still need T.let.
Array literals of simple literals are also inferred:
- A frozen array (
[...].freeze) infers as a fixed-size tuple, which is a subtype of the annotatedT::Array, so the annotation is redundant. - An unfrozen array infers as
T::Array[<element type>]. It is only flagged when that inferred type matches the annotation exactly, to avoid silently widening (e.g.["a", nil]infers a nilable element).
Hashes are excluded: Sorbet infers hash literals as T.untyped, so the
annotation is required.
Constant Summary collapse
- MSG =
"Redundant %{annotation} for %{type} literal. Sorbet can infer this type automatically."- LITERAL_TYPE_TO_CLASS =
Simple literal node types Sorbet infers, mapped to the class name. Interpolated strings/symbols (
dstr/dsym) infer asString/Symbol. { dstr: :String, dsym: :Symbol, float: :Float, int: :Integer, regexp: :Regexp, str: :String, sym: :Symbol, }.freeze
- ARRAY_ELEMENT_TYPES =
Element node types allowed inside an inferable array literal: the literals whose class Sorbet reflects into the array's element type. Regexps and ranges, by contrast, degrade the array to
T.untyped, so they are excluded. Interpolated strings/symbols (dstr/dsym) infer asString/Symbol, the same as their plain literal forms. [:dstr, :dsym, :str, :sym, :int, :float, :true, :false, :nil].freeze
- ELEMENT_TYPE_TO_CLASS =
Element node types whose inferred class is unambiguous, used to derive the element type of an unfrozen array literal.
{ dstr: "String", dsym: "Symbol", float: "Float", int: "Integer", str: "String", sym: "Symbol", }.freeze
Instance Method Summary collapse
- #on_casgn(node) ⇒ Object
- #t_let_with_array?(node) ⇒ Object
- #t_let_with_literal_and_class?(node) ⇒ Object
Methods included from TargetSorbetVersion
#enabled_for_sorbet_static_version?, included, #read_sorbet_static_version_from_bundler_lock_file, #sorbet_enabled?, #target_sorbet_static_version_from_bundler_lock_file
Instance Method Details
#on_casgn(node) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let_for_literal.rb', line 125 def on_casgn(node) return unless statically_scoped?(node) t_let_with_literal_and_class?(node) do |value_node, class_name| literal_node = inferable_literal_node(value_node) next unless literal_node next unless LITERAL_TYPE_TO_CLASS[literal_node.type] == class_name register_offense(node, value_node, class_name) end if enabled_for_sorbet_static_version? t_let_with_array?(node) do |value_node, type_node| frozen = value_node.send_type? array_node = frozen ? value_node.receiver : value_node next unless inferable_array?(array_node) next unless redundant_array_annotation?(array_node, type_node, frozen: frozen) register_offense(node, value_node, :Array) end end check_rbs_annotation(node) end |
#t_let_with_array?(node) ⇒ Object
121 122 123 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let_for_literal.rb', line 121 def_node_matcher :t_let_with_array?, <<~PATTERN (casgn _ _ (send (const {nil? cbase} :T) :let ${array (send array :freeze)} $_)) PATTERN |
#t_let_with_literal_and_class?(node) ⇒ Object
116 117 118 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let_for_literal.rb', line 116 def_node_matcher :t_let_with_literal_and_class?, <<~PATTERN (casgn _ _ (send (const {nil? cbase} :T) :let ${literal? (send (regexp ...) :freeze)} (const nil? $_))) PATTERN |