rubocop-on-rbs 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|