rubocop-on-rbs 2.1.0 → 2.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/README.md +46 -0
  4. data/config/default.yml +109 -0
  5. data/lib/rubocop/cop/rbs/lint/ambiguous_keyword_argument_key.rb +2 -43
  6. data/lib/rubocop/cop/rbs/lint/duplicate_overload.rb +2 -25
  7. data/lib/rubocop/cop/rbs/lint/literal_intersection.rb +7 -38
  8. data/lib/rubocop/cop/rbs/lint/new_returns_void.rb +2 -17
  9. data/lib/rubocop/cop/rbs/lint/rest_keyword_hash.rb +2 -22
  10. data/lib/rubocop/cop/rbs/lint/unused_overload_type_params.rb +2 -41
  11. data/lib/rubocop/cop/rbs/mixin/ambiguous_keyword_argument_key.rb +59 -0
  12. data/lib/rubocop/cop/rbs/mixin/block_return_boolish.rb +32 -0
  13. data/lib/rubocop/cop/rbs/mixin/class_with_singleton.rb +44 -0
  14. data/lib/rubocop/cop/rbs/mixin/classic_type.rb +72 -0
  15. data/lib/rubocop/cop/rbs/mixin/duplicate_overload.rb +43 -0
  16. data/lib/rubocop/cop/rbs/mixin/duplicated_type.rb +59 -0
  17. data/lib/rubocop/cop/rbs/mixin/empty_argument.rb +167 -0
  18. data/lib/rubocop/cop/rbs/mixin/initialize_return_type.rb +35 -0
  19. data/lib/rubocop/cop/rbs/mixin/instance_with_instance.rb +54 -0
  20. data/lib/rubocop/cop/rbs/mixin/literal_intersection.rb +56 -0
  21. data/lib/rubocop/cop/rbs/mixin/new_returns_void.rb +33 -0
  22. data/lib/rubocop/cop/rbs/mixin/optional_nil.rb +58 -0
  23. data/lib/rubocop/cop/rbs/mixin/redundant_parentheses.rb +161 -0
  24. data/lib/rubocop/cop/rbs/mixin/rest_keyword_hash.rb +40 -0
  25. data/lib/rubocop/cop/rbs/mixin/true_false.rb +89 -0
  26. data/lib/rubocop/cop/rbs/mixin/unused_overload_type_params.rb +58 -0
  27. data/lib/rubocop/cop/rbs/style/block_return_boolish.rb +2 -16
  28. data/lib/rubocop/cop/rbs/style/class_with_singleton.rb +2 -29
  29. data/lib/rubocop/cop/rbs/style/classic_type.rb +7 -56
  30. data/lib/rubocop/cop/rbs/style/duplicated_type.rb +7 -44
  31. data/lib/rubocop/cop/rbs/style/empty_argument.rb +7 -145
  32. data/lib/rubocop/cop/rbs/style/initialize_return_type.rb +2 -18
  33. data/lib/rubocop/cop/rbs/style/instance_with_instance.rb +2 -38
  34. data/lib/rubocop/cop/rbs/style/optional_nil.rb +7 -40
  35. data/lib/rubocop/cop/rbs/style/redundant_parentheses.rb +3 -141
  36. data/lib/rubocop/cop/rbs/style/true_false.rb +7 -71
  37. data/lib/rubocop/cop/rbs_cops.rb +17 -0
  38. data/lib/rubocop/cop/rbs_inline/lint/ambiguous_keyword_argument_key.rb +28 -0
  39. data/lib/rubocop/cop/rbs_inline/lint/duplicate_overload.rb +31 -0
  40. data/lib/rubocop/cop/rbs_inline/lint/literal_intersection.rb +31 -0
  41. data/lib/rubocop/cop/rbs_inline/lint/new_returns_void.rb +28 -0
  42. data/lib/rubocop/cop/rbs_inline/lint/rest_keyword_hash.rb +31 -0
  43. data/lib/rubocop/cop/rbs_inline/lint/syntax.rb +40 -0
  44. data/lib/rubocop/cop/rbs_inline/lint/unused_annotation.rb +41 -0
  45. data/lib/rubocop/cop/rbs_inline/lint/unused_overload_type_params.rb +28 -0
  46. data/lib/rubocop/cop/rbs_inline/style/block_return_boolish.rb +27 -0
  47. data/lib/rubocop/cop/rbs_inline/style/class_with_singleton.rb +29 -0
  48. data/lib/rubocop/cop/rbs_inline/style/classic_type.rb +38 -0
  49. data/lib/rubocop/cop/rbs_inline/style/duplicated_type.rb +37 -0
  50. data/lib/rubocop/cop/rbs_inline/style/empty_argument.rb +42 -0
  51. data/lib/rubocop/cop/rbs_inline/style/initialize_return_type.rb +37 -0
  52. data/lib/rubocop/cop/rbs_inline/style/instance_with_instance.rb +29 -0
  53. data/lib/rubocop/cop/rbs_inline/style/optional_nil.rb +32 -0
  54. data/lib/rubocop/cop/rbs_inline/style/redundant_parentheses.rb +96 -0
  55. data/lib/rubocop/cop/rbs_inline/style/true_false.rb +37 -0
  56. data/lib/rubocop/cop/rbs_inline_cops.rb +21 -0
  57. data/lib/rubocop/rbs/cop_base.rb +5 -34
  58. data/lib/rubocop/rbs/cop_helper.rb +22 -0
  59. data/lib/rubocop/rbs/version.rb +1 -1
  60. data/lib/rubocop/rbs_inline/cop_base.rb +110 -0
  61. data/lib/rubocop/rbs_inline/processed_inline_source.rb +33 -0
  62. data/lib/rubocop-on-rbs.rb +4 -0
  63. metadata +39 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43791277046bd585b3979b68148eb004aa7212cbcdd5301f7d5001915cf20b8a
