Class: RuboCop::Cop::Sorbet::RedundantTLet
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Sorbet::RedundantTLet
- Extended by:
- AutoCorrector
- Includes:
- ConstantScope, SignatureHelp, TLetCorrection, TargetSorbetVersion
- Defined in:
- lib/rubocop/cop/sorbet/redundant_t_let.rb
Overview
Prevents unnecessary T.let where Sorbet infers the type automatically.
When a signature parameter is assigned to an instance variable in
initialize, the type is inferred from the signature.
When a constant is assigned a constructor call (.new), optionally
followed by .freeze (Sorbet 0.6.13304+), the type is inferred from
the class being instantiated. Generic classes (e.g. Set) are
excluded: Sorbet infers their constructor calls as applied types like
T::Set[T.untyped], so an annotation is still required.
Constant Summary collapse
- MSG =
"Unnecessary T.let. The instance variable type is inferred from the signature."- MSG_CONSTRUCTOR =
"Unnecessary T.let. The constant type is inferred from the constructor."- GENERIC_CLASSES =
Classes whose constructor calls Sorbet infers as applied generic types (e.g.
T::Set[T.untyped]) rather than the bare class, so constants assigned them still need an explicit annotation. ["Array", "Class", "Enumerator", "Hash", "Module", "Range", "Set"].freeze
Instance Method Summary collapse
- #on_casgn(node) ⇒ Object
- #on_def(node) ⇒ Object
- #sig_params(node) ⇒ Object
- #t_let(node) ⇒ Object
- #t_let_casgn(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
Methods included from SignatureHelp
#bare_sig?, #on_block, #on_signature, #sig_with_runtime?, #sig_without_runtime?, #signature?
Instance Method Details
#on_casgn(node) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let.rb', line 99 def on_casgn(node) return unless enabled_for_sorbet_static_version? return unless statically_scoped?(node) t_let_casgn(node) do |tlet_node, value_node, type_node| next unless type_node.const_type? constructor = constructor_call(value_node) next unless constructor class_path = constructor.receiver.source.delete_prefix("::") next if GENERIC_CLASSES.include?(class_path) next unless class_path == type_node.source.delete_prefix("::") add_offense(tlet_node, message: MSG_CONSTRUCTOR) do |corrector| replace_t_let(corrector, tlet_node, value_node) end end end |
#on_def(node) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let.rb', line 80 def on_def(node) return unless node.method?(:initialize) method_args = named_argument_types(node) return if method_args.none? sig_node = find_sig_node(node) return unless sig_node sig_params = sig_params(sig_node)&.to_h { |pair| [pair.key.value, pair.value] } return unless sig_params&.any? ivar_assignments(node).each do |ivasgn_node| t_let(ivasgn_node) do |tlet_node, tlet_key, tlet_value| find_redundant_t_let(tlet_node, tlet_key, tlet_value, sig_params, method_args) end end end |
#sig_params(node) ⇒ Object
78 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let.rb', line 78 def_node_matcher :sig_params, "`(send nil? :params (hash $...))" |
#t_let(node) ⇒ Object
72 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let.rb', line 72 def_node_matcher :t_let, "(ivasgn _ $(send (const {nil? cbase} :T) :let (lvar $_) $_))" |
#t_let_casgn(node) ⇒ Object
75 |
# File 'lib/rubocop/cop/sorbet/redundant_t_let.rb', line 75 def_node_matcher :t_let_casgn, "(casgn _ _ $(send (const {nil? cbase} :T) :let $_ $_))" |