rubocop-sorbet 0.10.3 → 0.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/Gemfile.lock +2 -2
- data/VERSION +1 -1
- data/config/default.yml +31 -1
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cop/sorbet/forbid_t_absurd.rb +31 -0
- data/lib/rubocop/cop/sorbet/forbid_t_bind.rb +31 -0
- data/lib/rubocop/cop/sorbet/forbid_t_cast.rb +31 -0
- data/lib/rubocop/cop/sorbet/forbid_t_let.rb +31 -0
- data/lib/rubocop/cop/sorbet/forbid_t_must.rb +31 -0
- data/lib/rubocop/cop/sorbet/forbid_t_type_alias.rb +30 -0
- data/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb +207 -54
- data/lib/rubocop/cop/sorbet_cops.rb +6 -0
- data/lib/rubocop/sorbet/version.rb +1 -1
- data/manual/cops.md +6 -0
- data/manual/cops_sorbet.md +110 -1
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '086645a85b87da08958ff04471b05e238fbe14de8bc6108610bd20ca638f5ef7'
|
4
|
+
data.tar.gz: 24b4add23624df28a1019f528b0f24f5f87bf379ecca807d922b0220c65b09d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fd16f332f9df0642787e8a60baa934611298a1487aabb3b84c05795764ce839dfb37001413f751bcd6a494c068220038941aaf972d36ebe0edf05315daa1fe2
|
7
|
+
data.tar.gz: 2d015fbdc34e4d4fcb8ba3ea60db28ec9a5af2e88efc78f258152b5cf0c1cb748c15f464b6bba2c596f24141bbb98b2a82d57afb49a3ed27a18901d11f68253b
|
data/.github/workflows/ci.yml
CHANGED
@@ -16,7 +16,7 @@ jobs:
|
|
16
16
|
steps:
|
17
17
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
18
18
|
- name: Set up Ruby
|
19
|
-
uses: ruby/setup-ruby@
|
19
|
+
uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
20
20
|
with:
|
21
21
|
ruby-version: ${{ matrix.ruby }}
|
22
22
|
bundler-cache: true
|
@@ -31,7 +31,7 @@ jobs:
|
|
31
31
|
steps:
|
32
32
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
33
33
|
- name: Set up Ruby
|
34
|
-
uses: ruby/setup-ruby@
|
34
|
+
uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
35
35
|
with:
|
36
36
|
bundler-cache: true
|
37
37
|
# This is just to ensure the default config is valid. The target is intentionally set
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rubocop-sorbet (0.10.
|
4
|
+
rubocop-sorbet (0.10.5)
|
5
5
|
lint_roller
|
6
6
|
rubocop (>= 1.75.2)
|
7
7
|
|
@@ -39,7 +39,7 @@ GEM
|
|
39
39
|
regexp_parser (2.10.0)
|
40
40
|
reline (0.6.0)
|
41
41
|
io-console (~> 0.5)
|
42
|
-
rubocop (1.76.
|
42
|
+
rubocop (1.76.1)
|
43
43
|
json (~> 2.3)
|
44
44
|
language_server-protocol (~> 3.17.0.2)
|
45
45
|
lint_roller (~> 1.1.0)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.5
|
data/config/default.yml
CHANGED
@@ -82,7 +82,7 @@ Sorbet/EnforceSigilOrder:
|
|
82
82
|
Sorbet/EnforceSignatures:
|
83
83
|
Description: 'Ensures all methods have a valid signature.'
|
84
84
|
Enabled: false
|
85
|
-
|
85
|
+
Style: sig
|
86
86
|
VersionAdded: 0.3.4
|
87
87
|
|
88
88
|
Sorbet/EnforceSingleSigil:
|
@@ -171,6 +171,36 @@ Sorbet/ForbidTStruct:
|
|
171
171
|
VersionAdded: 0.7.4
|
172
172
|
Safe: false
|
173
173
|
|
174
|
+
Sorbet/ForbidTAbsurd:
|
175
|
+
Description: 'Forbid usage of T.absurd.'
|
176
|
+
Enabled: false
|
177
|
+
VersionAdded: 0.10.4
|
178
|
+
|
179
|
+
Sorbet/ForbidTBind:
|
180
|
+
Description: 'Forbid usage of T.bind.'
|
181
|
+
Enabled: false
|
182
|
+
VersionAdded: 0.10.4
|
183
|
+
|
184
|
+
Sorbet/ForbidTCast:
|
185
|
+
Description: 'Forbid usage of T.cast.'
|
186
|
+
Enabled: false
|
187
|
+
VersionAdded: 0.10.4
|
188
|
+
|
189
|
+
Sorbet/ForbidTLet:
|
190
|
+
Description: 'Forbid usage of T.let.'
|
191
|
+
Enabled: false
|
192
|
+
VersionAdded: 0.10.4
|
193
|
+
|
194
|
+
Sorbet/ForbidTMust:
|
195
|
+
Description: 'Forbid usage of T.must.'
|
196
|
+
Enabled: false
|
197
|
+
VersionAdded: 0.10.4
|
198
|
+
|
199
|
+
Sorbet/ForbidTTypeAlias:
|
200
|
+
Description: 'Forbid usage of T.type_alias.'
|
201
|
+
Enabled: false
|
202
|
+
VersionAdded: 0.10.4
|
203
|
+
|
174
204
|
Sorbet/ForbidTUnsafe:
|
175
205
|
Description: 'Forbid usage of T.unsafe.'
|
176
206
|
Enabled: false
|
data/config/obsoletion.yml
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.absurd` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# T.absurd(foo)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# x #: absurd
|
17
|
+
class ForbidTAbsurd < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.absurd`."
|
19
|
+
RESTRICT_ON_SEND = [:absurd].freeze
|
20
|
+
|
21
|
+
# @!method t_absurd?(node)
|
22
|
+
def_node_matcher(:t_absurd?, "(send (const nil? :T) :absurd _)")
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
add_offense(node) if t_absurd?(node)
|
26
|
+
end
|
27
|
+
alias_method :on_csend, :on_send
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.bind` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# T.bind(self, Integer)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# #: self as Integer
|
17
|
+
class ForbidTBind < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.bind`."
|
19
|
+
RESTRICT_ON_SEND = [:bind].freeze
|
20
|
+
|
21
|
+
# @!method t_bind?(node)
|
22
|
+
def_node_matcher(:t_bind?, "(send (const nil? :T) :bind _ _)")
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
add_offense(node) if t_bind?(node)
|
26
|
+
end
|
27
|
+
alias_method :on_csend, :on_send
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.cast` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# T.cast(foo, Integer)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# foo #: as Integer
|
17
|
+
class ForbidTCast < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.cast`."
|
19
|
+
RESTRICT_ON_SEND = [:cast].freeze
|
20
|
+
|
21
|
+
# @!method t_cast?(node)
|
22
|
+
def_node_matcher(:t_cast?, "(send (const nil? :T) :cast _ _)")
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
add_offense(node) if t_cast?(node)
|
26
|
+
end
|
27
|
+
alias_method :on_csend, :on_send
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.let` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# T.let(foo, Integer)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# foo #: Integer
|
17
|
+
class ForbidTLet < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.let`."
|
19
|
+
RESTRICT_ON_SEND = [:let].freeze
|
20
|
+
|
21
|
+
# @!method t_let?(node)
|
22
|
+
def_node_matcher(:t_let?, "(send (const nil? :T) :let _ _)")
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
add_offense(node) if t_let?(node)
|
26
|
+
end
|
27
|
+
alias_method :on_csend, :on_send
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.must` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# T.must(foo)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# foo #: as !nil
|
17
|
+
class ForbidTMust < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.must`."
|
19
|
+
RESTRICT_ON_SEND = [:must].freeze
|
20
|
+
|
21
|
+
# @!method t_must?(node)
|
22
|
+
def_node_matcher(:t_must?, "(send (const nil? :T) :must _)")
|
23
|
+
|
24
|
+
def on_send(node)
|
25
|
+
add_offense(node) if t_must?(node)
|
26
|
+
end
|
27
|
+
alias_method :on_csend, :on_send
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallows using `T.type_alias` anywhere.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# STRING_OR_INTEGER = T.type_alias { T.any(Integer, String) }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# #: type string_or_integer = Integer | String
|
17
|
+
class ForbidTTypeAlias < RuboCop::Cop::Base
|
18
|
+
MSG = "Do not use `T.type_alias`."
|
19
|
+
|
20
|
+
# @!method t_type_alias?(node)
|
21
|
+
def_node_matcher(:t_type_alias?, "(block (call (const nil? :T) :type_alias) _ _)")
|
22
|
+
|
23
|
+
def on_block(node)
|
24
|
+
add_offense(node) if t_type_alias?(node)
|
25
|
+
end
|
26
|
+
alias_method :on_numblock, :on_block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "stringio"
|
4
|
-
|
5
3
|
module RuboCop
|
6
4
|
module Cop
|
7
5
|
module Sorbet
|
@@ -24,16 +22,12 @@ module RuboCop
|
|
24
22
|
#
|
25
23
|
# * `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
|
26
24
|
# * `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
|
25
|
+
# * `Style`: signature style to enforce - 'sig' for sig blocks, 'rbs' for RBS comments, 'both' to allow either (default: 'sig')
|
27
26
|
class EnforceSignatures < ::RuboCop::Cop::Base
|
28
27
|
extend AutoCorrector
|
29
28
|
include SignatureHelp
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
def initialize(config = nil, options = nil)
|
34
|
-
super(config, options)
|
35
|
-
@last_sig_for_scope = {}
|
36
|
-
end
|
30
|
+
VALID_STYLES = ["sig", "rbs", "both"].freeze
|
37
31
|
|
38
32
|
# @!method accessor?(node)
|
39
33
|
def_node_matcher(:accessor?, <<-PATTERN)
|
@@ -53,7 +47,13 @@ module RuboCop
|
|
53
47
|
end
|
54
48
|
|
55
49
|
def on_signature(node)
|
56
|
-
|
50
|
+
sig_checker.on_signature(node, scope(node))
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_new_investigation
|
54
|
+
super
|
55
|
+
@sig_checker = nil
|
56
|
+
@rbs_checker = nil
|
57
57
|
end
|
58
58
|
|
59
59
|
def scope(node)
|
@@ -67,48 +67,102 @@ module RuboCop
|
|
67
67
|
|
68
68
|
def check_node(node)
|
69
69
|
scope = self.scope(node)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
sig_node = sig_checker.signature_node(scope)
|
71
|
+
rbs_node = rbs_checker.signature_node(node)
|
72
|
+
|
73
|
+
case signature_style
|
74
|
+
when "rbs"
|
75
|
+
# RBS style - only RBS signatures allowed
|
76
|
+
if sig_node
|
77
|
+
add_offense(sig_node, message: "Use RBS signature comments rather than sig blocks.")
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
unless rbs_node
|
82
|
+
add_offense(node, message: "Each method is required to have an RBS signature.") do |corrector|
|
83
|
+
autocorrect_with_signature_type(corrector, node, "rbs")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
when "both"
|
87
|
+
# Both styles allowed - require at least one
|
88
|
+
unless sig_node || rbs_node
|
89
|
+
add_offense(node, message: "Each method is required to have a signature.") do |corrector|
|
90
|
+
autocorrect_with_signature_type(corrector, node, "sig")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
else # "sig" (default)
|
94
|
+
# Sig style - only sig signatures allowed
|
95
|
+
unless sig_node
|
96
|
+
add_offense(node, message: "Each method is required to have a sig block signature.") do |corrector|
|
97
|
+
autocorrect_with_signature_type(corrector, node, "sig")
|
98
|
+
end
|
76
99
|
end
|
77
100
|
end
|
78
|
-
|
101
|
+
ensure
|
102
|
+
sig_checker.clear_signature(scope)
|
79
103
|
end
|
80
104
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
node = node.parent while RuboCop::AST::SendNode === node.parent
|
85
|
-
return false if (comments = preceeding_comments(node)).empty?
|
105
|
+
def sig_checker
|
106
|
+
@sig_checker ||= SigSignatureChecker.new(processed_source)
|
107
|
+
end
|
86
108
|
|
87
|
-
|
88
|
-
|
109
|
+
def rbs_checker
|
110
|
+
@rbs_checker ||= RBSSignatureChecker.new(processed_source)
|
111
|
+
end
|
89
112
|
|
90
|
-
|
113
|
+
def autocorrect_with_signature_type(corrector, node, type)
|
114
|
+
suggest = create_signature_suggestion(node, type)
|
115
|
+
populate_signature_suggestion(suggest, node)
|
116
|
+
corrector.insert_before(node, suggest.to_autocorrect)
|
91
117
|
end
|
92
118
|
|
93
|
-
def
|
94
|
-
|
119
|
+
def create_signature_suggestion(node, type)
|
120
|
+
case type
|
121
|
+
when "rbs"
|
122
|
+
RBSSuggestion.new(node.loc.column)
|
123
|
+
else # "sig"
|
124
|
+
SigSuggestion.new(node.loc.column, param_type_placeholder, return_type_placeholder)
|
125
|
+
end
|
95
126
|
end
|
96
127
|
|
97
|
-
def
|
98
|
-
|
128
|
+
def populate_signature_suggestion(suggest, node)
|
129
|
+
if node.any_def_type?
|
130
|
+
populate_method_definition_suggestion(suggest, node)
|
131
|
+
elsif accessor?(node)
|
132
|
+
populate_accessor_suggestion(suggest, node)
|
133
|
+
end
|
134
|
+
end
|
99
135
|
|
100
|
-
|
101
|
-
|
136
|
+
def populate_method_definition_suggestion(suggest, node)
|
137
|
+
node.arguments.each do |arg|
|
138
|
+
if arg.blockarg_type? && suggest.respond_to?(:has_block=)
|
139
|
+
suggest.has_block = true
|
140
|
+
else
|
102
141
|
suggest.params << arg.children.first
|
103
142
|
end
|
104
|
-
elsif accessor?(node) # attr reader, writer, accessor
|
105
|
-
method = node.children[1]
|
106
|
-
symbol = node.children[2]
|
107
|
-
suggest.params << symbol.value if symbol && (method == :attr_writer || method == :attr_accessor)
|
108
|
-
suggest.returns = "void" if method == :attr_writer
|
109
143
|
end
|
144
|
+
end
|
110
145
|
|
111
|
-
|
146
|
+
def populate_accessor_suggestion(suggest, node)
|
147
|
+
method = node.children[1]
|
148
|
+
symbol = node.children[2]
|
149
|
+
|
150
|
+
add_accessor_parameter_if_needed(suggest, symbol, method)
|
151
|
+
set_void_return_for_writer(suggest, method)
|
152
|
+
end
|
153
|
+
|
154
|
+
def add_accessor_parameter_if_needed(suggest, symbol, method)
|
155
|
+
return unless symbol && writer_or_accessor?(method)
|
156
|
+
|
157
|
+
suggest.params << symbol.value
|
158
|
+
end
|
159
|
+
|
160
|
+
def set_void_return_for_writer(suggest, method)
|
161
|
+
suggest.returns = "void" if method == :attr_writer
|
162
|
+
end
|
163
|
+
|
164
|
+
def writer_or_accessor?(method)
|
165
|
+
method == :attr_writer || method == :attr_accessor
|
112
166
|
end
|
113
167
|
|
114
168
|
def param_type_placeholder
|
@@ -119,6 +173,80 @@ module RuboCop
|
|
119
173
|
cop_config["ReturnTypePlaceholder"] || "T.untyped"
|
120
174
|
end
|
121
175
|
|
176
|
+
def allow_rbs?
|
177
|
+
cop_config["AllowRBS"] == true
|
178
|
+
end
|
179
|
+
|
180
|
+
def signature_style
|
181
|
+
config_value = cop_config["Style"]
|
182
|
+
if config_value
|
183
|
+
unless VALID_STYLES.include?(config_value)
|
184
|
+
raise ArgumentError, "Invalid Style option: '#{config_value}'. Valid options are: #{VALID_STYLES.join(", ")}"
|
185
|
+
end
|
186
|
+
|
187
|
+
return config_value
|
188
|
+
end
|
189
|
+
|
190
|
+
return "both" if allow_rbs?
|
191
|
+
|
192
|
+
"sig"
|
193
|
+
end
|
194
|
+
|
195
|
+
class SignatureChecker
|
196
|
+
def initialize(processed_source)
|
197
|
+
@processed_source = processed_source
|
198
|
+
end
|
199
|
+
|
200
|
+
protected
|
201
|
+
|
202
|
+
attr_reader :processed_source
|
203
|
+
|
204
|
+
def preceding_comments(node)
|
205
|
+
processed_source.ast_with_comments[node].select { |comment| comment.loc.line < node.loc.line }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class RBSSignatureChecker < SignatureChecker
|
210
|
+
RBS_COMMENT_REGEX = /^#\s*:.*$/
|
211
|
+
|
212
|
+
def signature_node(node)
|
213
|
+
node = find_non_send_ancestor(node)
|
214
|
+
comments = preceding_comments(node)
|
215
|
+
return if comments.empty?
|
216
|
+
|
217
|
+
last_comment = comments.last
|
218
|
+
return if last_comment.loc.line + 1 < node.loc.line
|
219
|
+
|
220
|
+
comments.find { |comment| RBS_COMMENT_REGEX.match?(comment.text) }
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def find_non_send_ancestor(node)
|
226
|
+
node = node.parent while node.parent&.send_type?
|
227
|
+
node
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class SigSignatureChecker < SignatureChecker
|
232
|
+
def initialize(processed_source)
|
233
|
+
super(processed_source)
|
234
|
+
@last_sig_for_scope = {}
|
235
|
+
end
|
236
|
+
|
237
|
+
def signature_node(scope)
|
238
|
+
@last_sig_for_scope[scope]
|
239
|
+
end
|
240
|
+
|
241
|
+
def on_signature(node, scope)
|
242
|
+
@last_sig_for_scope[scope] = node
|
243
|
+
end
|
244
|
+
|
245
|
+
def clear_signature(scope)
|
246
|
+
@last_sig_for_scope[scope] = nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
122
250
|
class SigSuggestion
|
123
251
|
attr_accessor :params, :returns
|
124
252
|
|
@@ -131,34 +259,59 @@ module RuboCop
|
|
131
259
|
end
|
132
260
|
|
133
261
|
def to_autocorrect
|
134
|
-
|
135
|
-
out << "sig { "
|
136
|
-
out << generate_params
|
137
|
-
out << generate_return
|
138
|
-
out << " }\n"
|
139
|
-
out << " " * @indent # preserve indent for the next line
|
140
|
-
out.string
|
262
|
+
"sig { #{generate_params}#{generate_return} }\n#{" " * @indent}"
|
141
263
|
end
|
142
264
|
|
143
265
|
private
|
144
266
|
|
145
267
|
def generate_params
|
146
|
-
return if @params.empty?
|
268
|
+
return "" if @params.empty?
|
147
269
|
|
148
|
-
|
149
|
-
|
150
|
-
out << @params.map do |param|
|
151
|
-
"#{param}: #{@param_placeholder}"
|
152
|
-
end.join(", ")
|
153
|
-
out << ")."
|
154
|
-
out.string
|
270
|
+
param_list = @params.map { |param| "#{param}: #{@param_placeholder}" }.join(", ")
|
271
|
+
"params(#{param_list})."
|
155
272
|
end
|
156
273
|
|
157
274
|
def generate_return
|
158
|
-
|
159
|
-
|
275
|
+
if @returns.nil?
|
276
|
+
"returns(#{@return_placeholder})"
|
277
|
+
elsif @returns == "void"
|
278
|
+
"void"
|
279
|
+
else
|
280
|
+
"returns(#{@returns})"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
class RBSSuggestion
|
286
|
+
attr_accessor :params, :returns, :has_block
|
287
|
+
|
288
|
+
def initialize(indent)
|
289
|
+
@params = []
|
290
|
+
@returns = nil
|
291
|
+
@has_block = false
|
292
|
+
@indent = indent
|
293
|
+
end
|
294
|
+
|
295
|
+
def to_autocorrect
|
296
|
+
"#: #{generate_signature}\n#{" " * @indent}"
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
|
301
|
+
def generate_signature
|
302
|
+
param_types = @params.map { "untyped" }.join(", ")
|
303
|
+
return_type = @returns || "untyped"
|
304
|
+
|
305
|
+
signature = if @params.empty?
|
306
|
+
"()"
|
307
|
+
else
|
308
|
+
"(#{param_types})"
|
309
|
+
end
|
310
|
+
|
311
|
+
signature += " { (?) -> untyped }" if @has_block
|
312
|
+
signature += " -> #{return_type}"
|
160
313
|
|
161
|
-
|
314
|
+
signature
|
162
315
|
end
|
163
316
|
end
|
164
317
|
end
|
@@ -14,8 +14,14 @@ require_relative "sorbet/forbid_type_aliased_shapes"
|
|
14
14
|
require_relative "sorbet/forbid_untyped_struct_props"
|
15
15
|
require_relative "sorbet/implicit_conversion_method"
|
16
16
|
require_relative "sorbet/callback_conditionals_binding"
|
17
|
+
require_relative "sorbet/forbid_t_absurd"
|
18
|
+
require_relative "sorbet/forbid_t_bind"
|
19
|
+
require_relative "sorbet/forbid_t_cast"
|
17
20
|
require_relative "sorbet/forbid_t_enum"
|
21
|
+
require_relative "sorbet/forbid_t_let"
|
22
|
+
require_relative "sorbet/forbid_t_must"
|
18
23
|
require_relative "sorbet/forbid_t_struct"
|
24
|
+
require_relative "sorbet/forbid_t_type_alias"
|
19
25
|
require_relative "sorbet/forbid_t_unsafe"
|
20
26
|
require_relative "sorbet/forbid_t_untyped"
|
21
27
|
require_relative "sorbet/redundant_extend_t_sig"
|
data/manual/cops.md
CHANGED
@@ -27,8 +27,14 @@ In the following section you find all available cops:
|
|
27
27
|
* [Sorbet/ForbidSigWithRuntime](cops_sorbet.md#sorbetforbidsigwithruntime)
|
28
28
|
* [Sorbet/ForbidSigWithoutRuntime](cops_sorbet.md#sorbetforbidsigwithoutruntime)
|
29
29
|
* [Sorbet/ForbidSuperclassConstLiteral](cops_sorbet.md#sorbetforbidsuperclassconstliteral)
|
30
|
+
* [Sorbet/ForbidTAbsurd](cops_sorbet.md#sorbetforbidtabsurd)
|
31
|
+
* [Sorbet/ForbidTBind](cops_sorbet.md#sorbetforbidtbind)
|
32
|
+
* [Sorbet/ForbidTCast](cops_sorbet.md#sorbetforbidtcast)
|
30
33
|
* [Sorbet/ForbidTEnum](cops_sorbet.md#sorbetforbidtenum)
|
34
|
+
* [Sorbet/ForbidTLet](cops_sorbet.md#sorbetforbidtlet)
|
35
|
+
* [Sorbet/ForbidTMust](cops_sorbet.md#sorbetforbidtmust)
|
31
36
|
* [Sorbet/ForbidTStruct](cops_sorbet.md#sorbetforbidtstruct)
|
37
|
+
* [Sorbet/ForbidTTypeAlias](cops_sorbet.md#sorbetforbidttypealias)
|
32
38
|
* [Sorbet/ForbidTUnsafe](cops_sorbet.md#sorbetforbidtunsafe)
|
33
39
|
* [Sorbet/ForbidTUntyped](cops_sorbet.md#sorbetforbidtuntyped)
|
34
40
|
* [Sorbet/ForbidTypeAliasedShapes](cops_sorbet.md#sorbetforbidtypealiasedshapes)
|
data/manual/cops_sorbet.md
CHANGED
@@ -331,12 +331,13 @@ You can configure the placeholders used by changing the following options:
|
|
331
331
|
|
332
332
|
* `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
|
333
333
|
* `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
|
334
|
+
* `Style`: signature style to enforce - 'sig' for sig blocks, 'rbs' for RBS comments, 'both' to allow either (default: 'sig')
|
334
335
|
|
335
336
|
### Configurable attributes
|
336
337
|
|
337
338
|
Name | Default value | Configurable values
|
338
339
|
--- | --- | ---
|
339
|
-
|
340
|
+
Style | `sig` | String
|
340
341
|
|
341
342
|
## Sorbet/EnforceSingleSigil
|
342
343
|
|
@@ -632,6 +633,60 @@ Name | Default value | Configurable values
|
|
632
633
|
--- | --- | ---
|
633
634
|
Exclude | `db/migrate/*.rb` | Array
|
634
635
|
|
636
|
+
## Sorbet/ForbidTAbsurd
|
637
|
+
|
638
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
639
|
+
--- | --- | --- | --- | ---
|
640
|
+
Disabled | Yes | No | 0.10.4 | -
|
641
|
+
|
642
|
+
Disallows using `T.absurd` anywhere.
|
643
|
+
|
644
|
+
### Examples
|
645
|
+
|
646
|
+
```ruby
|
647
|
+
# bad
|
648
|
+
T.absurd(foo)
|
649
|
+
|
650
|
+
# good
|
651
|
+
x #: absurd
|
652
|
+
```
|
653
|
+
|
654
|
+
## Sorbet/ForbidTBind
|
655
|
+
|
656
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
657
|
+
--- | --- | --- | --- | ---
|
658
|
+
Disabled | Yes | No | 0.10.4 | -
|
659
|
+
|
660
|
+
Disallows using `T.bind` anywhere.
|
661
|
+
|
662
|
+
### Examples
|
663
|
+
|
664
|
+
```ruby
|
665
|
+
# bad
|
666
|
+
T.bind(self, Integer)
|
667
|
+
|
668
|
+
# good
|
669
|
+
#: self as Integer
|
670
|
+
```
|
671
|
+
|
672
|
+
## Sorbet/ForbidTCast
|
673
|
+
|
674
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
675
|
+
--- | --- | --- | --- | ---
|
676
|
+
Disabled | Yes | No | 0.10.4 | -
|
677
|
+
|
678
|
+
Disallows using `T.cast` anywhere.
|
679
|
+
|
680
|
+
### Examples
|
681
|
+
|
682
|
+
```ruby
|
683
|
+
# bad
|
684
|
+
T.cast(foo, Integer)
|
685
|
+
|
686
|
+
# good
|
687
|
+
foo #: as Integer
|
688
|
+
```
|
689
|
+
|
635
690
|
## Sorbet/ForbidTEnum
|
636
691
|
|
637
692
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -659,6 +714,42 @@ class MyEnum
|
|
659
714
|
end
|
660
715
|
```
|
661
716
|
|
717
|
+
## Sorbet/ForbidTLet
|
718
|
+
|
719
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
720
|
+
--- | --- | --- | --- | ---
|
721
|
+
Disabled | Yes | No | 0.10.4 | -
|
722
|
+
|
723
|
+
Disallows using `T.let` anywhere.
|
724
|
+
|
725
|
+
### Examples
|
726
|
+
|
727
|
+
```ruby
|
728
|
+
# bad
|
729
|
+
T.let(foo, Integer)
|
730
|
+
|
731
|
+
# good
|
732
|
+
foo #: Integer
|
733
|
+
```
|
734
|
+
|
735
|
+
## Sorbet/ForbidTMust
|
736
|
+
|
737
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
738
|
+
--- | --- | --- | --- | ---
|
739
|
+
Disabled | Yes | No | 0.10.4 | -
|
740
|
+
|
741
|
+
Disallows using `T.must` anywhere.
|
742
|
+
|
743
|
+
### Examples
|
744
|
+
|
745
|
+
```ruby
|
746
|
+
# bad
|
747
|
+
T.must(foo)
|
748
|
+
|
749
|
+
# good
|
750
|
+
foo #: as !nil
|
751
|
+
```
|
752
|
+
|
662
753
|
## Sorbet/ForbidTStruct
|
663
754
|
|
664
755
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -698,6 +789,24 @@ class MyStruct
|
|
698
789
|
end
|
699
790
|
```
|
700
791
|
|
792
|
+
## Sorbet/ForbidTTypeAlias
|
793
|
+
|
794
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
795
|
+
--- | --- | --- | --- | ---
|
796
|
+
Disabled | Yes | No | 0.10.4 | -
|
797
|
+
|
798
|
+
Disallows using `T.type_alias` anywhere.
|
799
|
+
|
800
|
+
### Examples
|
801
|
+
|
802
|
+
```ruby
|
803
|
+
# bad
|
804
|
+
STRING_OR_INTEGER = T.type_alias { T.any(Integer, String) }
|
805
|
+
|
806
|
+
# good
|
807
|
+
#: type string_or_integer = Integer | String
|
808
|
+
```
|
809
|
+
|
701
810
|
## Sorbet/ForbidTUnsafe
|
702
811
|
|
703
812
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-sorbet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -84,8 +84,14 @@ files:
|
|
84
84
|
- lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
|
85
85
|
- lib/rubocop/cop/sorbet/forbid_mixes_in_class_methods.rb
|
86
86
|
- lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb
|
87
|
+
- lib/rubocop/cop/sorbet/forbid_t_absurd.rb
|
88
|
+
- lib/rubocop/cop/sorbet/forbid_t_bind.rb
|
89
|
+
- lib/rubocop/cop/sorbet/forbid_t_cast.rb
|
87
90
|
- lib/rubocop/cop/sorbet/forbid_t_enum.rb
|
91
|
+
- lib/rubocop/cop/sorbet/forbid_t_let.rb
|
92
|
+
- lib/rubocop/cop/sorbet/forbid_t_must.rb
|
88
93
|
- lib/rubocop/cop/sorbet/forbid_t_struct.rb
|
94
|
+
- lib/rubocop/cop/sorbet/forbid_t_type_alias.rb
|
89
95
|
- lib/rubocop/cop/sorbet/forbid_t_unsafe.rb
|
90
96
|
- lib/rubocop/cop/sorbet/forbid_t_untyped.rb
|
91
97
|
- lib/rubocop/cop/sorbet/forbid_type_aliased_shapes.rb
|