4
- data.tar.gz: b261814ee8ff54554e351e018c688821df1fff4b1bc78c9b6440df53e8db2029
3
+ metadata.gz: '08ba6bad1ed2be5adfb8b5afeaf6917521e98618a7279354231e637727774177'
4
+ data.tar.gz: 9e1ac97d25171ec66ad0815bab269e652ce10b159cb372aad2bd9b0baeeb4913
5
5
  SHA512:
6
- metadata.gz: 0a2e89869da1c6353ba2cf7baec53629244a69538f94e0ae6523cae22165fd4775f78d5bbfd7a0925ce2b992567b256e73a956306d8c0022b599db89f67e092b
7
- data.tar.gz: 53fea77b783bd0a3f53a2c59129e2cae7161c78c923cda78ce0ea7875e1a8ed53a2923df8aa438bb1143f3d0bfbfda410f6ab3c3ef0be1ca378664f7679b511c
6
+ metadata.gz: f8a8c23cfaffc12e440c3b0b8ab6e122e6d68352c481b0b548183329c36967b275627131b25b6a7123da202c84c93e2b2442735f3080fac20b148da12f7c4561
7
+ data.tar.gz: 800caf959a981ead103d76f611a69ec61ce4828d7e620c48bab82a621b21eea1ca8bccf90bb4c6a7fe6080c155bc29cf2bd6c0886e3707a67e8ae3da3d718581
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.2.0] - 2026-09-28
4
+
5
+ * Mark all `RBSInline/*` cops as `Enabled: pending` by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/164
6
+ * They will be enabled by default in v3.0.0. Use `NewCops: enable` to enable them now.
7
+ * Add `RBSInline` department for RBS inline annotations in Ruby files by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/159
8
+ * `RBSInline/Lint/Syntax`
9
+ * `RBSInline/Lint/UnusedAnnotation`
10
+ * Replace crc32 cache with `ObjectSpace::WeakKeyMap` and drop `zlib` dependency by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/160
11
+ * Add `RBSInline/Style` department by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/161
12
+ * `RBSInline/Style/BlockReturnBoolish`
13
+ * `RBSInline/Style/ClassWithSingleton`
14
+ * `RBSInline/Style/ClassicType`
15
+ * `RBSInline/Style/DuplicatedType`
16
+ * `RBSInline/Style/EmptyArgument`
17
+ * `RBSInline/Style/InitializeReturnType`
18
+ * `RBSInline/Style/InstanceWithInstance`
19
+ * `RBSInline/Style/OptionalNil`
20
+ * `RBSInline/Style/RedundantParentheses`
21
+ * `RBSInline/Style/TrueFalse`
22
+ * Drop steep by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/162
23
+ * Add `RBSInline/Lint` cops sharing implementation with `RBS/Lint` by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/163
24
+ * `RBSInline/Lint/AmbiguousKeywordArgumentKey`
25
+ * `RBSInline/Lint/DuplicateOverload`
26
+ * `RBSInline/Lint/LiteralIntersection`
27
+ * `RBSInline/Lint/NewReturnsVoid`
28
+ * `RBSInline/Lint/RestKeywordHash`
29
+ * `RBSInline/Lint/UnusedOverloadTypeParams`
30
+
3
31
  ## [2.1.0] - 2026-09-27
