rubocop-on-rbs 0.3.0 → 0.5.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 +22 -0
- data/README.md +4 -2
- data/config/default.yml +17 -51
- 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} +5 -20
- data/lib/rubocop/cop/rbs/style/empty_argument.rb +170 -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 +29 -2
- data/lib/rubocop/rbs/on_type_helper.rb +29 -0
- data/lib/rubocop/rbs/version.rb +1 -1
- data/lib/rubocop-on-rbs.rb +1 -0
- metadata +22 -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: 889ce959e28673f250187124bfd7955879317482cfdfb976f4bdb975fc918c5b
|
4
|
+
data.tar.gz: 0e0654669928cacd44ca23ad5ece90521ac21660758277fe0af42d3b33377d5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1556cdd4bb1116f2f49aca75d39ed229f3f3074e33d338528cb051c97cbcd952f2cb4daec81e0186e54c0794d2c265609e56483c7addcf77ad5d648b2fc68a39
|
7
|
+
data.tar.gz: c77872b3822c006c59d89a637f59366e63a58beb2a0ac7b8b351c1b4428ba353d7e1c8f2480faa5209258649eb25574008ffcb9ce2f25b815a7540b09da60c35
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.0] - 2024-06-14
|
4
|
+
|
5
|
+
* Split RuboCop task by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/6
|
6
|
+
* Ignore when return untyped by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/7
|
7
|
+
* Split task for steep by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/8
|
8
|
+
* Add Style/EmptyArgument by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/9
|
9
|
+
* Allow return variable only to use by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/10
|
10
|
+
* Remove Style/MergeUntyped by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/11
|
11
|
+
* Remove Lint/TypeParamsArity by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/12
|
12
|
+
* Regenerate docs by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/13
|
13
|
+
* Add RBS/Layout/SpaceAroundOperators by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/14
|
14
|
+
* Add RBS/Style/RedundantParentheses by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/15
|
15
|
+
* Add RBS/Lint/LiteralIntersection by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/16
|
16
|
+
|
17
|
+
## [0.3.0] - 2024-06-11
|
18
|
+
|
19
|
+
* Implement RedundantOverloadTypeParams instead of UselessOverloadTypeParams by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/1
|
20
|
+
* Introduce RBS/Lint/DuplicateOverload by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/2
|
21
|
+
* Fix typo by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/3
|
22
|
+
* Remove unnecessary Exclude settings in .rubocop.yml by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/4
|
23
|
+
* Generate docs for cop by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/5
|
24
|
+
|
3
25
|
## [0.1.0] - 2024-05-15
|
4
26
|
|
5
27
|
- 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,9 +85,9 @@ 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:
|
85
89
|
Severity: warning
|
86
|
-
Description: 'Check
|
90
|
+
Description: 'Check literal intersection'
|
87
91
|
Enabled: true
|
88
92
|
|
89
93
|
RBS/Lint/Syntax:
|
@@ -91,52 +95,10 @@ RBS/Lint/Syntax:
|
|
91
95
|
Description: 'Check RBS syntax'
|
92
96
|
Enabled: true
|
93
97
|
|
94
|
-
RBS/Lint/
|
98
|
+
RBS/Lint/UselessOverloadTypeParams:
|
95
99
|
Severity: warning
|
96
|
-
Description: 'Check type params
|
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
|
100
|
+
Description: 'Check redundant overload type params'
|
101
|
+
Enabled: true
|
140
102
|
|
141
103
|
RBS/Lint/WillSyntaxError:
|
142
104
|
Severity: warning
|
@@ -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,33 +10,18 @@ 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|
|
26
20
|
next if overload.method_type.type_params.empty?
|
27
21
|
|
28
|
-
type_params = overload.method_type.type_params
|
22
|
+
type_params = overload.method_type.type_params.dup
|
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,170 @@
|
|
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
|
+
class MethodTypeChecker
|
21
|
+
include RuboCop::RBS::OnTypeHelper
|
22
|
+
|
23
|
+
def initialize(base_type: nil, &block)
|
24
|
+
@base_type = base_type
|
25
|
+
@base = base_type.location.start_pos
|
26
|
+
@tokens = tokenize(base_type.location.source)
|
27
|
+
@block = block
|
28
|
+
end
|
29
|
+
|
30
|
+
def check
|
31
|
+
check_method_argument
|
32
|
+
if @base_type.block
|
33
|
+
check_block_argument
|
34
|
+
end
|
35
|
+
@base_type.each_type do |type|
|
36
|
+
check_type(type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# [T] () -> void
|
41
|
+
def check_method_argument
|
42
|
+
if @base_type.type_params.empty?
|
43
|
+
will_lparen_token = @tokens[0]
|
44
|
+
else
|
45
|
+
rbracket_index = @tokens.index do |token|
|
46
|
+
token.location.start_pos + @base >= @base_type.type_params.last.location.end_pos
|
47
|
+
end or raise
|
48
|
+
raise unless @tokens[rbracket_index].type == :pRBRACKET
|
49
|
+
|
50
|
+
will_lparen_token = @tokens[rbracket_index + 1]
|
51
|
+
end
|
52
|
+
|
53
|
+
if will_lparen_token.type != :pLPAREN
|
54
|
+
@block.call(
|
55
|
+
@base + will_lparen_token.location.start_pos,
|
56
|
+
@base + will_lparen_token.location.start_pos + 1
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# { () [self: instance] -> void } -> void
|
62
|
+
def check_block_argument
|
63
|
+
return unless @base_type.block
|
64
|
+
return unless @base_type.block.type.each_param.first.nil?
|
65
|
+
|
66
|
+
if @base_type.block.self_type
|
67
|
+
self_type_index = bsearch_token_index(@base_type.block.self_type.location.start_pos)
|
68
|
+
# ) [self:
|
69
|
+
# ^ ^^ ^ => pRPAREN, pLBRACKET, kSELF, pCOLON
|
70
|
+
rparen = @tokens[self_type_index - 4]
|
71
|
+
after_rparen = @tokens[self_type_index - 3]
|
72
|
+
else
|
73
|
+
block_arrow_index = @tokens.find_index { |t| t.type == :pARROW } or raise
|
74
|
+
rparen = @tokens[block_arrow_index - 1]
|
75
|
+
after_rparen = @tokens[block_arrow_index]
|
76
|
+
end
|
77
|
+
|
78
|
+
if rparen.type != :pRPAREN
|
79
|
+
@block.call(
|
80
|
+
@base + after_rparen.location.start_pos,
|
81
|
+
@base + after_rparen.location.start_pos + 1
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_type(type = @base_type)
|
87
|
+
on_type([::RBS::Types::Proc], type) do |proc_type|
|
88
|
+
check_proc(proc_type)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def check_proc(type)
|
93
|
+
proc_start_index = bsearch_token_index(type.location.start_pos)
|
94
|
+
proc_end_index = bsearch_token_index(type.location.end_pos)
|
95
|
+
if @tokens[proc_start_index + 1].type != :pLPAREN
|
96
|
+
@block.call(
|
97
|
+
@base + @tokens[proc_start_index + 1].location.start_pos,
|
98
|
+
@base + @tokens[proc_start_index + 1].location.start_pos + 1
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
if type.block
|
103
|
+
if type.block&.self_type
|
104
|
+
self_type_index = bsearch_token_index(type.block.self_type.location.start_pos)
|
105
|
+
# ) [self:
|
106
|
+
# ^ ^^ ^ => pRPAREN, pLBRACKET, kSELF, pCOLON
|
107
|
+
rparen = @tokens[self_type_index - 4]
|
108
|
+
after_rparen = @tokens[self_type_index - 3]
|
109
|
+
else
|
110
|
+
block_arrow_index = @tokens[proc_start_index...proc_end_index].find_index { |t|
|
111
|
+
t.type == :pARROW
|
112
|
+
} or raise
|
113
|
+
block_arrow_index += proc_start_index
|
114
|
+
rparen = @tokens[block_arrow_index - 1]
|
115
|
+
after_rparen = @tokens[block_arrow_index]
|
116
|
+
end
|
117
|
+
|
118
|
+
if rparen.type != :pRPAREN
|
119
|
+
@block.call(
|
120
|
+
@base + after_rparen.location.start_pos,
|
121
|
+
@base + after_rparen.location.start_pos + 1
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def bsearch_token_index(pos)
|
130
|
+
@tokens.bsearch_index do |token|
|
131
|
+
token.location.start_pos + @base >= pos
|
132
|
+
end or raise
|
133
|
+
end
|
134
|
+
|
135
|
+
def tokenize(source)
|
136
|
+
::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
extend AutoCorrector
|
141
|
+
|
142
|
+
MSG = 'Insert `()` when empty argument'
|
143
|
+
|
144
|
+
def on_rbs_def(decl)
|
145
|
+
decl.overloads.each do |overload|
|
146
|
+
MethodTypeChecker.new(base_type: overload.method_type) do |s, e|
|
147
|
+
range = range_between(s, e)
|
148
|
+
add_offense(range) do |corrector|
|
149
|
+
corrector.insert_before(range, '() ')
|
150
|
+
end
|
151
|
+
end.check
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def on_rbs_constant(const)
|
156
|
+
MethodTypeChecker.new(base_type: const.type) do |s, e|
|
157
|
+
range = range_between(s, e)
|
158
|
+
add_offense(range) do |corrector|
|
159
|
+
corrector.insert_before(range, '() ')
|
160
|
+
end
|
161
|
+
end.check_type
|
162
|
+
end
|
163
|
+
alias on_rbs_global on_rbs_constant
|
164
|
+
alias on_rbs_type_alias on_rbs_constant
|
165
|
+
alias on_rbs_attribute on_rbs_constant
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
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
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'zlib'
|
4
|
+
|
3
5
|
module RuboCop
|
4
6
|
module RBS
|
5
7
|
# Base class for cops that operate on RBS signatures.
|
6
8
|
class CopBase < RuboCop::Cop::Base
|
7
9
|
include RuboCop::Cop::RangeHelp
|
10
|
+
include RuboCop::RBS::OnTypeHelper
|
8
11
|
|
9
12
|
attr_reader :processed_rbs_source
|
10
13
|
|
@@ -19,11 +22,31 @@ module RuboCop
|
|
19
22
|
investigation_rbs()
|
20
23
|
end
|
21
24
|
|
25
|
+
@@cache = {}
|
26
|
+
def parse_rbs
|
27
|
+
buffer = rbs_buffer()
|
28
|
+
@processed_rbs_source = RuboCop::RBS::ProcessedRBSSource.new(buffer)
|
29
|
+
end
|
30
|
+
|
22
31
|
def investigation_rbs
|
23
32
|
return unless processed_source.buffer.name.then { |n| n.end_with?(".rbs") || n == "(string)" }
|
24
33
|
|
25
|
-
buffer
|
26
|
-
|
34
|
+
if processed_source.buffer.name == "(string)"
|
35
|
+
parse_rbs
|
36
|
+
else
|
37
|
+
crc32 = Zlib.crc32(processed_source.raw_source)
|
38
|
+
hit_path = @@cache[processed_source.buffer.name]
|
39
|
+
if hit_path
|
40
|
+
if hit_crc32 = hit_path[crc32]
|
41
|
+
@processed_rbs_source = hit_crc32
|
42
|
+
else
|
43
|
+
hit_path.clear # Other key expect clear by GC
|
44
|
+
hit_path[crc32] = parse_rbs
|
45
|
+
end
|
46
|
+
else
|
47
|
+
(@@cache[processed_source.buffer.name] ||= {})[crc32] = parse_rbs
|
48
|
+
end
|
49
|
+
end
|
27
50
|
|
28
51
|
if processed_rbs_source.error
|
29
52
|
on_rbs_parsing_error()
|
@@ -86,6 +109,10 @@ module RuboCop
|
|
86
109
|
def location_to_range(location)
|
87
110
|
range_between(location.start_pos, location.end_pos)
|
88
111
|
end
|
112
|
+
|
113
|
+
def tokenize(source)
|
114
|
+
::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
|
115
|
+
end
|
89
116
|
end
|
90
117
|
end
|
91
118
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RBS
|
5
|
+
module OnTypeHelper
|
6
|
+
def on_type(types, type, &block)
|
7
|
+
case type
|
8
|
+
when *types
|
9
|
+
yield type
|
10
|
+
end
|
11
|
+
type.each_type do |t|
|
12
|
+
on_type(types, t, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_not_type(types, type, &block)
|
17
|
+
case type
|
18
|
+
when *types
|
19
|
+
# not
|
20
|
+
else
|
21
|
+
yield type
|
22
|
+
end
|
23
|
+
type.each_type do |t|
|
24
|
+
on_not_type(types, t, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rubocop/rbs/version.rb
CHANGED
data/lib/rubocop-on-rbs.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rubocop'
|
|
4
4
|
|
5
5
|
require_relative 'rubocop/rbs'
|
6
6
|
require_relative 'rubocop/rbs/version'
|
7
|
+
require_relative 'rubocop/rbs/on_type_helper'
|
7
8
|
require_relative 'rubocop/rbs/cop_base'
|
8
9
|
require_relative 'rubocop/rbs/inject'
|
9
10
|
require_relative 'rubocop/rbs/processed_rbs_source'
|
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.5.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-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.41'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: zlib
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: RuboCop extension for RBS file.
|
42
56
|
email:
|
43
57
|
- co000ri@gmail.com
|
@@ -59,25 +73,28 @@ files:
|
|
59
73
|
- lib/rubocop/cop/rbs/layout/overload_indentation.rb
|
60
74
|
- lib/rubocop/cop/rbs/layout/space_around_arrow.rb
|
61
75
|
- lib/rubocop/cop/rbs/layout/space_around_braces.rb
|
76
|
+
- lib/rubocop/cop/rbs/layout/space_around_operators.rb
|
62
77
|
- lib/rubocop/cop/rbs/layout/space_before_colon.rb
|
63
78
|
- lib/rubocop/cop/rbs/layout/space_before_overload.rb
|
64
79
|
- lib/rubocop/cop/rbs/layout/trailing_whitespace.rb
|
65
80
|
- lib/rubocop/cop/rbs/lint/duplicate_overload.rb
|
66
|
-
- lib/rubocop/cop/rbs/lint/
|
81
|
+
- lib/rubocop/cop/rbs/lint/literal_intersection.rb
|
67
82
|
- lib/rubocop/cop/rbs/lint/syntax.rb
|
68
|
-
- lib/rubocop/cop/rbs/lint/
|
83
|
+
- lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb
|
69
84
|
- lib/rubocop/cop/rbs/lint/will_syntax_error.rb
|
70
85
|
- lib/rubocop/cop/rbs/style/block_return_boolish.rb
|
71
86
|
- lib/rubocop/cop/rbs/style/classic_type.rb
|
72
87
|
- lib/rubocop/cop/rbs/style/duplicated_type.rb
|
88
|
+
- lib/rubocop/cop/rbs/style/empty_argument.rb
|
73
89
|
- lib/rubocop/cop/rbs/style/initialize_return_type.rb
|
74
|
-
- lib/rubocop/cop/rbs/style/merge_untyped.rb
|
75
90
|
- lib/rubocop/cop/rbs/style/optional_nil.rb
|
91
|
+
- lib/rubocop/cop/rbs/style/redundant_parentheses.rb
|
76
92
|
- lib/rubocop/cop/rbs/style/true_false.rb
|
77
93
|
- lib/rubocop/cop/rbs_cops.rb
|
78
94
|
- lib/rubocop/rbs.rb
|
79
95
|
- lib/rubocop/rbs/cop_base.rb
|
80
96
|
- lib/rubocop/rbs/inject.rb
|
97
|
+
- lib/rubocop/rbs/on_type_helper.rb
|
81
98
|
- lib/rubocop/rbs/processed_rbs_source.rb
|
82
99
|
- lib/rubocop/rbs/version.rb
|
83
100
|
homepage: https://github.com/ksss/rubocop-on-rbs
|
@@ -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
|