rubocop-on-rbs 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +186 -0
- data/config/default.yml +165 -0
- data/lib/rubocop/cop/rbs/layout/comment_indentation.rb +69 -0
- data/lib/rubocop/cop/rbs/layout/empty_lines_around_overloads.rb +49 -0
- data/lib/rubocop/cop/rbs/layout/end_alignment.rb +55 -0
- data/lib/rubocop/cop/rbs/layout/extra_spacing.rb +55 -0
- data/lib/rubocop/cop/rbs/layout/indentation_width.rb +64 -0
- data/lib/rubocop/cop/rbs/layout/overload_indentation.rb +69 -0
- data/lib/rubocop/cop/rbs/layout/space_around_arrow.rb +56 -0
- data/lib/rubocop/cop/rbs/layout/space_around_braces.rb +77 -0
- data/lib/rubocop/cop/rbs/layout/space_before_colon.rb +43 -0
- data/lib/rubocop/cop/rbs/layout/space_before_overload.rb +46 -0
- data/lib/rubocop/cop/rbs/layout/trailing_whitespace.rb +42 -0
- data/lib/rubocop/cop/rbs/lint/syntax.rb +18 -0
- data/lib/rubocop/cop/rbs/lint/type_params_arity.rb +170 -0
- data/lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb +57 -0
- data/lib/rubocop/cop/rbs/lint/will_syntax_error.rb +205 -0
- data/lib/rubocop/cop/rbs/style/block_return_boolish.rb +35 -0
- data/lib/rubocop/cop/rbs/style/classic_type.rb +73 -0
- data/lib/rubocop/cop/rbs/style/duplicated_type.rb +61 -0
- data/lib/rubocop/cop/rbs/style/initialize_return_type.rb +40 -0
- data/lib/rubocop/cop/rbs/style/merge_untyped.rb +91 -0
- data/lib/rubocop/cop/rbs/style/optional_nil.rb +50 -0
- data/lib/rubocop/cop/rbs/style/true_false.rb +84 -0
- data/lib/rubocop/cop/rbs_cops.rb +28 -0
- data/lib/rubocop/rbs/cop_base.rb +91 -0
- data/lib/rubocop/rbs/inject.rb +20 -0
- data/lib/rubocop/rbs/processed_rbs_source.rb +29 -0
- data/lib/rubocop/rbs/version.rb +7 -0
- data/lib/rubocop/rbs.rb +15 -0
- data/lib/rubocop-on-rbs.rb +13 -0
- metadata +106 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Lint
|
7
|
+
# Notice useless overload type parameters.
|
8
|
+
#
|
9
|
+
# @example default
|
10
|
+
# # bad
|
11
|
+
# def foo: [T] () -> void
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# def bar: [T, U] (T) -> void
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# def foo: [T] (Array[T]) -> T
|
18
|
+
class UselessOverloadTypeParams < RuboCop::RBS::CopBase
|
19
|
+
MSG = 'Useless overload type variable - `%<variable>s`.'
|
20
|
+
|
21
|
+
def on_rbs_def(decl)
|
22
|
+
decl.overloads.each do |overload|
|
23
|
+
next if overload.method_type.type_params.empty?
|
24
|
+
|
25
|
+
type_params = overload.method_type.type_params
|
26
|
+
|
27
|
+
overload.method_type.each_type do |type|
|
28
|
+
used_variable_in_type(type) do |var|
|
29
|
+
type_params.delete_if { |type_param| type_param.name == var.name }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
next if type_params.empty?
|
33
|
+
|
34
|
+
type_params.each do |type_param|
|
35
|
+
next unless type_param.location
|
36
|
+
|
37
|
+
t = location_to_range(type_param.location[:name])
|
38
|
+
add_offense(t, message: format(MSG, variable: type_param.name), severity: :warning)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def used_variable_in_type(type, &block)
|
44
|
+
case type
|
45
|
+
when ::RBS::Types::Variable
|
46
|
+
yield type
|
47
|
+
else
|
48
|
+
type.each_type do |t|
|
49
|
+
used_variable_in_type(t, &block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RBS
|
6
|
+
module Lint
|
7
|
+
# This cop checks the WillSyntaxError in RBS.
|
8
|
+
# RBS with this diagnostics will fail in `rbs validate` command.
|
9
|
+
#
|
10
|
+
# @example default
|
11
|
+
# # bad
|
12
|
+
# def foo: (void) -> void
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# CONST: self
|
16
|
+
class WillSyntaxError < RuboCop::RBS::CopBase
|
17
|
+
# @rbs!
|
18
|
+
# module Types = ::RBS::Types
|
19
|
+
# module AST = ::RBS::AST
|
20
|
+
|
21
|
+
# @rbs skip
|
22
|
+
AST = ::RBS::AST
|
23
|
+
# @rbs skip
|
24
|
+
Types = ::RBS::Types
|
25
|
+
|
26
|
+
def on_rbs_class(decl)
|
27
|
+
if super_class = decl.super_class
|
28
|
+
super_class.args.each do |arg|
|
29
|
+
void_type_context_validator(arg, true)
|
30
|
+
no_self_type_validator(arg)
|
31
|
+
no_classish_type_validator(arg)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
check_module_or_class(decl)
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_rbs_module(decl)
|
38
|
+
decl.self_types.each do |self_type|
|
39
|
+
self_type.args.each do |arg|
|
40
|
+
void_type_context_validator(arg, true)
|
41
|
+
no_self_type_validator(arg)
|
42
|
+
no_classish_type_validator(arg)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
check_module_or_class(decl)
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_module_or_class(decl)
|
49
|
+
decl.type_params.each do |param|
|
50
|
+
if ub = param.upper_bound
|
51
|
+
void_type_context_validator(ub)
|
52
|
+
no_self_type_validator(ub)
|
53
|
+
no_classish_type_validator(ub)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
decl.each_member do |member|
|
58
|
+
case member
|
59
|
+
when AST::Members::MethodDefinition
|
60
|
+
member.overloads.each do |ov|
|
61
|
+
void_type_context_validator(ov.method_type)
|
62
|
+
end
|
63
|
+
when AST::Members::Attribute
|
64
|
+
void_type_context_validator(member.type)
|
65
|
+
when AST::Members::Mixin
|
66
|
+
member.args.each do |arg|
|
67
|
+
no_self_type_validator(arg)
|
68
|
+
unless arg.is_a?(Types::Bases::Void)
|
69
|
+
void_type_context_validator(arg, true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
when AST::Members::Var
|
73
|
+
void_type_context_validator(member.type)
|
74
|
+
if member.is_a?(AST::Members::ClassVariable)
|
75
|
+
no_self_type_validator(member.type)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_rbs_interface(decl)
|
82
|
+
decl.members.each do |member|
|
83
|
+
case member
|
84
|
+
when AST::Members::MethodDefinition
|
85
|
+
member.overloads.each do |ov|
|
86
|
+
void_type_context_validator(ov.method_type)
|
87
|
+
no_classish_type_validator(ov.method_type)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def on_rbs_constant(decl)
|
94
|
+
no_self_type_validator(decl.type)
|
95
|
+
no_classish_type_validator(decl.type)
|
96
|
+
void_type_context_validator(decl.type)
|
97
|
+
end
|
98
|
+
alias on_rbs_global on_rbs_constant
|
99
|
+
alias on_rbs_type_alias on_rbs_constant
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# @rbs type: ::RBS::Types::t
|
104
|
+
def no_self_type_validator(type)
|
105
|
+
case type
|
106
|
+
when ::RBS::MethodType,
|
107
|
+
Types::Record,
|
108
|
+
Types::Tuple,
|
109
|
+
Types::Union,
|
110
|
+
Types::Intersection,
|
111
|
+
Types::Optional,
|
112
|
+
Types::ClassInstance,
|
113
|
+
Types::Proc
|
114
|
+
type.each_type do |t|
|
115
|
+
no_self_type_validator(t)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
if type.has_self_type?
|
119
|
+
offence(type, "`self` type is not allowed in this context")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# @rbs type: ::RBS::MethodType | ::RBS::Types::t
|
125
|
+
def no_classish_type_validator(type)
|
126
|
+
case type
|
127
|
+
when ::RBS::MethodType,
|
128
|
+
Types::Record,
|
129
|
+
Types::Tuple,
|
130
|
+
Types::Union,
|
131
|
+
Types::Intersection,
|
132
|
+
Types::Optional,
|
133
|
+
Types::ClassInstance,
|
134
|
+
Types::Proc
|
135
|
+
type.each_type do |t|
|
136
|
+
no_classish_type_validator(t)
|
137
|
+
end
|
138
|
+
when Types::Bases::Instance
|
139
|
+
offence(type, "`instance` type is not allowed in this context")
|
140
|
+
when Types::Bases::Class
|
141
|
+
offence(type, "`class` type is not allowed in this context")
|
142
|
+
else
|
143
|
+
if type.has_classish_type?
|
144
|
+
offence(type, "`instance` or `class` type is not allowed in this context")
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# @rbs type: ::RBS::MethodType | ::RBS::Types::Function | ::RBS::Types::t
|
150
|
+
# @rbs allowed_here: bool
|
151
|
+
def void_type_context_validator(type, allowed_here = false)
|
152
|
+
return if type.is_a?(Types::UntypedFunction)
|
153
|
+
|
154
|
+
case type
|
155
|
+
when ::RBS::MethodType
|
156
|
+
void_type_context_validator(type.type)
|
157
|
+
when Types::Function
|
158
|
+
type.each_param do |param|
|
159
|
+
void_type_context_validator(param.type)
|
160
|
+
end
|
161
|
+
case type.return_type
|
162
|
+
when Types::Bases::Void
|
163
|
+
# `() -> void` is allowed
|
164
|
+
else
|
165
|
+
void_type_context_validator(type.return_type, true)
|
166
|
+
end
|
167
|
+
when Types::Proc
|
168
|
+
void_type_context_validator(type.type)
|
169
|
+
if type.block
|
170
|
+
void_type_context_validator(type.block.type)
|
171
|
+
void_type_context_validator(type.block.self_type) if type.block.self_type
|
172
|
+
end
|
173
|
+
when Types::ClassInstance
|
174
|
+
type.args.each do |arg|
|
175
|
+
next if arg.is_a?(Types::Bases::Void)
|
176
|
+
|
177
|
+
void_type_context_validator(arg)
|
178
|
+
end
|
179
|
+
when Types::Record,
|
180
|
+
Types::Tuple,
|
181
|
+
Types::Union,
|
182
|
+
Types::Intersection,
|
183
|
+
Types::Optional
|
184
|
+
type.each_type do |t|
|
185
|
+
void_type_context_validator(t)
|
186
|
+
end
|
187
|
+
else
|
188
|
+
if allowed_here
|
189
|
+
return if type.is_a?(Types::Bases::Void)
|
190
|
+
end
|
191
|
+
if type.with_nonreturn_void?
|
192
|
+
offence(type, "`void` type is only allowed in return type or generics parameter")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def offence(decl, message)
|
198
|
+
range = location_to_range(decl.location)
|
199
|
+
add_offense(range, message: message)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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 } -> void
|
10
|
+
#
|
11
|
+
# # good
|
12
|
+
# def foo: () { () -> boolish } -> void
|
13
|
+
class BlockReturnBoolish < RuboCop::RBS::CopBase
|
14
|
+
extend AutoCorrector
|
15
|
+
MSG = 'Use `boolish` instead of `bool` in block return type.'
|
16
|
+
|
17
|
+
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
18
|
+
def on_rbs_def(decl)
|
19
|
+
decl.overloads.each do |overload|
|
20
|
+
next unless overload.method_type.block
|
21
|
+
|
22
|
+
return_type = overload.method_type.block.type.return_type
|
23
|
+
next unless return_type.is_a?(::RBS::Types::Bases::Bool)
|
24
|
+
|
25
|
+
range = location_to_range(return_type.location)
|
26
|
+
add_offense(range) do |corrector|
|
27
|
+
corrector.replace(range, 'boolish')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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: () -> TrueClass
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def bar: () -> NilClass
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def foo: () -> true
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# def bar: () -> nil
|
19
|
+
class ClassicType < RuboCop::RBS::CopBase
|
20
|
+
extend AutoCorrector
|
21
|
+
|
22
|
+
Types = ::RBS::Types
|
23
|
+
|
24
|
+
def on_rbs_def(decl)
|
25
|
+
decl.overloads.each do |overload|
|
26
|
+
overload.method_type.each_type do |type|
|
27
|
+
check_type(type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @rbs type: ::RBS::Types::t
|
33
|
+
def check_type(type)
|
34
|
+
find_replacement(type) do |t, replaced|
|
35
|
+
range = location_to_range(t.location)
|
36
|
+
add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
|
37
|
+
corrector.replace(range, replaced)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_replacement(type, &block)
|
43
|
+
case type
|
44
|
+
when Types::Record,
|
45
|
+
Types::Tuple,
|
46
|
+
Types::Union,
|
47
|
+
Types::Intersection,
|
48
|
+
Types::Optional,
|
49
|
+
Types::Proc,
|
50
|
+
Types::Alias,
|
51
|
+
Types::Interface
|
52
|
+
type.each_type do |t|
|
53
|
+
find_replacement(t, &block)
|
54
|
+
end
|
55
|
+
when Types::ClassInstance
|
56
|
+
case type.name.to_s
|
57
|
+
when 'TrueClass', '::TrueClass'
|
58
|
+
block.call([type, 'true'])
|
59
|
+
when 'FalseClass', '::FalseClass'
|
60
|
+
block.call([type, 'false'])
|
61
|
+
when 'NilClass', '::NilClass'
|
62
|
+
block.call([type, 'nil'])
|
63
|
+
end
|
64
|
+
type.each_type do |arg|
|
65
|
+
find_replacement(arg, &block)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,61 @@
|
|
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: (Integer | Integer) -> void
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def foo: (Integer & Integer) -> void
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def foo: (Integer) -> void
|
16
|
+
class DuplicatedType < RuboCop::RBS::CopBase
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
20
|
+
def on_rbs_def(decl)
|
21
|
+
decl.overloads.each do |overload|
|
22
|
+
overload.method_type.each_type do |type|
|
23
|
+
check_type(type)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @rbs type: ::RBS::Types::t
|
29
|
+
def check_type(type)
|
30
|
+
case type
|
31
|
+
when ::RBS::Types::Record,
|
32
|
+
::RBS::Types::Tuple,
|
33
|
+
::RBS::Types::Optional,
|
34
|
+
::RBS::Types::ClassInstance,
|
35
|
+
::RBS::Types::Proc
|
36
|
+
type.each_type do |t|
|
37
|
+
check_type(t)
|
38
|
+
end
|
39
|
+
when ::RBS::Types::Union,
|
40
|
+
::RBS::Types::Intersection
|
41
|
+
set = Set.new
|
42
|
+
type.types.each do |t|
|
43
|
+
if set.include?(t)
|
44
|
+
if t.location
|
45
|
+
range = location_to_range(t.location)
|
46
|
+
add_offense(range, message: "Duplicated type `#{t}`.")
|
47
|
+
end
|
48
|
+
else
|
49
|
+
set.add(t)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
type.each_type do |t|
|
53
|
+
check_type(t)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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 initialize: () -> untyped
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def initialize: () -> nil
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def initialize: () -> void
|
16
|
+
class InitializeReturnType < RuboCop::RBS::CopBase
|
17
|
+
extend AutoCorrector
|
18
|
+
MSG = '`#initialize` method should return `void`'
|
19
|
+
|
20
|
+
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
21
|
+
def on_rbs_def(decl)
|
22
|
+
return unless decl.name == :initialize
|
23
|
+
return unless decl.kind == :instance
|
24
|
+
return unless decl.overloading == false
|
25
|
+
|
26
|
+
decl.overloads.each do |overload|
|
27
|
+
return_type = overload.method_type.type.return_type
|
28
|
+
next if return_type.is_a?(::RBS::Types::Bases::Void)
|
29
|
+
|
30
|
+
range = location_to_range(return_type.location)
|
31
|
+
add_offense(range) do |corrector|
|
32
|
+
corrector.replace(range, 'void')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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
|
@@ -0,0 +1,50 @@
|
|
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: (nil?) -> void
|
10
|
+
#
|
11
|
+
# # good
|
12
|
+
# def foo: (nil) -> void
|
13
|
+
class OptionalNil < RuboCop::RBS::CopBase
|
14
|
+
extend AutoCorrector
|
15
|
+
|
16
|
+
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
17
|
+
def on_rbs_def(decl)
|
18
|
+
decl.overloads.each do |overload|
|
19
|
+
overload.method_type.each_type do |type|
|
20
|
+
find_replacement(type) do |t, replaced|
|
21
|
+
range = location_to_range(t.location)
|
22
|
+
add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
|
23
|
+
corrector.replace(range, replaced.to_s)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @rbs type: ::RBS::Types::t
|
31
|
+
def find_replacement(type, &block)
|
32
|
+
case type
|
33
|
+
when ::RBS::Types::Optional
|
34
|
+
case type.type
|
35
|
+
when ::RBS::Types::Bases::Nil
|
36
|
+
block.call([type, ::RBS::Types::Bases::Nil.new(location: nil)])
|
37
|
+
else
|
38
|
+
find_replacement(type.type, &block)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
type.each_type do |type|
|
42
|
+
find_replacement(type, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,84 @@
|
|
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: (true | false) -> (true | false)
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# def foo: (TrueClass | FalseClass) -> (TrueClass | FalseClass)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# def foo: (bool) -> bool
|
16
|
+
class TrueFalse < RuboCop::RBS::CopBase
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
# @sig decl: ::RBS::AST::Members::MethodDefinition
|
20
|
+
def on_rbs_def(decl)
|
21
|
+
decl.overloads.each do |overload|
|
22
|
+
overload.method_type.each_type do |type|
|
23
|
+
find_replacement(type) do |t, replaced|
|
24
|
+
range = location_to_range(t.location)
|
25
|
+
add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
|
26
|
+
corrector.replace(range, replaced.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @rbs type: ::RBS::Types::t
|
34
|
+
def find_replacement(type, &block)
|
35
|
+
case type
|
36
|
+
when ::RBS::Types::Union
|
37
|
+
has_true = has_false = false
|
38
|
+
type.types.each do |t|
|
39
|
+
case t
|
40
|
+
when ::RBS::Types::Literal
|
41
|
+
has_true = true if t.literal == true
|
42
|
+
has_false = true if t.literal == false
|
43
|
+
when ::RBS::Types::ClassInstance
|
44
|
+
case t.name.to_s
|
45
|
+
when 'TrueClass', '::TrueClass'
|
46
|
+
has_true = true
|
47
|
+
when 'FalseClass', '::FalseClass'
|
48
|
+
has_false = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if has_true && has_false
|
53
|
+
replaced = type.types.dup
|
54
|
+
first_index = nil
|
55
|
+
i = -1
|
56
|
+
replaced.delete_if do |t|
|
57
|
+
i += 1
|
58
|
+
case t
|
59
|
+
when ::RBS::Types::Literal
|
60
|
+
(t.literal == true || t.literal == false).tap do |r|
|
61
|
+
first_index ||= i if r
|
62
|
+
end
|
63
|
+
when ::RBS::Types::ClassInstance
|
64
|
+
t.name.to_s.then do |s|
|
65
|
+
s == 'TrueClass' || s == '::TrueClass' || s == 'FalseClass' || s == '::FalseClass'
|
66
|
+
end.tap do |r|
|
67
|
+
first_index ||= i if r
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
replaced.insert(first_index || 0, ::RBS::Types::Bases::Bool.new(location: nil))
|
72
|
+
block.call([type, ::RBS::Types::Union.new(types: replaced, location: nil)])
|
73
|
+
end
|
74
|
+
else
|
75
|
+
type.each_type do |type|
|
76
|
+
find_replacement(type, &block)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|