4
32
 
5
33
  * Drop support for Ruby v3.2 by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/153
data/README.md CHANGED
@@ -104,6 +104,52 @@ RBS/Style:
104
104
  $ bundle exec rubocop --only RBS/Style
105
105
  ```
106
106
 
107
+ ### RBSInline
108
+
109
+ Cops for RBS inline annotations (`#: String`, `# @rbs x: Integer`) written in Ruby files.
110
+ They are separated from `RBS/*` cops and run only on Ruby files that contain annotations.
111
+
112
+ All `RBSInline/*` cops are `pending` in v2.x and will be enabled by default in v3.0.0.
113
+ To enable them now, set `NewCops: enable` in your `.rubocop.yml`:
114
+
115
+ ```yaml
116
+ AllCops:
117
+ NewCops: enable
118
+ ```
119
+
120
+ Or enable only the `RBSInline` department (requires RuboCop 1.89+):
121
+
122
+ ```yaml
123
+ RBSInline:
124
+ NewCops: enable
125
+ ```
126
+
127
+ ### RBSInline/Lint
128
+
129
+ Same as `RBS/Lint`, but for inline annotations.
130
+
131
+ ```yaml
132
+ RBSInline/Lint:
133
+ Enabled: true
134
+ ```
135
+
136
+ ```console
137
+ $ bundle exec rubocop --only RBSInline/Lint
138
+ ```
139
+
140
+ ### RBSInline/Style
141
+
142
+ Same as `RBS/Style`, but for inline annotations.
143
+
144
+ ```yaml
145
+ RBSInline/Style:
146
+ Enabled: true
147
+ ```
148
+
149
+ ```console
150
+ $ bundle exec rubocop --only RBSInline/Style
151
+ ```
152
+
107
153
  ## Installation
108
154
 
109
155
  Install the gem and add to the application's Gemfile by executing:
data/config/default.yml CHANGED
@@ -222,3 +222,112 @@ RBS/Style/RedundantParentheses:
222
222
  RBS/Style/TrueFalse:
223
223
  Description: 'Use bool instead of true | false'
224
224
  Enabled: true
