rubocop-on-rbs 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|