rubocop-sorbet 0.10.2 → 0.10.4
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 +5 -5
- data/Rakefile +4 -4
- data/VERSION +1 -1
- data/config/default.yml +37 -0
- data/lib/rubocop/cop/sorbet/block_method_definition.rb +127 -6
- 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/capitalized_type_parameters.rb +70 -0
- data/lib/rubocop/cop/sorbet_cops.rb +7 -0
- data/lib/rubocop/sorbet/version.rb +1 -1
- data/manual/cops.md +7 -0
- data/manual/cops_sorbet.md +147 -1
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79bcbc5d5d2a20065dae6bd132ce89a78f6d55d913253f582d57b26dbc90e3fe
|
4
|
+
data.tar.gz: fc68fab55a25f15a2689564842768d87b2268ed99e8bdcf503284e47dd82deb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b67f844675e5ca0c5f229cf8dd55e091f12c068dcaeb0cf289eded28a92367d32ead0f315ca4776bd0acd04e743c3c0420c345ac1ac6a7041f84dc61cc1fa78
|
7
|
+
data.tar.gz: ca77c4f1a29809ce05da20319309c760dff38fcf4adae09b60e4a588a24ca234a32c6a48226df8baa9eaa169b388953e4f65cb079a47d22f062924efdf3b9c3b
|
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.4)
|
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.
|
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)
|
@@ -47,17 +47,17 @@ GEM
|
|
47
47
|
parser (>= 3.3.0.2)
|
48
48
|
rainbow (>= 2.2.2, < 4.0)
|
49
49
|
regexp_parser (>= 2.9.3, < 3.0)
|
50
|
-
rubocop-ast (>= 1.
|
50
|
+
rubocop-ast (>= 1.45.0, < 2.0)
|
51
51
|
ruby-progressbar (~> 1.7)
|
52
52
|
unicode-display_width (>= 2.4.0, < 4.0)
|
53
|
-
rubocop-ast (1.
|
53
|
+
rubocop-ast (1.45.1)
|
54
54
|
parser (>= 3.3.7.2)
|
55
55
|
prism (~> 1.4)
|
56
56
|
rubocop-minitest (0.38.1)
|
57
57
|
lint_roller (~> 1.1)
|
58
58
|
rubocop (>= 1.75.0, < 2.0)
|
59
59
|
rubocop-ast (>= 1.38.0, < 2.0)
|
60
|
-
rubocop-shopify (2.17.
|
60
|
+
rubocop-shopify (2.17.1)
|
61
61
|
rubocop (~> 1.62)
|
62
62
|
ruby-progressbar (1.13.0)
|
63
63
|
ruby2_keywords (0.0.5)
|
data/Rakefile
CHANGED
@@ -60,10 +60,10 @@ module Releaser
|
|
60
60
|
|
61
61
|
sh "git add lib/rubocop/sorbet/version.rb config/default.yml Gemfile.lock VERSION manual"
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
sh "git commit -m 'Release v#{version}'"
|
64
|
+
sh "git push origin main"
|
65
|
+
sh "git tag -a v#{version} -m 'Release v#{version}'"
|
66
|
+
sh "git push origin v#{version}"
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.3
|
data/config/default.yml
CHANGED
@@ -23,6 +23,7 @@ Sorbet/BlockMethodDefinition:
|
|
23
23
|
Safe: true
|
24
24
|
SafeAutoCorrect: false
|
25
25
|
VersionAdded: '0.10.1'
|
26
|
+
VersionChanged: '0.10.3'
|
26
27
|
|
27
28
|
Sorbet/BuggyObsoleteStrictMemoization:
|
28
29
|
Description: >-
|
@@ -47,6 +48,12 @@ Sorbet/CallbackConditionalsBinding:
|
|
47
48
|
Safe: false
|
48
49
|
VersionAdded: 0.7.0
|
49
50
|
|
51
|
+
Sorbet/CapitalizedTypeParameters:
|
52
|
+
Description: 'Ensures that type parameters are capitalized.'
|
53
|
+
Enabled: true
|
54
|
+
SafeAutoCorrect: false
|
55
|
+
VersionAdded: '0.10.3'
|
56
|
+
|
50
57
|
Sorbet/CheckedTrueInSignature:
|
51
58
|
Description: 'Disallows the usage of `checked(true)` in signatures.'
|
52
59
|
Enabled: true
|
@@ -164,6 +171,36 @@ Sorbet/ForbidTStruct:
|
|
164
171
|
VersionAdded: 0.7.4
|
165
172
|
Safe: false
|
166
173
|
|
174
|
+
Sorbet/ForbidTAbsurd:
|
175
|
+
Description: 'Forbid usage of T.absurd.'
|
176
|
+
Enabled: false
|
177
|
+
VersionAdded: <<next>>
|
178
|
+
|
179
|
+
Sorbet/ForbidTBind:
|
180
|
+
Description: 'Forbid usage of T.bind.'
|
181
|
+
Enabled: false
|
182
|
+
VersionAdded: <<next>>
|
183
|
+
|
184
|
+
Sorbet/ForbidTCast:
|
185
|
+
Description: 'Forbid usage of T.cast.'
|
186
|
+
Enabled: false
|
187
|
+
VersionAdded: <<next>>
|
188
|
+
|
189
|
+
Sorbet/ForbidTLet:
|
190
|
+
Description: 'Forbid usage of T.let.'
|
191
|
+
Enabled: false
|
192
|
+
VersionAdded: <<next>>
|
193
|
+
|
194
|
+
Sorbet/ForbidTMust:
|
195
|
+
Description: 'Forbid usage of T.must.'
|
196
|
+
Enabled: false
|
197
|
+
VersionAdded: <<next>>
|
198
|
+
|
199
|
+
Sorbet/ForbidTTypeAlias:
|
200
|
+
Description: 'Forbid usage of T.type_alias.'
|
201
|
+
Enabled: false
|
202
|
+
VersionAdded: <<next>>
|
203
|
+
|
167
204
|
Sorbet/ForbidTUnsafe:
|
168
205
|
Description: 'Forbid usage of T.unsafe.'
|
169
206
|
Enabled: false
|
@@ -10,7 +10,8 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# The one exception is for `Class.new` blocks, as long as the result is
|
12
12
|
# assigned to a constant (i.e. as long as it is not an anonymous class).
|
13
|
-
|
13
|
+
# Another exception is for ActiveSupport::Concern `class_methods` blocks.
|
14
|
+
#
|
14
15
|
# @example
|
15
16
|
# # bad
|
16
17
|
# yielding_method do
|
@@ -40,17 +41,50 @@ module RuboCop
|
|
40
41
|
# end
|
41
42
|
# end
|
42
43
|
#
|
44
|
+
# # good
|
45
|
+
# module SomeConcern
|
46
|
+
# extend ActiveSupport::Concern
|
47
|
+
#
|
48
|
+
# class_methods do
|
49
|
+
# def good(args)
|
50
|
+
# # ...
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
43
55
|
class BlockMethodDefinition < Base
|
44
56
|
include RuboCop::Cop::Alignment
|
45
57
|
extend AutoCorrector
|
46
58
|
|
47
59
|
MSG = "Do not define methods in blocks (use `define_method` as a workaround)."
|
48
60
|
|
61
|
+
# @!method activesupport_concern_class_methods_block?(node)
|
62
|
+
def_node_matcher :activesupport_concern_class_methods_block?, <<~PATTERN
|
63
|
+
(block
|
64
|
+
(send nil? :class_methods)
|
65
|
+
_
|
66
|
+
_
|
67
|
+
)
|
68
|
+
PATTERN
|
69
|
+
|
70
|
+
# @!method module_extends_activesupport_concern?(node)
|
71
|
+
def_node_matcher :module_extends_activesupport_concern?, <<~PATTERN
|
72
|
+
(module _
|
73
|
+
(begin
|
74
|
+
<(send nil? :extend (const (const {nil? cbase} :ActiveSupport) :Concern)) ...>
|
75
|
+
...
|
76
|
+
)
|
77
|
+
)
|
78
|
+
PATTERN
|
79
|
+
|
49
80
|
def on_block(node)
|
50
81
|
if (parent = node.parent)
|
51
82
|
return if parent.casgn_type?
|
52
83
|
end
|
53
84
|
|
85
|
+
# Check if this is a class_methods block inside an ActiveSupport::Concern
|
86
|
+
return if in_activesupport_concern_class_methods_block?(node)
|
87
|
+
|
54
88
|
node.each_descendant(:any_def) do |def_node|
|
55
89
|
add_offense(def_node) do |corrector|
|
56
90
|
autocorrect_method_in_block(corrector, def_node)
|
@@ -61,21 +95,108 @@ module RuboCop
|
|
61
95
|
|
62
96
|
private
|
63
97
|
|
98
|
+
def in_activesupport_concern_class_methods_block?(node)
|
99
|
+
return false unless activesupport_concern_class_methods_block?(node)
|
100
|
+
|
101
|
+
immediate_module = node.each_ancestor(:module).first
|
102
|
+
|
103
|
+
module_extends_activesupport_concern?(immediate_module)
|
104
|
+
end
|
105
|
+
|
64
106
|
def autocorrect_method_in_block(corrector, node)
|
65
107
|
indent = offset(node)
|
66
108
|
|
67
109
|
method_name = node.method_name
|
68
|
-
args = node
|
69
|
-
body = node.body&.source&.prepend("\n#{indent} ")
|
110
|
+
args = transform_args_to_block_args(node)
|
70
111
|
|
112
|
+
# Build the method signature replacement
|
71
113
|
if node.def_type?
|
72
|
-
|
114
|
+
signature_replacement = "define_method(:#{method_name}) do#{args}"
|
73
115
|
elsif node.defs_type?
|
74
116
|
receiver = node.receiver.source
|
75
|
-
|
117
|
+
signature_replacement = "#{receiver}.define_singleton_method(:#{method_name}) do#{args}"
|
118
|
+
end
|
119
|
+
|
120
|
+
if node.body
|
121
|
+
end_pos = node.body.source_range.begin_pos
|
122
|
+
indentation = "\n#{indent} "
|
123
|
+
else
|
124
|
+
end_pos, indentation = handle_method_without_body(node, indent)
|
76
125
|
end
|
77
126
|
|
78
|
-
|
127
|
+
signature_range = node.source_range.with(end_pos: end_pos)
|
128
|
+
|
129
|
+
corrector.replace(signature_range, signature_replacement + indentation)
|
130
|
+
end
|
131
|
+
|
132
|
+
def transform_args_to_block_args(node)
|
133
|
+
args = node.arguments
|
134
|
+
|
135
|
+
if args.empty?
|
136
|
+
""
|
137
|
+
else
|
138
|
+
args_string = args.map(&:source).join(", ")
|
139
|
+
" |#{args_string}|"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def handle_method_without_body(node, indent)
|
144
|
+
if single_line_method?(node)
|
145
|
+
handle_single_line_method(node, indent)
|
146
|
+
else
|
147
|
+
handle_multiline_method_without_body(node)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def single_line_method?(node)
|
152
|
+
!node.source.include?("\n")
|
153
|
+
end
|
154
|
+
|
155
|
+
def handle_single_line_method(node, indent)
|
156
|
+
end_pos = node.source_range.end_pos
|
157
|
+
indentation = "\n#{indent}end"
|
158
|
+
[end_pos, indentation]
|
159
|
+
end
|
160
|
+
|
161
|
+
def handle_multiline_method_without_body(node)
|
162
|
+
end_pos = find_method_signature_end_position(node)
|
163
|
+
indentation = ""
|
164
|
+
[end_pos, indentation]
|
165
|
+
end
|
166
|
+
|
167
|
+
def find_method_signature_end_position(node)
|
168
|
+
if node.arguments.any?
|
169
|
+
find_end_position_with_arguments(node)
|
170
|
+
else
|
171
|
+
find_end_position_without_arguments(node)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def find_end_position_with_arguments(node)
|
176
|
+
last_arg = node.last_argument
|
177
|
+
end_pos = last_arg.source_range.end_pos
|
178
|
+
|
179
|
+
adjust_for_closing_parenthesis(end_pos)
|
180
|
+
end
|
181
|
+
|
182
|
+
def find_end_position_without_arguments(node)
|
183
|
+
node.loc.name.end_pos
|
184
|
+
end
|
185
|
+
|
186
|
+
def adjust_for_closing_parenthesis(end_pos)
|
187
|
+
source_after_last_arg = processed_source.buffer.source[end_pos..-1]
|
188
|
+
|
189
|
+
match = closing_parenthesis_follows(source_after_last_arg)
|
190
|
+
|
191
|
+
if match
|
192
|
+
end_pos + match.end(0)
|
193
|
+
else
|
194
|
+
end_pos
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def closing_parenthesis_follows(source)
|
199
|
+
source.match(/\A\s*\)/)
|
79
200
|
end
|
80
201
|
end
|
81
202
|
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.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
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Sorbet
|
6
|
+
# Ensure type parameters used in generic methods are always capitalized.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# sig { type_parameters(:x).params(a: T.type_parameter(:x)).void }
|
12
|
+
# def foo(a); end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# sig { type_parameters(:X).params(a: T.type_parameter(:X)).void }
|
16
|
+
# def foo(a: 1); end
|
17
|
+
class CapitalizedTypeParameters < ::RuboCop::Cop::Base
|
18
|
+
extend AutoCorrector
|
19
|
+
include SignatureHelp
|
20
|
+
|
21
|
+
MSG = "Type parameters must be capitalized."
|
22
|
+
|
23
|
+
RESTRICT_ON_SEND = [:type_parameter].freeze
|
24
|
+
|
25
|
+
# @!method type_parameters?(node)
|
26
|
+
def_node_matcher(:type_parameters?, <<-PATTERN)
|
27
|
+
(send nil? :type_parameters ...)
|
28
|
+
PATTERN
|
29
|
+
|
30
|
+
# @!method t_type_parameter?(node)
|
31
|
+
def_node_matcher(:t_type_parameter?, <<-PATTERN)
|
32
|
+
(send (const {nil? | cbase} :T) :type_parameter ...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_signature(node)
|
36
|
+
send = node.children[2]
|
37
|
+
|
38
|
+
while send&.send_type?
|
39
|
+
if type_parameters?(send)
|
40
|
+
check_type_parameters_case(send)
|
41
|
+
end
|
42
|
+
|
43
|
+
send = send.children[0]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_send(node)
|
48
|
+
check_type_parameters_case(node) if t_type_parameter?(node)
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_csend(node)
|
52
|
+
check_type_parameters_case(node) if t_type_parameter?(node)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def check_type_parameters_case(node)
|
58
|
+
node.children[2..].each do |arg|
|
59
|
+
next unless arg.is_a?(RuboCop::AST::SymbolNode)
|
60
|
+
next if arg.value =~ /^[A-Z]/
|
61
|
+
|
62
|
+
add_offense(arg) do |corrector|
|
63
|
+
corrector.replace(arg, arg.value.capitalize.to_sym.inspect)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
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"
|
@@ -33,6 +39,7 @@ require_relative "sorbet/rbi_versioning/gem_version_annotation_helper"
|
|
33
39
|
require_relative "sorbet/rbi_versioning/valid_gem_version_annotations"
|
34
40
|
|
35
41
|
require_relative "sorbet/signatures/allow_incompatible_override"
|
42
|
+
require_relative "sorbet/signatures/capitalized_type_parameters"
|
36
43
|
require_relative "sorbet/signatures/checked_true_in_signature"
|
37
44
|
require_relative "sorbet/signatures/empty_line_after_sig"
|
38
45
|
require_relative "sorbet/signatures/enforce_signatures"
|
data/manual/cops.md
CHANGED
@@ -10,6 +10,7 @@ In the following section you find all available cops:
|
|
10
10
|
* [Sorbet/BlockMethodDefinition](cops_sorbet.md#sorbetblockmethoddefinition)
|
11
11
|
* [Sorbet/BuggyObsoleteStrictMemoization](cops_sorbet.md#sorbetbuggyobsoletestrictmemoization)
|
12
12
|
* [Sorbet/CallbackConditionalsBinding](cops_sorbet.md#sorbetcallbackconditionalsbinding)
|
13
|
+
* [Sorbet/CapitalizedTypeParameters](cops_sorbet.md#sorbetcapitalizedtypeparameters)
|
13
14
|
* [Sorbet/CheckedTrueInSignature](cops_sorbet.md#sorbetcheckedtrueinsignature)
|
14
15
|
* [Sorbet/ConstantsFromStrings](cops_sorbet.md#sorbetconstantsfromstrings)
|
15
16
|
* [Sorbet/EmptyLineAfterSig](cops_sorbet.md#sorbetemptylineaftersig)
|
@@ -26,8 +27,14 @@ In the following section you find all available cops:
|
|
26
27
|
* [Sorbet/ForbidSigWithRuntime](cops_sorbet.md#sorbetforbidsigwithruntime)
|
27
28
|
* [Sorbet/ForbidSigWithoutRuntime](cops_sorbet.md#sorbetforbidsigwithoutruntime)
|
28
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)
|
29
33
|
* [Sorbet/ForbidTEnum](cops_sorbet.md#sorbetforbidtenum)
|
34
|
+
* [Sorbet/ForbidTLet](cops_sorbet.md#sorbetforbidtlet)
|
35
|
+
* [Sorbet/ForbidTMust](cops_sorbet.md#sorbetforbidtmust)
|
30
36
|
* [Sorbet/ForbidTStruct](cops_sorbet.md#sorbetforbidtstruct)
|
37
|
+
* [Sorbet/ForbidTTypeAlias](cops_sorbet.md#sorbetforbidttypealias)
|
31
38
|
* [Sorbet/ForbidTUnsafe](cops_sorbet.md#sorbetforbidtunsafe)
|
32
39
|
* [Sorbet/ForbidTUntyped](cops_sorbet.md#sorbetforbidtuntyped)
|
33
40
|
* [Sorbet/ForbidTypeAliasedShapes](cops_sorbet.md#sorbetforbidtypealiasedshapes)
|
data/manual/cops_sorbet.md
CHANGED
@@ -45,9 +45,16 @@ FooOrBar = T.type_alias { T.any(Foo, Bar) }
|
|
45
45
|
|
46
46
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
47
47
|
--- | --- | --- | --- | ---
|
48
|
-
Enabled | Yes | Yes (Unsafe) | 0.10.1 |
|
48
|
+
Enabled | Yes | Yes (Unsafe) | 0.10.1 | 0.10.3
|
49
49
|
|
50
|
+
Disallow defining methods in blocks, to prevent running into issues
|
51
|
+
caused by https://github.com/sorbet/sorbet/issues/3609.
|
50
52
|
|
53
|
+
As a workaround, use `define_method` instead.
|
54
|
+
|
55
|
+
The one exception is for `Class.new` blocks, as long as the result is
|
56
|
+
assigned to a constant (i.e. as long as it is not an anonymous class).
|
57
|
+
Another exception is for ActiveSupport::Concern `class_methods` blocks.
|
51
58
|
|
52
59
|
### Examples
|
53
60
|
|
@@ -79,6 +86,17 @@ MyClass = Class.new do
|
|
79
86
|
# ...
|
80
87
|
end
|
81
88
|
end
|
89
|
+
|
90
|
+
# good
|
91
|
+
module SomeConcern
|
92
|
+
extend ActiveSupport::Concern
|
93
|
+
|
94
|
+
class_methods do
|
95
|
+
def good(args)
|
96
|
+
# ...
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
82
100
|
```
|
83
101
|
|
84
102
|
## Sorbet/BuggyObsoleteStrictMemoization
|
@@ -157,6 +175,26 @@ class Post < ApplicationRecord
|
|
157
175
|
end
|
158
176
|
```
|
159
177
|
|
178
|
+
## Sorbet/CapitalizedTypeParameters
|
179
|
+
|
180
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
181
|
+
--- | --- | --- | --- | ---
|
182
|
+
Enabled | Yes | Yes (Unsafe) | 0.10.3 | -
|
183
|
+
|
184
|
+
Ensure type parameters used in generic methods are always capitalized.
|
185
|
+
|
186
|
+
### Examples
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
# bad
|
190
|
+
sig { type_parameters(:x).params(a: T.type_parameter(:x)).void }
|
191
|
+
def foo(a); end
|
192
|
+
|
193
|
+
# good
|
194
|
+
sig { type_parameters(:X).params(a: T.type_parameter(:X)).void }
|
195
|
+
def foo(a: 1); end
|
196
|
+
```
|
197
|
+
|
160
198
|
## Sorbet/CheckedTrueInSignature
|
161
199
|
|
162
200
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -594,6 +632,60 @@ Name | Default value | Configurable values
|
|
594
632
|
--- | --- | ---
|
595
633
|
Exclude | `db/migrate/*.rb` | Array
|
596
634
|
|
635
|
+
## Sorbet/ForbidTAbsurd
|
636
|
+
|
637
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
638
|
+
--- | --- | --- | --- | ---
|
639
|
+
Disabled | Yes | No | <<next>> | -
|
640
|
+
|
641
|
+
Disallows using `T.absurd` anywhere.
|
642
|
+
|
643
|
+
### Examples
|
644
|
+
|
645
|
+
```ruby
|
646
|
+
# bad
|
647
|
+
T.absurd(foo)
|
648
|
+
|
649
|
+
# good
|
650
|
+
x #: absurd
|
651
|
+
```
|
652
|
+
|
653
|
+
## Sorbet/ForbidTBind
|
654
|
+
|
655
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
656
|
+
--- | --- | --- | --- | ---
|
657
|
+
Disabled | Yes | No | <<next>> | -
|
658
|
+
|
659
|
+
Disallows using `T.bind` anywhere.
|
660
|
+
|
661
|
+
### Examples
|
662
|
+
|
663
|
+
```ruby
|
664
|
+
# bad
|
665
|
+
T.bind(self, Integer)
|
666
|
+
|
667
|
+
# good
|
668
|
+
#: self as Integer
|
669
|
+
```
|
670
|
+
|
671
|
+
## Sorbet/ForbidTCast
|
672
|
+
|
673
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
674
|
+
--- | --- | --- | --- | ---
|
675
|
+
Disabled | Yes | No | <<next>> | -
|
676
|
+
|
677
|
+
Disallows using `T.cast` anywhere.
|
678
|
+
|
679
|
+
### Examples
|
680
|
+
|
681
|
+
```ruby
|
682
|
+
# bad
|
683
|
+
T.cast(foo, Integer)
|
684
|
+
|
685
|
+
# good
|
686
|
+
foo #: as Integer
|
687
|
+
```
|
688
|
+
|
597
689
|
## Sorbet/ForbidTEnum
|
598
690
|
|
599
691
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -621,6 +713,42 @@ class MyEnum
|
|
621
713
|
end
|
622
714
|
```
|
623
715
|
|
716
|
+
## Sorbet/ForbidTLet
|
717
|
+
|
718
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
719
|
+
--- | --- | --- | --- | ---
|
720
|
+
Disabled | Yes | No | <<next>> | -
|
721
|
+
|
722
|
+
Disallows using `T.let` anywhere.
|
723
|
+
|
724
|
+
### Examples
|
725
|
+
|
726
|
+
```ruby
|
727
|
+
# bad
|
728
|
+
T.let(foo, Integer)
|
729
|
+
|
730
|
+
# good
|
731
|
+
foo #: Integer
|
732
|
+
```
|
733
|
+
|
734
|
+
## Sorbet/ForbidTMust
|
735
|
+
|
736
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
737
|
+
--- | --- | --- | --- | ---
|
738
|
+
Disabled | Yes | No | <<next>> | -
|
739
|
+
|
740
|
+
Disallows using `T.must` anywhere.
|
741
|
+
|
742
|
+
### Examples
|
743
|
+
|
744
|
+
```ruby
|
745
|
+
# bad
|
746
|
+
T.must(foo)
|
747
|
+
|
748
|
+
# good
|
749
|
+
foo #: as !nil
|
750
|
+
```
|
751
|
+
|
624
752
|
## Sorbet/ForbidTStruct
|
625
753
|
|
626
754
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -660,6 +788,24 @@ class MyStruct
|
|
660
788
|
end
|
661
789
|
```
|
662
790
|
|
791
|
+
## Sorbet/ForbidTTypeAlias
|
792
|
+
|
793
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
794
|
+
--- | --- | --- | --- | ---
|
795
|
+
Disabled | Yes | No | <<next>> | -
|
796
|
+
|
797
|
+
Disallows using `T.type_alias` anywhere.
|
798
|
+
|
799
|
+
### Examples
|
800
|
+
|
801
|
+
```ruby
|
802
|
+
# bad
|
803
|
+
STRING_OR_INTEGER = T.type_alias { T.any(Integer, String) }
|
804
|
+
|
805
|
+
# good
|
806
|
+
#: type string_or_integer = Integer | String
|
807
|
+
```
|
808
|
+
|
663
809
|
## Sorbet/ForbidTUnsafe
|
664
810
|
|
665
811
|
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.4
|
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
|
@@ -114,6 +120,7 @@ files:
|
|
114
120
|
- lib/rubocop/cop/sorbet/sigils/true_sigil.rb
|
115
121
|
- lib/rubocop/cop/sorbet/sigils/valid_sigil.rb
|
116
122
|
- lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb
|
123
|
+
- lib/rubocop/cop/sorbet/signatures/capitalized_type_parameters.rb
|
117
124
|
- lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb
|
118
125
|
- lib/rubocop/cop/sorbet/signatures/empty_line_after_sig.rb
|
119
126
|
- lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb
|