225
+
226
+ # RBSInline
227
+
228
+ RBSInline:
229
+ Enabled: true
230
+
231
+ ## RBSInline/Lint
232
+
233
+ RBSInline/Lint:
234
+ Enabled: true
235
+
236
+ RBSInline/Lint/AmbiguousKeywordArgumentKey:
237
+ Description: 'Check ambiguous keyword argument key'
238
+ Enabled: pending
239
+ VersionAdded: '2.2.0'
240
+
241
+ RBSInline/Lint/DuplicateOverload:
242
+ Description: 'Checks that there are no repeated overload bodies'
243
+ Enabled: pending
244
+ VersionAdded: '2.2.0'
245
+
246
+ RBSInline/Lint/LiteralIntersection:
247
+ Description: 'Check literal intersection'
248
+ Enabled: pending
249
+ VersionAdded: '2.2.0'
250
+
251
+ RBSInline/Lint/NewReturnsVoid:
252
+ Description: 'sigleton `new` method should not returns `void` type'
253
+ Enabled: pending
254
+ VersionAdded: '2.2.0'
255
+
256
+ RBSInline/Lint/RestKeywordHash:
257
+ Description: 'Check rest keyword with `Hash` type'
258
+ Enabled: pending
259
+ VersionAdded: '2.2.0'
260
+
261
+ RBSInline/Lint/Syntax:
262
+ Severity: error
263
+ Description: 'Check RBS inline annotation syntax'
264
+ Enabled: pending
265
+ VersionAdded: '2.2.0'
266
+ AllowedPatterns:
267
+ # Embedded RBS by rbs-inline gem. Not supported by RBS::InlineParser.
268
+ - '\A# @rbs!'
269
+
270
+ RBSInline/Lint/UnusedAnnotation:
271
+ Description: 'Check unused RBS inline annotation'
272
+ Enabled: pending
273
+ VersionAdded: '2.2.0'
274
+
275
+ RBSInline/Lint/UnusedOverloadTypeParams:
276
+ Description: 'Check redundant overload type params'
277
+ Enabled: pending
278
+ VersionAdded: '2.2.0'
279
+
280
+ ## RBSInline/Style
281
+
282
+ RBSInline/Style:
283
+ Enabled: true
284
+
285
+ RBSInline/Style/BlockReturnBoolish:
286
+ Description: 'Use `bool` for block return type'
287
+ Enabled: pending
288
+ VersionAdded: '2.2.0'
289
+
290
+ RBSInline/Style/ClassWithSingleton:
291
+ Description: 'Check `class` with singleton context'
292
+ Enabled: pending
293
+ VersionAdded: '2.2.0'
294
+
295
+ RBSInline/Style/ClassicType:
296
+ Description: 'Use simple type'
297
+ Enabled: pending
298
+ VersionAdded: '2.2.0'
299
+
300
+ RBSInline/Style/DuplicatedType:
301
+ Description: 'Check duplicated type'
302
+ Enabled: pending
303
+ VersionAdded: '2.2.0'
304
+
305
+ RBSInline/Style/EmptyArgument:
306
+ Description: 'Use `()` for empty argument'
307
+ Enabled: pending
308
+ VersionAdded: '2.2.0'
309
+
310
+ RBSInline/Style/InitializeReturnType:
311
+ Description: 'Use `void` for initialize method'
312
+ Enabled: pending
313
+ VersionAdded: '2.2.0'
314
+
315
+ RBSInline/Style/InstanceWithInstance:
316
+ Description: 'Check `instance` with instance context'
317
+ Enabled: pending
318
+ VersionAdded: '2.2.0'
319
+
320
+ RBSInline/Style/OptionalNil:
321
+ Description: 'Use nil instead of nil?'
322
+ Enabled: pending
323
+ VersionAdded: '2.2.0'
324
+
325
+ RBSInline/Style/RedundantParentheses:
326
+ Description: 'Remove redundant parentheses'
327
+ Enabled: pending
328
+ VersionAdded: '2.2.0'
329
+
330
+ RBSInline/Style/TrueFalse:
331
+ Description: 'Use bool instead of true | false'
332
+ Enabled: pending
333
+ VersionAdded: '2.2.0'
@@ -11,51 +11,10 @@ module RuboCop
11
11
  # def foo: (option?: bool, option!: bool, Option: bool) -> void
12
12
  #
13
13
  class AmbiguousKeywordArgumentKey < RuboCop::RBS::CopBase
14
+ include RuboCop::Cop::RBS::Mixin::AmbiguousKeywordArgumentKey
14
15
  extend AutoCorrector
15
16
 
16
- # @rbs decl: ::RBS::AST::Members::MethodDefinition
17
- def on_rbs_def(decl)
18
- decl.overloads.each do |overload|
19
- func = overload.method_type.type
20
- next unless func.kind_of?(::RBS::Types::Function)
21
- next unless !func.required_keywords.empty? || !func.optional_keywords.empty?
22
-
23
- location = overload.method_type.location or next
24
- base_pos = location.start_pos
25
- lex_result = ::RBS::Parser.lex(location.source)
26
- buf = []
27
- lex_result.value.each do |token|
28
- case token.type
29
- when :pLPAREN, :pRPAREN, :tTRIVIA
30
- # skip
31
- when :pCOLON
32
- next if buf.empty?
33
-
34
- case buf.last.type
35
- when :pQUESTION
36
- buf.shift if buf.first.type == :pQUESTION
37
- actual = buf.map { |t| t.location.source }.join
38
- did_you_mean = buf.reject { |t| t.location.source == '?' }.map { |t| t.location.source }.join
39
- message = +"`#{actual}` is not local variable name."
40
- if did_you_mean.length > 0
41
- message << " Did you mean `?#{did_you_mean}` for optional keyword argument?"
42
- end
43
- range = range_between(buf.first.location.start_pos + base_pos, buf.last.location.end_pos + base_pos)
44
- add_offense(range, message: message)
45
- when :tBANGIDENT, :tUIDENT
46
- buf.shift if buf.first.type == :pQUESTION
47
- actual = buf.map { |t| t.location.source }.join
48
- range = range_between(buf.first.location.start_pos + base_pos, buf.last.location.end_pos + base_pos)
49
- add_offense(range, message: "`#{actual}` is not local variable name.")
50
- end
51
- when :pCOMMA
52
- buf.clear
53
- else
54
- buf << token
55
- end
56
- end
57
- end
58
- end
17
+ alias on_rbs_def check_def
59
18
  end
