rubocop-on-rbs 0.3.0 → 0.4.0
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/CHANGELOG.md +8 -0
- data/README.md +4 -2
- data/config/default.yml +18 -52
- data/lib/rubocop/cop/rbs/layout/space_around_operators.rb +66 -0
- data/lib/rubocop/cop/rbs/lint/literal_intersection.rb +59 -0
- data/lib/rubocop/cop/rbs/lint/{redundant_overload_type_params.rb → useless_overload_type_params.rb} +4 -19
- data/lib/rubocop/cop/rbs/style/empty_argument.rb +103 -0
- data/lib/rubocop/cop/rbs/style/initialize_return_type.rb +4 -4
- data/lib/rubocop/cop/rbs/style/redundant_parentheses.rb +152 -0
- data/lib/rubocop/cop/rbs_cops.rb +7 -5
- data/lib/rubocop/rbs/cop_base.rb +26 -0
- data/lib/rubocop/rbs/version.rb +1 -1
- metadata +7 -5
- data/lib/rubocop/cop/rbs/lint/type_params_arity.rb +0 -170
- data/lib/rubocop/cop/rbs/style/merge_untyped.rb +0 -91
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adb415dc438caa7d859497f2915d37fe647ba2c0a0c396a1afc79f6aec2a53ee
|
4
|
+
data.tar.gz: 621b0e9338aab521860cf7e73c7b346015f3e9e51b6af06d9159b1844083281a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e3357ceba540c5c6ee25188804ebe95965147e47970bc39c98fd8fe60eb8f52af762c1a3a90ca9e68be9d63e2263622cffc983b029232fd23f89d6f536a12b3
|
7
|
+
data.tar.gz: a9155f9687029947fb9bb4d0c47332a5bc3075e400872ebf1e58312f7d6cd47ffa0d37c4005c644adb08e88494c8c14d84a063e2550590db93c75ac7e95f0136
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.0] - 2024-06-11
|
4
|
+
|
5
|
+
* Implement RedundantOverloadTypeParams instead of UselessOverloadTypeParams by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/1
|
6
|
+
* Introduce RBS/Lint/DuplicateOverload by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/2
|
7
|
+
* Fix typo by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/3
|
8
|
+
* Remove unnecessary Exclude settings in .rubocop.yml by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/4
|
9
|
+
* Generate docs for cop by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/5
|
10
|
+
|
3
11
|
## [0.1.0] - 2024-05-15
|
4
12
|
|
5
13
|
- Initial release
|
data/README.md
CHANGED
@@ -64,6 +64,10 @@ And restart VSCode.
|
|
64
64
|
|
65
65
|
## Departments
|
66
66
|
|
67
|
+
You can see documentation for all cops.
|
68
|
+
|
69
|
+
https://github.com/ksss/rubocop-on-rbs/blob/main/docs/modules/ROOT/pages/cops.adoc
|
70
|
+
|
67
71
|
### RBS
|
68
72
|
|
69
73
|
This gem handles many cops.
|
@@ -74,8 +78,6 @@ RBS:
|
|
74
78
|
Enabled: true
|
75
79
|
```
|
76
80
|
|
77
|
-
See `config/default.yml` for all Cop.
|
78
|
-
|
79
81
|
### RBS/Layout
|
80
82
|
|
81
83
|
This department is a collection of relatively minor fixes has been gathered.
|
data/config/default.yml
CHANGED
@@ -59,6 +59,10 @@ RBS/Layout/SpaceAroundBraces:
|
|
59
59
|
Description: 'Use space around `{}`'
|
60
60
|
Enabled: true
|
61
61
|
|
62
|
+
RBS/Layout/SpaceAroundOperators:
|
63
|
+
Description: 'Use space around `|` or `&`'
|
64
|
+
Enabled: true
|
65
|
+
|
62
66
|
RBS/Layout/SpaceBeforeColon:
|
63
67
|
Description: 'Use space before `:`'
|
64
68
|
Enabled: true
|
@@ -81,7 +85,12 @@ RBS/Lint/DuplicateOverload:
|
|
81
85
|
Description: 'Checks that there are no repeated overload bodies'
|
82
86
|
Enabled: true
|
83
87
|
|
84
|
-
RBS/Lint/
|
88
|
+
RBS/Lint/LiteralIntersection:
|
89
|
+
Severity: warning
|
90
|
+
Description: 'Check literal intersection'
|
91
|
+
Enabled: true
|
92
|
+
|
93
|
+
RBS/Lint/UselessOverloadTypeParams:
|
85
94
|
Severity: warning
|
86
95
|
Description: 'Check redundant overload type params'
|
87
96
|
Enabled: true
|
@@ -91,53 +100,6 @@ RBS/Lint/Syntax:
|
|
91
100
|
Description: 'Check RBS syntax'
|
92
101
|
Enabled: true
|
93
102
|
|
94
|
-
RBS/Lint/TypeParamsArity:
|
95
|
-
Severity: warning
|
96
|
-
Description: 'Check type params arity'
|
97
|
-
Enabled: true
|
98
|
-
Expects:
|
99
|
-
# Default expects.
|
100
|
-
# You can add expects in .rubocop.yml.
|
101
|
-
|
102
|
-
## class/module
|
103
|
-
Array: 1
|
104
|
-
Enumerable: 1
|
105
|
-
Enumerator: 2
|
106
|
-
Enumerator::Chain: 1
|
107
|
-
Enumerator::Generator: 1
|
108
|
-
Enumerator::Lazy: 2
|
109
|
-
Enumerator::Product: 1
|
110
|
-
FrozenError: 1
|
111
|
-
Hash: 2
|
112
|
-
KeyError: 2
|
113
|
-
NameError: 1
|
114
|
-
NoMatchingPatternKeyError: 2
|
115
|
-
NoMethodError: 1
|
116
|
-
ObjectSpace::WeakKeyMap: 2
|
117
|
-
Range: 1
|
118
|
-
Set: 1
|
119
|
-
Struct: 1
|
120
|
-
|
121
|
-
## interface
|
122
|
-
Array::_Pattern: 1
|
123
|
-
Enumerable::_NotFound: 1
|
124
|
-
Gem::_HashLike: 2
|
125
|
-
Kernel::_RationalDiv: 1
|
126
|
-
Marshal::_Proc: 1
|
127
|
-
String::_MatchAgainst: 2
|
128
|
-
_Each: 1
|
129
|
-
_EachEntry: 1
|
130
|
-
_Range: 1
|
131
|
-
_ToA: 1
|
132
|
-
_ToAry: 1
|
133
|
-
_ToH: 2
|
134
|
-
_ToHash: 2
|
135
|
-
|
136
|
-
## type alias
|
137
|
-
array: 1
|
138
|
-
hash: 2
|
139
|
-
range: 1
|
140
|
-
|
141
103
|
RBS/Lint/WillSyntaxError:
|
142
104
|
Severity: warning
|
143
105
|
Description: 'Check RBS will syntax error'
|
@@ -160,18 +122,22 @@ RBS/Style/DuplicatedType:
|
|
160
122
|
Description: 'Check duplicated type'
|
161
123
|
Enabled: true
|
162
124
|
|
163
|
-
RBS/Style/
|
164
|
-
Description: 'Use `
|
125
|
+
RBS/Style/EmptyArgument:
|
126
|
+
Description: 'Use `()` for empty argument'
|
165
127
|
Enabled: true
|
166
128
|
|
167
|
-
RBS/Style/
|
168
|
-
Description: '
|
129
|
+
RBS/Style/InitializeReturnType:
|
130
|
+
Description: 'Use `void` for initialize method'
|
169
131
|
Enabled: true
|
170
132
|
|
171
133
|
RBS/Style/OptionalNil:
|
172
134
|
Description: 'Use nil instead of nil?'
|
173
135
|
Enabled: true
|
174
136
|
|
137
|
+
RBS/Style/RedundantParentheses:
|
138
|
+
Description: 'Remove redundant parentheses'
|
139
|
+
Enabled: true
|
140
|
+
|
175
141
|
RBS/Style/TrueFalse:
|
176
142
|
Description: 'Use bool instead of true | false'
|
177
143
|
Enabled: true
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Layout
|
7
|
+
# @example default
|
8
|
+
# # bad
|
9
|
+
# Integer|String
|
10
|
+
#
|
11
|
+
# # good
|
12
|
+
# Integer | String
|
13
|
+
class SpaceAroundOperators < RuboCop::RBS::CopBase
|
14
|
+
extend AutoCorrector
|
15
|
+
|
16
|
+
def on_rbs_def(decl)
|
17
|
+
decl.overloads.each do |overload|
|
18
|
+
overload.method_type.each_type do |type|
|
19
|
+
on_type(type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_type(type)
|
25
|
+
case type
|
26
|
+
when ::RBS::Types::Union
|
27
|
+
check_operator(type, '|')
|
28
|
+
when ::RBS::Types::Intersection
|
29
|
+
check_operator(type, '&')
|
30
|
+
end
|
31
|
+
type.each_type do |t|
|
32
|
+
on_type(t)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_operator(type, operator)
|
37
|
+
type.types.each_cons(2) do |before, after|
|
38
|
+
next unless before.location.end_line == after.location.start_line
|
39
|
+
|
40
|
+
operator_index = type.location.source.index(
|
41
|
+
operator,
|
42
|
+
before.location.end_pos - type.location.start_pos
|
43
|
+
) or raise
|
44
|
+
operator_index += type.location.start_pos
|
45
|
+
operator_range = range_between(operator_index, operator_index + 1)
|
46
|
+
|
47
|
+
before_char = processed_source.raw_source[operator_index - 1]
|
48
|
+
if before_char != ' '
|
49
|
+
add_offense(operator_range, message: "Use one space before `#{operator}`.") do |corrector|
|
50
|
+
corrector.insert_before(operator_range, ' ')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
after_char = processed_source.raw_source[operator_index + 1]
|
55
|
+
if after_char != ' '
|
56
|
+
add_offense(operator_range, message: "Use one space after `#{operator}`.") do |corrector|
|
57
|
+
corrector.insert_after(operator_range, ' ')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Lint
|
7
|
+
# Checks that there are no repeated overload bodies
|
8
|
+
#
|
9
|
+
# @example default
|
10
|
+
# # bad
|
11
|
+
# 1 & 2
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# 1 & _Foo
|
15
|
+
#
|
16
|
+
class LiteralIntersection < RuboCop::RBS::CopBase
|
17
|
+
MSG = "Don't use literals with `&`."
|
18
|
+
|
19
|
+
def on_rbs_def(decl)
|
20
|
+
decl.overloads.each do |overload|
|
21
|
+
overload.method_type.each_type do |type|
|
22
|
+
check_type(type)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_type(type)
|
28
|
+
on_type([::RBS::Types::Intersection], type) do |intersection|
|
29
|
+
check_intersection(intersection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_rbs_constant(type)
|
34
|
+
check_type(type.type)
|
35
|
+
end
|
36
|
+
alias on_rbs_global on_rbs_constant
|
37
|
+
alias on_rbs_type_alias on_rbs_constant
|
38
|
+
alias on_rbs_attribute on_rbs_constant
|
39
|
+
|
40
|
+
def check_intersection(intersection)
|
41
|
+
intersection.types.each do |type|
|
42
|
+
check_intersection_child(type)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_intersection_child(type)
|
47
|
+
case type
|
48
|
+
when ::RBS::Types::Literal
|
49
|
+
range = location_to_range(type.location)
|
50
|
+
add_offense(range)
|
51
|
+
when ::RBS::Types::Intersection
|
52
|
+
check_intersection(type)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/rubocop/cop/rbs/lint/{redundant_overload_type_params.rb → useless_overload_type_params.rb}
RENAMED
@@ -10,16 +10,10 @@ module RuboCop
|
|
10
10
|
# # bad
|
11
11
|
# def foo: [T] () -> void
|
12
12
|
#
|
13
|
-
# # bad
|
14
|
-
# def bar: [T] () -> T
|
15
|
-
#
|
16
|
-
# # bad
|
17
|
-
# def baz: [T] () { () -> T } -> void
|
18
|
-
#
|
19
13
|
# # good
|
20
|
-
# def foo: [T] (
|
21
|
-
class
|
22
|
-
MSG = '
|
14
|
+
# def foo: [T] (T) -> T
|
15
|
+
class UselessOverloadTypeParams < RuboCop::RBS::CopBase
|
16
|
+
MSG = 'Useless overload type variable - `%<variable>s`.'
|
23
17
|
|
24
18
|
def on_rbs_def(decl)
|
25
19
|
decl.overloads.each do |overload|
|
@@ -27,16 +21,7 @@ module RuboCop
|
|
27
21
|
|
28
22
|
type_params = overload.method_type.type_params
|
29
23
|
|
30
|
-
|
31
|
-
overload.method_type.type.each_param do |param|
|
32
|
-
types << param.type
|
33
|
-
end
|
34
|
-
overload.method_type.block&.then do |block|
|
35
|
-
block.type.each_type do |t|
|
36
|
-
types << t
|
37
|
-
end
|
38
|
-
end
|
39
|
-
types.each do |type|
|
24
|
+
overload.method_type.each_type do |type|
|
40
25
|
used_variable_in_type(type) do |var|
|
41
26
|
type_params.delete_if { |type_param| type_param.name == var.name }
|
42
27
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Style
|
7
|
+
# @example default
|
8
|
+
# # bad
|
9
|
+
# def foo: -> void
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def foo: () { -> void } -> void
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# def foo: () -> ^ -> void
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# def foo: () { () -> void } -> ^() -> void
|
19
|
+
class EmptyArgument < RuboCop::RBS::CopBase
|
20
|
+
extend AutoCorrector
|
21
|
+
|
22
|
+
MSG = 'Insert `()` when empty argument'
|
23
|
+
|
24
|
+
def on_rbs_def(decl)
|
25
|
+
decl.overloads.each do |overload|
|
26
|
+
if !overload.method_type.location.source.start_with?('(')
|
27
|
+
range = range_between(overload.method_type.location.start_pos, overload.method_type.location.start_pos)
|
28
|
+
add_offense(range) do |corrector|
|
29
|
+
corrector.insert_before(range, '()')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
if overload.method_type.block
|
33
|
+
tokens = tokenize(overload.method_type.location.source)
|
34
|
+
block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise
|
35
|
+
if tokens[block_arrow_index - 1].type != :pRPAREN
|
36
|
+
range = range_between(
|
37
|
+
overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos,
|
38
|
+
overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos
|
39
|
+
)
|
40
|
+
add_offense(range) do |corrector|
|
41
|
+
corrector.insert_before(range, '()')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
overload.method_type.each_type do |type|
|
47
|
+
check_type(type)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_rbs_constant(const)
|
53
|
+
check_type(const.type)
|
54
|
+
end
|
55
|
+
alias on_rbs_global on_rbs_constant
|
56
|
+
alias on_rbs_type_alias on_rbs_constant
|
57
|
+
alias on_rbs_attribute on_rbs_constant
|
58
|
+
|
59
|
+
def check_type(type)
|
60
|
+
case type
|
61
|
+
when ::RBS::Types::Proc
|
62
|
+
check_proc(type)
|
63
|
+
else
|
64
|
+
type.each_type do |t|
|
65
|
+
check_type(t)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_proc(type)
|
71
|
+
tokens = tokenize(type.location.source)
|
72
|
+
if tokens[1].type != :pLPAREN
|
73
|
+
range = range_between(
|
74
|
+
type.location.start_pos + tokens[0].location.end_pos,
|
75
|
+
type.location.start_pos + tokens[0].location.end_pos
|
76
|
+
)
|
77
|
+
add_offense(range) do |corrector|
|
78
|
+
corrector.insert_after(range, '()')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if type.block
|
83
|
+
block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise
|
84
|
+
if tokens[block_arrow_index - 1].type != :pRPAREN
|
85
|
+
range = range_between(
|
86
|
+
type.location.start_pos + tokens[block_arrow_index].location.start_pos,
|
87
|
+
type.location.start_pos + tokens[block_arrow_index].location.start_pos
|
88
|
+
)
|
89
|
+
add_offense(range) do |corrector|
|
90
|
+
corrector.insert_before(range, '()')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def tokenize(source)
|
97
|
+
::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -6,18 +6,17 @@ module RuboCop
|
|
6
6
|
module Style
|
7
7
|
# @example default
|
8
8
|
# # bad
|
9
|
-
# def initialize: () -> untyped
|
10
|
-
#
|
11
|
-
# # bad
|
12
9
|
# def initialize: () -> nil
|
13
10
|
#
|
14
11
|
# # good
|
12
|
+
# def initialize: () -> untyped
|
13
|
+
#
|
14
|
+
# # good
|
15
15
|
# def initialize: () -> void
|
16
16
|
class InitializeReturnType < RuboCop::RBS::CopBase
|
17
17
|
extend AutoCorrector
|
18
18
|
MSG = '`#initialize` method should return `void`'
|
19
19
|
|
20
|
-
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
21
20
|
def on_rbs_def(decl)
|
22
21
|
return unless decl.name == :initialize
|
23
22
|
return unless decl.kind == :instance
|
@@ -25,6 +24,7 @@ module RuboCop
|
|
25
24
|
|
26
25
|
decl.overloads.each do |overload|
|
27
26
|
return_type = overload.method_type.type.return_type
|
27
|
+
next if return_type.is_a?(::RBS::Types::Bases::Any)
|
28
28
|
next if return_type.is_a?(::RBS::Types::Bases::Void)
|
29
29
|
|
30
30
|
range = location_to_range(return_type.location)
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Style
|
7
|
+
# @example default
|
8
|
+
# # bad
|
9
|
+
# def foo: () -> (bool)
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def foo: (((true | false))) -> void
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def foo: () -> bool
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# def foo: ((true | false)) -> bool
|
19
|
+
class RedundantParentheses < RuboCop::RBS::CopBase
|
20
|
+
module BeforeTokenIfLparen
|
21
|
+
def before_token_if_lparen(tokens, base, fun)
|
22
|
+
first_param = fun.each_param.first
|
23
|
+
return unless first_param
|
24
|
+
|
25
|
+
b, _ = token_before_after(tokens, first_param.location.start_pos - base)
|
26
|
+
return unless b&.type == :pLPAREN
|
27
|
+
|
28
|
+
yield b
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def token_before_after(tokens, pos)
|
34
|
+
token_index = tokens.bsearch_index do |t|
|
35
|
+
t.location.start_pos >= pos
|
36
|
+
end
|
37
|
+
return unless token_index
|
38
|
+
|
39
|
+
[
|
40
|
+
tokens[token_index - 1],
|
41
|
+
tokens[token_index + 1]
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ParenChecker
|
47
|
+
include BeforeTokenIfLparen
|
48
|
+
include RangeHelp
|
49
|
+
attr_reader :processed_source
|
50
|
+
|
51
|
+
def initialize(processed_source:, base:, tokens:, type:, skip:, cop:)
|
52
|
+
@processed_source = processed_source
|
53
|
+
@base = base
|
54
|
+
@tokens = tokens
|
55
|
+
@type = type
|
56
|
+
@skip = skip
|
57
|
+
@cop = cop
|
58
|
+
end
|
59
|
+
|
60
|
+
def check
|
61
|
+
@cop.on_type([::RBS::Types::Proc], @type) do |proc_type|
|
62
|
+
before_token_if_lparen(@tokens, @base, proc_type.type) do |b|
|
63
|
+
@skip << (b.location.start_pos + @base)
|
64
|
+
end
|
65
|
+
if proc_type.block
|
66
|
+
before_token_if_lparen(@tokens, @base, proc_type.block.type) do |b|
|
67
|
+
@skip << (b.location.start_pos + @base)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
excludes = [
|
73
|
+
::RBS::Types::Union,
|
74
|
+
::RBS::Types::Intersection,
|
75
|
+
::RBS::Types::Proc
|
76
|
+
]
|
77
|
+
@cop.on_not_type(excludes, @type) do |type|
|
78
|
+
check_parentheses(type)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def check_parentheses(type)
|
83
|
+
type_token_start_index = @tokens.bsearch_index do |token|
|
84
|
+
(token.location.start_pos + @base) >= type.location.start_pos
|
85
|
+
end or raise
|
86
|
+
before_token = @tokens[type_token_start_index - 1]
|
87
|
+
return if @skip.include?(before_token.location.start_pos + @base)
|
88
|
+
return if before_token&.type != :pLPAREN
|
89
|
+
|
90
|
+
type_token_end_index = @tokens.bsearch_index do |token|
|
91
|
+
(token.location.start_pos + @base) >= type.location.end_pos
|
92
|
+
end or raise
|
93
|
+
after_token = @tokens[type_token_end_index]
|
94
|
+
return if after_token&.type != :pRPAREN
|
95
|
+
|
96
|
+
range = range_between(before_token.location.start_pos + @base, after_token.location.end_pos + @base)
|
97
|
+
@cop.add_offense(range, message: "Don't use parentheses around simple type.") do |corrector|
|
98
|
+
corrector.remove(range_between(before_token.location.start_pos + @base,
|
99
|
+
before_token.location.end_pos + @base))
|
100
|
+
corrector.remove(range_between(after_token.location.start_pos + @base,
|
101
|
+
after_token.location.end_pos + @base))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
include BeforeTokenIfLparen
|
107
|
+
extend AutoCorrector
|
108
|
+
|
109
|
+
def on_rbs_def(decl)
|
110
|
+
base = decl.location.start_pos
|
111
|
+
tokens = tokenize(decl.location.source)
|
112
|
+
skip = Set.new
|
113
|
+
decl.overloads.each do |overload|
|
114
|
+
before_token_if_lparen(tokens, base, overload.method_type.type) do |b|
|
115
|
+
skip << (b.location.start_pos + base)
|
116
|
+
end
|
117
|
+
if overload.method_type.block
|
118
|
+
before_token_if_lparen(tokens, base, overload.method_type.block.type) do |b|
|
119
|
+
skip << (b.location.start_pos + base)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
overload.method_type.each_type do |type|
|
123
|
+
check_type(tokens:, type:, base:, skip:)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def check_type(tokens:, type:, base:, skip: Set.new)
|
129
|
+
ParenChecker.new(
|
130
|
+
processed_source:,
|
131
|
+
base:,
|
132
|
+
tokens:,
|
133
|
+
type:,
|
134
|
+
skip:,
|
135
|
+
cop: self
|
136
|
+
).check
|
137
|
+
end
|
138
|
+
|
139
|
+
def on_rbs_constant(const)
|
140
|
+
tokens = tokenize(const.location.source)
|
141
|
+
type = const.type
|
142
|
+
base = const.location.start_pos
|
143
|
+
check_type(tokens:, type:, base:)
|
144
|
+
end
|
145
|
+
alias on_rbs_global on_rbs_constant
|
146
|
+
alias on_rbs_type_alias on_rbs_constant
|
147
|
+
alias on_rbs_attribute on_rbs_constant
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/rubocop/cop/rbs_cops.rb
CHANGED
@@ -10,20 +10,22 @@ require_relative 'rbs/layout/indentation_width'
|
|
10
10
|
require_relative 'rbs/layout/overload_indentation'
|
11
11
|
require_relative 'rbs/layout/space_around_arrow'
|
12
12
|
require_relative 'rbs/layout/space_around_braces'
|
13
|
+
require_relative 'rbs/layout/space_around_operators'
|
13
14
|
require_relative 'rbs/layout/space_before_colon'
|
14
15
|
require_relative 'rbs/layout/space_before_overload'
|
15
16
|
require_relative 'rbs/layout/trailing_whitespace'
|
16
17
|
|
17
18
|
require_relative 'rbs/lint/duplicate_overload'
|
18
|
-
require_relative 'rbs/lint/
|
19
|
+
require_relative 'rbs/lint/literal_intersection'
|
20
|
+
require_relative 'rbs/lint/useless_overload_type_params'
|
19
21
|
require_relative 'rbs/lint/syntax'
|
20
|
-
require_relative 'rbs/lint/type_params_arity'
|
21
22
|
require_relative 'rbs/lint/will_syntax_error'
|
22
23
|
|
23
24
|
require_relative 'rbs/style/block_return_boolish'
|
24
|
-
require_relative 'rbs/style/true_false'
|
25
25
|
require_relative 'rbs/style/classic_type'
|
26
|
-
require_relative 'rbs/style/optional_nil'
|
27
26
|
require_relative 'rbs/style/duplicated_type'
|
27
|
+
require_relative 'rbs/style/empty_argument'
|
28
28
|
require_relative 'rbs/style/initialize_return_type'
|
29
|
-
require_relative 'rbs/style/
|
29
|
+
require_relative 'rbs/style/optional_nil'
|
30
|
+
require_relative 'rbs/style/redundant_parentheses'
|
31
|
+
require_relative 'rbs/style/true_false'
|
data/lib/rubocop/rbs/cop_base.rb
CHANGED
@@ -86,6 +86,32 @@ module RuboCop
|
|
86
86
|
def location_to_range(location)
|
87
87
|
range_between(location.start_pos, location.end_pos)
|
88
88
|
end
|
89
|
+
|
90
|
+
def tokenize(source)
|
91
|
+
::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
|
92
|
+
end
|
93
|
+
|
94
|
+
def on_type(types, type, &block)
|
95
|
+
case type
|
96
|
+
when *types
|
97
|
+
yield type
|
98
|
+
end
|
99
|
+
type.each_type do |t|
|
100
|
+
on_type(types, t, &block)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def on_not_type(types, type, &block)
|
105
|
+
case type
|
106
|
+
when *types
|
107
|
+
# not
|
108
|
+
else
|
109
|
+
yield type
|
110
|
+
end
|
111
|
+
type.each_type do |t|
|
112
|
+
on_not_type(types, t, &block)
|
113
|
+
end
|
114
|
+
end
|
89
115
|
end
|
90
116
|
end
|
91
117
|
end
|
data/lib/rubocop/rbs/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-on-rbs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ksss
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|
@@ -59,20 +59,22 @@ files:
|
|
59
59
|
- lib/rubocop/cop/rbs/layout/overload_indentation.rb
|
60
60
|
- lib/rubocop/cop/rbs/layout/space_around_arrow.rb
|
61
61
|
- lib/rubocop/cop/rbs/layout/space_around_braces.rb
|
62
|
+
- lib/rubocop/cop/rbs/layout/space_around_operators.rb
|
62
63
|
- lib/rubocop/cop/rbs/layout/space_before_colon.rb
|
63
64
|
- lib/rubocop/cop/rbs/layout/space_before_overload.rb
|
64
65
|
- lib/rubocop/cop/rbs/layout/trailing_whitespace.rb
|
65
66
|
- lib/rubocop/cop/rbs/lint/duplicate_overload.rb
|
66
|
-
- lib/rubocop/cop/rbs/lint/
|
67
|
+
- lib/rubocop/cop/rbs/lint/literal_intersection.rb
|
67
68
|
- lib/rubocop/cop/rbs/lint/syntax.rb
|
68
|
-
- lib/rubocop/cop/rbs/lint/
|
69
|
+
- lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb
|
69
70
|
- lib/rubocop/cop/rbs/lint/will_syntax_error.rb
|
70
71
|
- lib/rubocop/cop/rbs/style/block_return_boolish.rb
|
71
72
|
- lib/rubocop/cop/rbs/style/classic_type.rb
|
72
73
|
- lib/rubocop/cop/rbs/style/duplicated_type.rb
|
74
|
+
- lib/rubocop/cop/rbs/style/empty_argument.rb
|
73
75
|
- lib/rubocop/cop/rbs/style/initialize_return_type.rb
|
74
|
-
- lib/rubocop/cop/rbs/style/merge_untyped.rb
|
75
76
|
- lib/rubocop/cop/rbs/style/optional_nil.rb
|
77
|
+
- lib/rubocop/cop/rbs/style/redundant_parentheses.rb
|
76
78
|
- lib/rubocop/cop/rbs/style/true_false.rb
|
77
79
|
- lib/rubocop/cop/rbs_cops.rb
|
78
80
|
- lib/rubocop/rbs.rb
|
@@ -1,170 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module RBS
|
6
|
-
module Lint
|
7
|
-
# This cop checks the arity of type parameters arity.
|
8
|
-
# You can add expect settings in your .rubocop.yml.
|
9
|
-
#
|
10
|
-
# @example Expects settings
|
11
|
-
# RBS/Lint/TypeParamsArity:
|
12
|
-
# Expects:
|
13
|
-
# Your::Class: 1
|
14
|
-
#
|
15
|
-
# @example default
|
16
|
-
# # bad
|
17
|
-
# type a = Array[Integer, String, Symbol]
|
18
|
-
#
|
19
|
-
# # bad
|
20
|
-
# class Foo
|
21
|
-
# include Enumerable
|
22
|
-
# end
|
23
|
-
class TypeParamsArity < RuboCop::RBS::CopBase
|
24
|
-
Types = ::RBS::Types
|
25
|
-
|
26
|
-
def on_rbs_module(decl)
|
27
|
-
check_type_params(decl)
|
28
|
-
decl.self_types.each do |self_type|
|
29
|
-
check(
|
30
|
-
name: self_type.name,
|
31
|
-
args: self_type.args,
|
32
|
-
location: self_type.location
|
33
|
-
)
|
34
|
-
end
|
35
|
-
check_each_mixin(decl)
|
36
|
-
end
|
37
|
-
|
38
|
-
def on_rbs_class(decl)
|
39
|
-
check_type_params(decl)
|
40
|
-
if decl.super_class
|
41
|
-
check(
|
42
|
-
name: decl.super_class.name,
|
43
|
-
args: decl.super_class.args,
|
44
|
-
location: decl.super_class.location
|
45
|
-
)
|
46
|
-
end
|
47
|
-
check_each_mixin(decl)
|
48
|
-
end
|
49
|
-
|
50
|
-
def on_rbs_interface(decl)
|
51
|
-
check_type_params(decl)
|
52
|
-
check_each_mixin(decl)
|
53
|
-
end
|
54
|
-
|
55
|
-
def on_rbs_constant(const)
|
56
|
-
check_type(const.type)
|
57
|
-
end
|
58
|
-
|
59
|
-
def on_rbs_global(global)
|
60
|
-
check_type(global.type)
|
61
|
-
end
|
62
|
-
|
63
|
-
def on_rbs_type_alias(decl)
|
64
|
-
check_type_params(decl)
|
65
|
-
check_type(decl.type)
|
66
|
-
decl.type.each_type do |type|
|
67
|
-
check_type(type)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def on_rbs_def(member)
|
72
|
-
member.overloads.each do |overload|
|
73
|
-
overload.method_type.each_type do |type|
|
74
|
-
check_type(type)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def on_rbs_attribute(attr)
|
80
|
-
check_type(attr.type)
|
81
|
-
end
|
82
|
-
|
83
|
-
def check_each_mixin(decl)
|
84
|
-
decl.each_mixin do |mixin|
|
85
|
-
check(
|
86
|
-
name: mixin.name,
|
87
|
-
args: mixin.args,
|
88
|
-
location: mixin.location
|
89
|
-
)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def check_type_params(decl)
|
94
|
-
decl.type_params.each do |type_param|
|
95
|
-
if type_param.upper_bound
|
96
|
-
check(
|
97
|
-
name: type_param.upper_bound.name,
|
98
|
-
args: type_param.upper_bound.args,
|
99
|
-
location: type_param.upper_bound.location
|
100
|
-
)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def check_type(type)
|
106
|
-
case type
|
107
|
-
when Types::Record,
|
108
|
-
Types::Tuple,
|
109
|
-
Types::Union,
|
110
|
-
Types::Intersection,
|
111
|
-
Types::Optional,
|
112
|
-
Types::Proc
|
113
|
-
type.each_type.each do |t|
|
114
|
-
check_type(t)
|
115
|
-
end
|
116
|
-
when Types::Interface,
|
117
|
-
Types::Alias,
|
118
|
-
Types::ClassInstance
|
119
|
-
check(
|
120
|
-
name: type.name,
|
121
|
-
args: type.args,
|
122
|
-
location: type.location,
|
123
|
-
)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def check(name:, args:, location:)
|
128
|
-
return unless name.absolute?
|
129
|
-
return unless location
|
130
|
-
|
131
|
-
expect_size = expects[name.to_s]
|
132
|
-
return unless expect_size
|
133
|
-
return unless expect_size != args.size
|
134
|
-
|
135
|
-
message = if args.size == 0
|
136
|
-
"Type `#{name}` is generic but used as a non generic type."
|
137
|
-
else
|
138
|
-
"Type `#{name}` expects #{expect_size} arguments, but #{args.size} arguments are given."
|
139
|
-
end
|
140
|
-
add_offense(
|
141
|
-
location_to_range(location),
|
142
|
-
message: message,
|
143
|
-
severity: :error
|
144
|
-
)
|
145
|
-
end
|
146
|
-
|
147
|
-
def expects
|
148
|
-
@expects ||= begin
|
149
|
-
expects = cop_config['Expects']
|
150
|
-
raise "Expects must be a hash" unless expects.is_a?(Hash)
|
151
|
-
|
152
|
-
unless expects.all? { |k, _| k.is_a?(String) }
|
153
|
-
raise "[RBS/Lint/TypeParamsArity] Keys of Expects must be strings"
|
154
|
-
end
|
155
|
-
unless expects.all? { |_, v| v.is_a?(Integer) }
|
156
|
-
raise "[RBS/Lint/TypeParamsArity] Values of Expects must be integers"
|
157
|
-
end
|
158
|
-
|
159
|
-
expects.transform_keys! do |k|
|
160
|
-
k.start_with?('::') ? k : "::#{k}"
|
161
|
-
end
|
162
|
-
|
163
|
-
expects
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module RBS
|
6
|
-
module Style
|
7
|
-
# @example default
|
8
|
-
# # bad
|
9
|
-
# def foo: (untyped?) -> untyped?
|
10
|
-
#
|
11
|
-
# # bad
|
12
|
-
# def foo: (Integer | untyped) -> (Integer | untyped)
|
13
|
-
#
|
14
|
-
# # bad
|
15
|
-
# def foo: (Integer & untyped) -> (Integer & untyped)
|
16
|
-
#
|
17
|
-
# # good
|
18
|
-
# def foo: (untyped) -> untyped
|
19
|
-
class MergeUntyped < RuboCop::RBS::CopBase
|
20
|
-
extend AutoCorrector
|
21
|
-
|
22
|
-
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
23
|
-
def on_rbs_def(decl)
|
24
|
-
decl.overloads.each do |overload|
|
25
|
-
overload.method_type.type.tap do |fun|
|
26
|
-
fun.each_param do |param|
|
27
|
-
check_type(param.type)
|
28
|
-
end
|
29
|
-
check_type(fun.return_type)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def check_type(type)
|
35
|
-
find_replacement(type) do |method, t, replaced|
|
36
|
-
case method
|
37
|
-
when :replace
|
38
|
-
range = location_to_range(t.location)
|
39
|
-
add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
|
40
|
-
corrector.replace(range, replaced.to_s)
|
41
|
-
end
|
42
|
-
when :remove
|
43
|
-
range = t
|
44
|
-
add_offense(range, message: "Remove `?` in Optional") do |corrector|
|
45
|
-
corrector.remove(range)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def find_replacement(type, &block)
|
52
|
-
case type
|
53
|
-
when ::RBS::Types::Optional
|
54
|
-
case type.type
|
55
|
-
when ::RBS::Types::Bases::Any,
|
56
|
-
::RBS::Types::Bases::Nil,
|
57
|
-
::RBS::Types::Bases::Void,
|
58
|
-
::RBS::Types::Bases::Top,
|
59
|
-
::RBS::Types::Bases::Bottom
|
60
|
-
# untyped? => untyped
|
61
|
-
block.call([:replace, type, type.type])
|
62
|
-
when ::RBS::Types::Optional
|
63
|
-
# (Integer?)? => Integer?
|
64
|
-
range = Parser::Source::Range.new(processed_source.buffer, type.type.location.end_pos - 1,
|
65
|
-
type.type.location.end_pos)
|
66
|
-
block.call([:remove, range])
|
67
|
-
find_replacement(type.type, &block)
|
68
|
-
when ::RBS::Types::Union, ::RBS::Types::Intersection
|
69
|
-
find_replacement(type.type, &block)
|
70
|
-
end
|
71
|
-
when ::RBS::Types::Union, ::RBS::Types::Intersection
|
72
|
-
# (untyped | Integer) => untyped
|
73
|
-
# (untyped & Integer) => untyped
|
74
|
-
if type.types.any? { |t| t.is_a?(::RBS::Types::Bases::Any) }
|
75
|
-
block.call([:replace, type, 'untyped'])
|
76
|
-
end
|
77
|
-
|
78
|
-
uniqed = type.types.uniq
|
79
|
-
if uniqed.size < type.types.size
|
80
|
-
block.call([:replace, type, type.class.new(types: uniqed, location: nil)])
|
81
|
-
end
|
82
|
-
type.types.each do |t|
|
83
|
-
find_replacement(t, &block)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|