rubocop-on-rbs 0.2.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 +6 -6
- data/config/default.yml +31 -53
- data/lib/rubocop/cop/rbs/layout/space_around_operators.rb +66 -0
- data/lib/rubocop/cop/rbs/lint/duplicate_overload.rb +35 -0
- data/lib/rubocop/cop/rbs/lint/literal_intersection.rb +59 -0
- data/lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb +1 -4
- 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 +8 -5
- data/lib/rubocop/rbs/cop_base.rb +26 -0
- data/lib/rubocop/rbs/version.rb +1 -1
- metadata +7 -4
- 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.
|
@@ -117,15 +119,13 @@ $ bundle exec rubocop --only RBS/Style
|
|
117
119
|
|
118
120
|
## Installation
|
119
121
|
|
120
|
-
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
121
|
-
|
122
122
|
Install the gem and add to the application's Gemfile by executing:
|
123
123
|
|
124
|
-
$ bundle add
|
124
|
+
$ bundle add rubocop-on-rbs --require false
|
125
125
|
|
126
126
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
127
127
|
|
128
|
-
$ gem install
|
128
|
+
$ gem install rubocop-on-rbs
|
129
129
|
|
130
130
|
## Usage
|
131
131
|
|
data/config/default.yml
CHANGED
@@ -11,6 +11,10 @@ Lint:
|
|
11
11
|
Exclude:
|
12
12
|
- '**/*.rbs'
|
13
13
|
|
14
|
+
Style:
|
15
|
+
Exclude:
|
16
|
+
- '**/*.rbs'
|
17
|
+
|
14
18
|
# RBS
|
15
19
|
|
16
20
|
RBS:
|
@@ -55,6 +59,10 @@ RBS/Layout/SpaceAroundBraces:
|
|
55
59
|
Description: 'Use space around `{}`'
|
56
60
|
Enabled: true
|
57
61
|
|
62
|
+
RBS/Layout/SpaceAroundOperators:
|
63
|
+
Description: 'Use space around `|` or `&`'
|
64
|
+
Enabled: true
|
65
|
+
|
58
66
|
RBS/Layout/SpaceBeforeColon:
|
59
67
|
Description: 'Use space before `:`'
|
60
68
|
Enabled: true
|
@@ -70,64 +78,30 @@ RBS/Layout/TrailingWhitespace:
|
|
70
78
|
## RBS/Lint
|
71
79
|
|
72
80
|
RBS/Lint:
|
73
|
-
Severity: warning
|
74
81
|
Enabled: true
|
75
82
|
|
76
|
-
RBS/Lint/
|
77
|
-
|
83
|
+
RBS/Lint/DuplicateOverload:
|
84
|
+
Severity: warning
|
85
|
+
Description: 'Checks that there are no repeated overload bodies'
|
78
86
|
Enabled: true
|
79
87
|
|
80
|
-
RBS/Lint/
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# Default expects.
|
85
|
-
# You can add expects in .rubocop.yml.
|
86
|
-
|
87
|
-
## class/module
|
88
|
-
Array: 1
|
89
|
-
Enumerable: 1
|
90
|
-
Enumerator: 2
|
91
|
-
Enumerator::Chain: 1
|
92
|
-
Enumerator::Generator: 1
|
93
|
-
Enumerator::Lazy: 2
|
94
|
-
Enumerator::Product: 1
|
95
|
-
FrozenError: 1
|
96
|
-
Hash: 2
|
97
|
-
KeyError: 2
|
98
|
-
NameError: 1
|
99
|
-
NoMatchingPatternKeyError: 2
|
100
|
-
NoMethodError: 1
|
101
|
-
ObjectSpace::WeakKeyMap: 2
|
102
|
-
Range: 1
|
103
|
-
Set: 1
|
104
|
-
Struct: 1
|
105
|
-
|
106
|
-
## interface
|
107
|
-
Array::_Pattern: 1
|
108
|
-
Enumerable::_NotFound: 1
|
109
|
-
Gem::_HashLike: 2
|
110
|
-
Kernel::_RationalDiv: 1
|
111
|
-
Marshal::_Proc: 1
|
112
|
-
String::_MatchAgainst: 2
|
113
|
-
_Each: 1
|
114
|
-
_EachEntry: 1
|
115
|
-
_Range: 1
|
116
|
-
_ToA: 1
|
117
|
-
_ToAry: 1
|
118
|
-
_ToH: 2
|
119
|
-
_ToHash: 2
|
120
|
-
|
121
|
-
## type alias
|
122
|
-
array: 1
|
123
|
-
hash: 2
|
124
|
-
range: 1
|
88
|
+
RBS/Lint/LiteralIntersection:
|
89
|
+
Severity: warning
|
90
|
+
Description: 'Check literal intersection'
|
91
|
+
Enabled: true
|
125
92
|
|
126
93
|
RBS/Lint/UselessOverloadTypeParams:
|
127
|
-
|
94
|
+
Severity: warning
|
95
|
+
Description: 'Check redundant overload type params'
|
96
|
+
Enabled: true
|
97
|
+
|
98
|
+
RBS/Lint/Syntax:
|
99
|
+
Severity: fatal
|
100
|
+
Description: 'Check RBS syntax'
|
128
101
|
Enabled: true
|
129
102
|
|
130
103
|
RBS/Lint/WillSyntaxError:
|
104
|
+
Severity: warning
|
131
105
|
Description: 'Check RBS will syntax error'
|
132
106
|
Enabled: true
|
133
107
|
|
@@ -148,18 +122,22 @@ RBS/Style/DuplicatedType:
|
|
148
122
|
Description: 'Check duplicated type'
|
149
123
|
Enabled: true
|
150
124
|
|
151
|
-
RBS/Style/
|
152
|
-
Description: 'Use `
|
125
|
+
RBS/Style/EmptyArgument:
|
126
|
+
Description: 'Use `()` for empty argument'
|
153
127
|
Enabled: true
|
154
128
|
|
155
|
-
RBS/Style/
|
156
|
-
Description: '
|
129
|
+
RBS/Style/InitializeReturnType:
|
130
|
+
Description: 'Use `void` for initialize method'
|
157
131
|
Enabled: true
|
158
132
|
|
159
133
|
RBS/Style/OptionalNil:
|
160
134
|
Description: 'Use nil instead of nil?'
|
161
135
|
Enabled: true
|
162
136
|
|
137
|
+
RBS/Style/RedundantParentheses:
|
138
|
+
Description: 'Remove redundant parentheses'
|
139
|
+
Enabled: true
|
140
|
+
|
163
141
|
RBS/Style/TrueFalse:
|
164
142
|
Description: 'Use bool instead of true | false'
|
165
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,35 @@
|
|
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
|
+
# def foo: () -> void
|
12
|
+
# | () -> void
|
13
|
+
#
|
14
|
+
class DuplicateOverload < RuboCop::RBS::CopBase
|
15
|
+
MSG = 'Duplicate overload body detected.'
|
16
|
+
|
17
|
+
def on_rbs_def(decl)
|
18
|
+
overloads = decl.overloads
|
19
|
+
overloads.each_with_index do |overload, idx|
|
20
|
+
next if idx == overloads.size - 1
|
21
|
+
|
22
|
+
next_overloads = overloads[(idx + 1)..-1]
|
23
|
+
next_overloads.each do |next_overload|
|
24
|
+
next unless overload.method_type == next_overload.method_type
|
25
|
+
|
26
|
+
range = location_to_range(next_overload.method_type.location)
|
27
|
+
add_offense(range)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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
|
@@ -10,11 +10,8 @@ module RuboCop
|
|
10
10
|
# # bad
|
11
11
|
# def foo: [T] () -> void
|
12
12
|
#
|
13
|
-
# # bad
|
14
|
-
# def bar: [T, U] (T) -> void
|
15
|
-
#
|
16
13
|
# # good
|
17
|
-
# def foo: [T] (
|
14
|
+
# def foo: [T] (T) -> T
|
18
15
|
class UselessOverloadTypeParams < RuboCop::RBS::CopBase
|
19
16
|
MSG = 'Useless overload type variable - `%<variable>s`.'
|
20
17
|
|
@@ -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,19 +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
|
-
require_relative 'rbs/lint/
|
18
|
-
require_relative 'rbs/lint/
|
18
|
+
require_relative 'rbs/lint/duplicate_overload'
|
19
|
+
require_relative 'rbs/lint/literal_intersection'
|
19
20
|
require_relative 'rbs/lint/useless_overload_type_params'
|
21
|
+
require_relative 'rbs/lint/syntax'
|
20
22
|
require_relative 'rbs/lint/will_syntax_error'
|
21
23
|
|
22
24
|
require_relative 'rbs/style/block_return_boolish'
|
23
|
-
require_relative 'rbs/style/true_false'
|
24
25
|
require_relative 'rbs/style/classic_type'
|
25
|
-
require_relative 'rbs/style/optional_nil'
|
26
26
|
require_relative 'rbs/style/duplicated_type'
|
27
|
+
require_relative 'rbs/style/empty_argument'
|
27
28
|
require_relative 'rbs/style/initialize_return_type'
|
28
|
-
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,19 +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
|
66
|
+
- lib/rubocop/cop/rbs/lint/duplicate_overload.rb
|
67
|
+
- lib/rubocop/cop/rbs/lint/literal_intersection.rb
|
65
68
|
- lib/rubocop/cop/rbs/lint/syntax.rb
|
66
|
-
- lib/rubocop/cop/rbs/lint/type_params_arity.rb
|
67
69
|
- lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb
|
68
70
|
- lib/rubocop/cop/rbs/lint/will_syntax_error.rb
|
69
71
|
- lib/rubocop/cop/rbs/style/block_return_boolish.rb
|
70
72
|
- lib/rubocop/cop/rbs/style/classic_type.rb
|
71
73
|
- lib/rubocop/cop/rbs/style/duplicated_type.rb
|
74
|
+
- lib/rubocop/cop/rbs/style/empty_argument.rb
|
72
75
|
- lib/rubocop/cop/rbs/style/initialize_return_type.rb
|
73
|
-
- lib/rubocop/cop/rbs/style/merge_untyped.rb
|
74
76
|
- lib/rubocop/cop/rbs/style/optional_nil.rb
|
77
|
+
- lib/rubocop/cop/rbs/style/redundant_parentheses.rb
|
75
78
|
- lib/rubocop/cop/rbs/style/true_false.rb
|
76
79
|
- lib/rubocop/cop/rbs_cops.rb
|
77
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
|