60
19
  end
61
20
  end
@@ -13,32 +13,9 @@ module RuboCop
13
13
  # | () -> top
14
14
  #
15
15
  class DuplicateOverload < RuboCop::RBS::CopBase
16
- MSG = 'Duplicate overload arguments detected.'
16
+ include RuboCop::Cop::RBS::Mixin::DuplicateOverload
17
17
 
18
- def on_rbs_def(decl)
19
- overloads = decl.overloads
20
- overloads.each_with_index do |overload, idx|
21
- next if idx == overloads.size - 1
22
-
23
- next_overloads = overloads[(idx + 1)..-1] or next
24
- next_overloads.each do |next_overload|
25
- a = method_type_with_untyped_return_type(overload.method_type)
26
- b = method_type_with_untyped_return_type(next_overload.method_type)
27
- next unless a == b
28
-
29
- location = next_overload.method_type.location or next
30
- range = location_to_range(location)
31
- add_offense(range)
32
- end
33
- end
34
- end
35
-
36
- private
37
-
38
- def method_type_with_untyped_return_type(method_type)
39
- type = method_type.type.with_return_type(::RBS::Types::Bases::Any.new(location: nil))
40
- method_type.update(type:)
41
- end
18
+ alias on_rbs_def check_def
42
19
  end
43
20
  end
44
21
  end
@@ -14,45 +14,14 @@ module RuboCop
14
14
  # 1 & _Foo
15
15
  #
16
16
  class LiteralIntersection < RuboCop::RBS::CopBase
17
- MSG = "Don't use literals with `&`."
17
+ include RuboCop::Cop::RBS::Mixin::LiteralIntersection
18
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
- alias on_rbs_var on_rbs_constant
40
-
41
- def check_intersection(intersection)
42
- intersection.types.each do |type|
43
- check_intersection_child(type)
44
- end
45
- end
46
-
47
- def check_intersection_child(type)
48
- case type
49
- when ::RBS::Types::Literal
50
- range = location_to_range(type.location)
51
- add_offense(range)
52
- when ::RBS::Types::Intersection
53
- check_intersection(type)
54
- end
55
- end
19
+ alias on_rbs_def check_def
20
+ alias on_rbs_constant check_member
21
+ alias on_rbs_global check_member
22
+ alias on_rbs_type_alias check_member
23
+ alias on_rbs_attribute check_member
24
+ alias on_rbs_var check_member
56
25
  end
57
26
  end
58
27
  end
@@ -16,24 +16,9 @@ module RuboCop
16
16
  # def self.new: () -> instance
17
17
  #
18
18
  class NewReturnsVoid < RuboCop::RBS::CopBase
19
- MSG = "Don't use `void` in self.new method. Did you mean `instance`?"
19
+ include RuboCop::Cop::RBS::Mixin::NewReturnsVoid
20
20
 
21
- # @rbs decl: RBS::AST::Members::MethodDefinition
22
- def on_rbs_def(decl)
23
- return unless decl.kind == :singleton
24
- return unless decl.name == :new
25
-
26
- decl.overloads.each do |overload|
27
- return_type = overload.method_type.type.return_type
28
- case return_type
29
- when ::RBS::Types::Bases::Void
30
- next unless return_type.location
31
-
32
- range = location_to_range(return_type.location)
33
- add_offense(range)
34
- end
35
- end
36
- end
21
+ alias on_rbs_def check_def
37
22
  end
38
23
  end
39
24
  end
@@ -17,29 +17,9 @@ module RuboCop
17
17
  # # e.g.) foo(a: "x", b: "y", c: "z")
18
18
  #
19
19
  class RestKeywordHash < RuboCop::RBS::CopBase
20
- def on_rbs_def(decl)
21
- decl.overloads.each do |overload|
22
- func = overload.method_type.type
23
- next unless func.is_a?(::RBS::Types::Function)
20
+ include RuboCop::Cop::RBS::Mixin::RestKeywordHash
24
21
 
25
- if !func.rest_keywords.nil?
26
- check_type(func.rest_keywords.type)
27
- end
28
- end
29
- end
30
-
31
- def check_type(type)
32
- case type
33
- when ::RBS::Types::ClassInstance
34
- if type.name.relative!.to_s == 'Hash'
35
- did_you_mean = type.args[1] or return
36
- range = location_to_range(type.location)
37
- message = "The type of `**` specifies only the type of value. " \
38
- "Did you mean `**#{did_you_mean}`?"
39
- add_offense(range, message:)
40
- end
41
- end
42
- end
22
+ alias on_rbs_def check_def
43
23
  end
44
24
  end
45
25
  end
@@ -14,48 +14,9 @@ module RuboCop
14
14
  # def foo: [T] (T) -> T
15
15
  #
16
16
  class UnusedOverloadTypeParams < RuboCop::RBS::CopBase
17
- MSG = 'Unused overload type variable - `%<variable>s`.'
17
+ include RuboCop::Cop::RBS::Mixin::UnusedOverloadTypeParams
18
18
 
19
- def on_rbs_def(decl)
20
- decl.overloads.each do |overload|
21
- next if overload.method_type.type_params.empty?
22
-
23
- type_params = overload.method_type.type_params.dup
24
- map = type_params.to_h { |param| [param.name, param] }
25
- type_params.each do |type_param|
26
- if type_param.upper_bound
27
- used_variable_in_type(type_param.upper_bound) do |var|
28
- map.delete(var.name)
29
- end
30
- end
31
- end
32
-
33
- overload.method_type.each_type do |type|
34
- used_variable_in_type(type) do |var|
35
- map.delete(var.name)
36
- end
37
- end
38
- next if map.empty?
39
-
40
- map.each do |name, type_param|
41
- next unless type_param.location
42
-
43
- t = location_to_range(type_param.location[:name])
44
- add_offense(t, message: format(MSG, variable: name))
45
- end
46
- end
47
- end
48
-
49
- def used_variable_in_type(type, &block)
50
- case type
51
- when ::RBS::Types::Variable
52
- yield type
53
- else
54
- type.each_type do |t|
55
- used_variable_in_type(t, &block)
56
- end
57
- end
58
- end
19
+ alias on_rbs_def check_def
59
20
  end
60
21
  end
61
22
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Mixin
7
+ # Shared implementation of `RBS/Lint/AmbiguousKeywordArgumentKey`
8
+ # and `RBSInline/Lint/AmbiguousKeywordArgumentKey`.
9
+ # @rbs module-self: RuboCop::Cop::Base
10
+ # @rbs module-self: RuboCop::RBS::CopHelper
11
+ module AmbiguousKeywordArgumentKey
12
+ #: (::RBS::AST::Members::MethodDefinition | ::RBS::AST::Ruby::Members::DefMember decl) -> void
13
+ def check_def(decl)
14
+ decl.overloads.each do |overload|
15
+ func = overload.method_type.type
16
+ next unless func.kind_of?(::RBS::Types::Function)
17
+ next unless !func.required_keywords.empty? || !func.optional_keywords.empty?
18
+
19
+ location = overload.method_type.location or next
20
+ base_pos = location.start_pos
21
+ lex_result = ::RBS::Parser.lex(location.source)
22
+ buf = []
23
+ lex_result.value.each do |token|
24
+ case token.type
25
+ when :pLPAREN, :pRPAREN, :tTRIVIA
26
+ # skip
27
+ when :pCOLON
28
+ next if buf.empty?
29
+
30
+ case buf.last.type
31
+ when :pQUESTION
32
+ buf.shift if buf.first.type == :pQUESTION
33
+ actual = buf.map { |t| t.location.source }.join
34
+ did_you_mean = buf.reject { |t| t.location.source == '?' }.map { |t| t.location.source }.join
35
+ message = +"`#{actual}` is not local variable name."
36
+ if did_you_mean.length > 0
37
+ message << " Did you mean `?#{did_you_mean}` for optional keyword argument?"
38
+ end
39
+ range = range_between(buf.first.location.start_pos + base_pos, buf.last.location.end_pos + base_pos)
40
+ add_offense(range, message: message)
41
+ when :tBANGIDENT, :tUIDENT
42
+ buf.shift if buf.first.type == :pQUESTION
43
+ actual = buf.map { |t| t.location.source }.join
44
+ range = range_between(buf.first.location.start_pos + base_pos, buf.last.location.end_pos + base_pos)
45
+ add_offense(range, message: "`#{actual}` is not local variable name.")
46
+ end
47
+ when :pCOMMA
48
+ buf.clear
49
+ else
50
+ buf << token
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Mixin
7
+ # Shared implementation of `RBS/Style/BlockReturnBoolish` and `RBSInline/Style/BlockReturnBoolish`.
8
+ # @rbs module-self: RuboCop::Cop::Base
9
+ # @rbs module-self: RuboCop::RBS::CopHelper
10
+ module BlockReturnBoolish
11
+ MSG = 'Use `boolish` instead of `bool` in block return type.'
12
+
13
+ #: (::RBS::AST::Members::MethodDefinition | ::RBS::AST::Ruby::Members::DefMember decl) -> void
14
+ def check_def(decl)
15
+ decl.overloads.each do |overload|
16
+ next unless overload.method_type.block
17
+
18
+ return_type = overload.method_type.block.type.return_type
19
+ next unless return_type.is_a?(::RBS::Types::Bases::Bool)
20
+ next unless return_type.location
21
+
22
+ range = location_to_range(return_type.location)
23
+ add_offense(range) do |corrector|
24
+ corrector.replace(range, 'boolish')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Mixin
7
+ # Shared implementation of `RBS/Style/ClassWithSingleton` and `RBSInline/Style/ClassWithSingleton`.
8
+ # @rbs module-self: RuboCop::Cop::Base
9
+ # @rbs module-self: RuboCop::RBS::CopHelper
10
+ module ClassWithSingleton
11
+ MSG = 'Use `self` instead of `class`.'
12
+
13
+ #: (::RBS::AST::Members::MethodDefinition | ::RBS::AST::Ruby::Members::DefMember decl) -> void
14
+ def check_def(decl)
15
+ return unless decl.kind == :singleton
16
+
17
+ decl.overloads.each do |overload|
18
+ overload.method_type.each_type do |type|
19
+ check_type(type)
20
+ end
21
+ end
22
+ end
23
+
24
+ #: (::RBS::Types::t type) -> void
25
+ def check_type(type)
26
+ case type
27
+ when ::RBS::Types::Bases::Class
28
+ return unless type.location
29
+
30
+ range = location_to_range(type.location)
31
+ add_offense(range) do |corrector|
32
+ corrector.replace(range, 'self')
33
+ end
34
+ else
35
+ type.each_type do |t|
36
+ check_type(t)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Mixin
7
+ # Shared implementation of `RBS/Style/ClassicType` and `RBSInline/Style/ClassicType`.
8
+ # @rbs module-self: RuboCop::Cop::Base
9
+ # @rbs module-self: RuboCop::RBS::CopHelper
10
+ module ClassicType
11
+ Types = ::RBS::Types #: module-alias
12
+
13
+ #: (::RBS::AST::Members::MethodDefinition | ::RBS::AST::Ruby::Members::DefMember decl) -> void
14
+ def check_def(decl)
15
+ decl.overloads.each do |overload|
16
+ overload.method_type.each_type do |type|
17
+ check_type(type)
18
+ end
19
+ end
20
+ end
21
+
22
+ #: (untyped member) -> void
23
+ def check_member(member)
24
+ type = member.type
25
+ check_type(type) if type&.location
26
+ end
27
+
28
+ #: (::RBS::Types::t type) -> untyped
29
+ def check_type(type)
30
+ find_replacement(type) do |t, replaced|
31
+ location = t.location or next
32
+
33
+ range = location_to_range(location)
34
+ add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
35
+ corrector.replace(range, replaced)
36
+ end
37
+ end
38
+ end
39
+
40
+ #: (::RBS::Types::t type) ?{ ([::RBS::Types::t, String]) -> untyped } -> untyped
41
+ def find_replacement(type, &block)
42
+ case type
43
+ when Types::Record,
44
+ Types::Tuple,
45
+ Types::Union,
46
+ Types::Intersection,
47
+ Types::Optional,
48
+ Types::Proc,
49
+ Types::Alias,
50
+ Types::Interface
51
+ type.each_type do |t|
52
+ find_replacement(t, &block)
53
+ end
54
+ when Types::ClassInstance
55
+ case type.name.to_s
56
+ when 'TrueClass', '::TrueClass'
57
+ block&.call([type, 'true'])
58
+ when 'FalseClass', '::FalseClass'
59
+ block&.call([type, 'false'])
60
+ when 'NilClass', '::NilClass'
61
+ block&.call([type, 'nil'])
62
+ end
63
+ type.each_type do |arg|
64
+ find_replacement(arg, &block)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end