rubocop-on-rbs 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2d0a08d15b11889f3e9cb30b870ab7f10708d79fc88984271cd0d1d229a6eb2
4
- data.tar.gz: c5bbecab5e33bbbddcab3081b1df9c0370948e1c4cbd2fbe9ea1f9bb8e7cf820
3
+ metadata.gz: adb415dc438caa7d859497f2915d37fe647ba2c0a0c396a1afc79f6aec2a53ee
4
+ data.tar.gz: 621b0e9338aab521860cf7e73c7b346015f3e9e51b6af06d9159b1844083281a
5
5
  SHA512:
6
- metadata.gz: 8153af6d71ecd6f087d9511de6a3caa2ded02a2edf6a1e51833a212d1a1fee269bfcf8c398b536ce89fedebf91b86784aba445117779101a64efb83e1082ffd8
7
- data.tar.gz: aa38d915d25385ae67af7a84d7b480b28fcd23a6e4110e273e5d42571ff1b7bf5daf0116c7803b14297cbbd4a4f4e706836b2b1d6bc770edf8d81104f76aff46
6
+ metadata.gz: 6e3357ceba540c5c6ee25188804ebe95965147e47970bc39c98fd8fe60eb8f52af762c1a3a90ca9e68be9d63e2263622cffc983b029232fd23f89d6f536a12b3
7
+ data.tar.gz: a9155f9687029947fb9bb4d0c47332a5bc3075e400872ebf1e58312f7d6cd47ffa0d37c4005c644adb08e88494c8c14d84a063e2550590db93c75ac7e95f0136
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2024-06-11
4
+
5
+ * Implement RedundantOverloadTypeParams instead of UselessOverloadTypeParams by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/1
6
+ * Introduce RBS/Lint/DuplicateOverload by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/2
7
+ * Fix typo by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/3
8
+ * Remove unnecessary Exclude settings in .rubocop.yml by @ydah in https://github.com/ksss/rubocop-on-rbs/pull/4
9
+ * Generate docs for cop by @ksss in https://github.com/ksss/rubocop-on-rbs/pull/5
10
+
3
11
  ## [0.1.0] - 2024-05-15
4
12
 
5
13
  - Initial release
data/README.md CHANGED
@@ -64,6 +64,10 @@ And restart VSCode.
64
64
 
65
65
  ## Departments
66
66
 
67
+ You can see documentation for all cops.
68
+
69
+ https://github.com/ksss/rubocop-on-rbs/blob/main/docs/modules/ROOT/pages/cops.adoc
70
+
67
71
  ### RBS
68
72
 
69
73
  This gem handles many cops.
@@ -74,8 +78,6 @@ RBS:
74
78
  Enabled: true
75
79
  ```
76
80
 
77
- See `config/default.yml` for all Cop.
78
-
79
81
  ### RBS/Layout
80
82
 
81
83
  This department is a collection of relatively minor fixes has been gathered.
@@ -117,15 +119,13 @@ $ bundle exec rubocop --only RBS/Style
117
119
 
118
120
  ## Installation
119
121
 
120
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
121
-
122
122
  Install the gem and add to the application's Gemfile by executing:
123
123
 
124
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
124
+ $ bundle add rubocop-on-rbs --require false
125
125
 
126
126
  If bundler is not being used to manage dependencies, install the gem by executing:
127
127
 
128
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
128
+ $ gem install rubocop-on-rbs
129
129
 
130
130
  ## Usage
131
131
 
data/config/default.yml CHANGED
@@ -11,6 +11,10 @@ Lint:
11
11
  Exclude:
12
12
  - '**/*.rbs'
13
13
 
14
+ Style:
15
+ Exclude:
16
+ - '**/*.rbs'
17
+
14
18
  # RBS
15
19
 
16
20
  RBS:
@@ -55,6 +59,10 @@ RBS/Layout/SpaceAroundBraces:
55
59
  Description: 'Use space around `{}`'
56
60
  Enabled: true
57
61
 
62
+ RBS/Layout/SpaceAroundOperators:
63
+ Description: 'Use space around `|` or `&`'
64
+ Enabled: true
65
+
58
66
  RBS/Layout/SpaceBeforeColon:
59
67
  Description: 'Use space before `:`'
60
68
  Enabled: true
@@ -70,64 +78,30 @@ RBS/Layout/TrailingWhitespace:
70
78
  ## RBS/Lint
71
79
 
72
80
  RBS/Lint:
73
- Severity: warning
74
81
  Enabled: true
75
82
 
76
- RBS/Lint/Syntax:
77
- Description: 'Check RBS syntax'
83
+ RBS/Lint/DuplicateOverload:
84
+ Severity: warning
85
+ Description: 'Checks that there are no repeated overload bodies'
78
86
  Enabled: true
79
87
 
80
- RBS/Lint/TypeParamsArity:
81
- Description: 'Check type params arity'
82
- Enabled: true
83
- Expects:
84
- # Default expects.
85
- # You can add expects in .rubocop.yml.
86
-
87
- ## class/module
88
- Array: 1
89
- Enumerable: 1
90
- Enumerator: 2
91
- Enumerator::Chain: 1
92
- Enumerator::Generator: 1
93
- Enumerator::Lazy: 2
94
- Enumerator::Product: 1
95
- FrozenError: 1
96
- Hash: 2
97
- KeyError: 2
98
- NameError: 1
99
- NoMatchingPatternKeyError: 2
100
- NoMethodError: 1
101
- ObjectSpace::WeakKeyMap: 2
102
- Range: 1
103
- Set: 1
104
- Struct: 1
105
-
106
- ## interface
107
- Array::_Pattern: 1
108
- Enumerable::_NotFound: 1
109
- Gem::_HashLike: 2
110
- Kernel::_RationalDiv: 1
111
- Marshal::_Proc: 1
112
- String::_MatchAgainst: 2
113
- _Each: 1
114
- _EachEntry: 1
115
- _Range: 1
116
- _ToA: 1
117
- _ToAry: 1
118
- _ToH: 2
119
- _ToHash: 2
120
-
121
- ## type alias
122
- array: 1
123
- hash: 2
124
- range: 1
88
+ RBS/Lint/LiteralIntersection:
89
+ Severity: warning
90
+ Description: 'Check literal intersection'
91
+ Enabled: true
125
92
 
126
93
  RBS/Lint/UselessOverloadTypeParams:
127
- Description: 'Check useless overload type params'
94
+ Severity: warning
95
+ Description: 'Check redundant overload type params'
96
+ Enabled: true
97
+
98
+ RBS/Lint/Syntax:
99
+ Severity: fatal
100
+ Description: 'Check RBS syntax'
128
101
  Enabled: true
129
102
 
130
103
  RBS/Lint/WillSyntaxError:
104
+ Severity: warning
131
105
  Description: 'Check RBS will syntax error'
132
106
  Enabled: true
133
107
 
@@ -148,18 +122,22 @@ RBS/Style/DuplicatedType:
148
122
  Description: 'Check duplicated type'
149
123
  Enabled: true
150
124
 
151
- RBS/Style/InitializeReturnType:
152
- Description: 'Use `void` for initialize method'
125
+ RBS/Style/EmptyArgument:
126
+ Description: 'Use `()` for empty argument'
153
127
  Enabled: true
154
128
 
155
- RBS/Style/MergeUntyped:
156
- Description: 'Merge to `untyped`'
129
+ RBS/Style/InitializeReturnType:
130
+ Description: 'Use `void` for initialize method'
157
131
  Enabled: true
158
132
 
159
133
  RBS/Style/OptionalNil:
160
134
  Description: 'Use nil instead of nil?'
161
135
  Enabled: true
162
136
 
137
+ RBS/Style/RedundantParentheses:
138
+ Description: 'Remove redundant parentheses'
139
+ Enabled: true
140
+
163
141
  RBS/Style/TrueFalse:
164
142
  Description: 'Use bool instead of true | false'
165
143
  Enabled: true
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Layout
7
+ # @example default
8
+ # # bad
9
+ # Integer|String
10
+ #
11
+ # # good
12
+ # Integer | String
13
+ class SpaceAroundOperators < RuboCop::RBS::CopBase
14
+ extend AutoCorrector
15
+
16
+ def on_rbs_def(decl)
17
+ decl.overloads.each do |overload|
18
+ overload.method_type.each_type do |type|
19
+ on_type(type)
20
+ end
21
+ end
22
+ end
23
+
24
+ def on_type(type)
25
+ case type
26
+ when ::RBS::Types::Union
27
+ check_operator(type, '|')
28
+ when ::RBS::Types::Intersection
29
+ check_operator(type, '&')
30
+ end
31
+ type.each_type do |t|
32
+ on_type(t)
33
+ end
34
+ end
35
+
36
+ def check_operator(type, operator)
37
+ type.types.each_cons(2) do |before, after|
38
+ next unless before.location.end_line == after.location.start_line
39
+
40
+ operator_index = type.location.source.index(
41
+ operator,
42
+ before.location.end_pos - type.location.start_pos
43
+ ) or raise
44
+ operator_index += type.location.start_pos
45
+ operator_range = range_between(operator_index, operator_index + 1)
46
+
47
+ before_char = processed_source.raw_source[operator_index - 1]
48
+ if before_char != ' '
49
+ add_offense(operator_range, message: "Use one space before `#{operator}`.") do |corrector|
50
+ corrector.insert_before(operator_range, ' ')
51
+ end
52
+ end
53
+
54
+ after_char = processed_source.raw_source[operator_index + 1]
55
+ if after_char != ' '
56
+ add_offense(operator_range, message: "Use one space after `#{operator}`.") do |corrector|
57
+ corrector.insert_after(operator_range, ' ')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Lint
7
+ # Checks that there are no repeated overload bodies
8
+ #
9
+ # @example default
10
+ # # bad
11
+ # def foo: () -> void
12
+ # | () -> void
13
+ #
14
+ class DuplicateOverload < RuboCop::RBS::CopBase
15
+ MSG = 'Duplicate overload body detected.'
16
+
17
+ def on_rbs_def(decl)
18
+ overloads = decl.overloads
19
+ overloads.each_with_index do |overload, idx|
20
+ next if idx == overloads.size - 1
21
+
22
+ next_overloads = overloads[(idx + 1)..-1]
23
+ next_overloads.each do |next_overload|
24
+ next unless overload.method_type == next_overload.method_type
25
+
26
+ range = location_to_range(next_overload.method_type.location)
27
+ add_offense(range)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Lint
7
+ # Checks that there are no repeated overload bodies
8
+ #
9
+ # @example default
10
+ # # bad
11
+ # 1 & 2
12
+ #
13
+ # # bad
14
+ # 1 & _Foo
15
+ #
16
+ class LiteralIntersection < RuboCop::RBS::CopBase
17
+ MSG = "Don't use literals with `&`."
18
+
19
+ def on_rbs_def(decl)
20
+ decl.overloads.each do |overload|
21
+ overload.method_type.each_type do |type|
22
+ check_type(type)
23
+ end
24
+ end
25
+ end
26
+
27
+ def check_type(type)
28
+ on_type([::RBS::Types::Intersection], type) do |intersection|
29
+ check_intersection(intersection)
30
+ end
31
+ end
32
+
33
+ def on_rbs_constant(type)
34
+ check_type(type.type)
35
+ end
36
+ alias on_rbs_global on_rbs_constant
37
+ alias on_rbs_type_alias on_rbs_constant
38
+ alias on_rbs_attribute on_rbs_constant
39
+
40
+ def check_intersection(intersection)
41
+ intersection.types.each do |type|
42
+ check_intersection_child(type)
43
+ end
44
+ end
45
+
46
+ def check_intersection_child(type)
47
+ case type
48
+ when ::RBS::Types::Literal
49
+ range = location_to_range(type.location)
50
+ add_offense(range)
51
+ when ::RBS::Types::Intersection
52
+ check_intersection(type)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -10,11 +10,8 @@ module RuboCop
10
10
  # # bad
11
11
  # def foo: [T] () -> void
12
12
  #
13
- # # bad
14
- # def bar: [T, U] (T) -> void
15
- #
16
13
  # # good
17
- # def foo: [T] (Array[T]) -> T
14
+ # def foo: [T] (T) -> T
18
15
  class UselessOverloadTypeParams < RuboCop::RBS::CopBase
19
16
  MSG = 'Useless overload type variable - `%<variable>s`.'
20
17
 
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Style
7
+ # @example default
8
+ # # bad
9
+ # def foo: -> void
10
+ #
11
+ # # bad
12
+ # def foo: () { -> void } -> void
13
+ #
14
+ # # bad
15
+ # def foo: () -> ^ -> void
16
+ #
17
+ # # good
18
+ # def foo: () { () -> void } -> ^() -> void
19
+ class EmptyArgument < RuboCop::RBS::CopBase
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Insert `()` when empty argument'
23
+
24
+ def on_rbs_def(decl)
25
+ decl.overloads.each do |overload|
26
+ if !overload.method_type.location.source.start_with?('(')
27
+ range = range_between(overload.method_type.location.start_pos, overload.method_type.location.start_pos)
28
+ add_offense(range) do |corrector|
29
+ corrector.insert_before(range, '()')
30
+ end
31
+ end
32
+ if overload.method_type.block
33
+ tokens = tokenize(overload.method_type.location.source)
34
+ block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise
35
+ if tokens[block_arrow_index - 1].type != :pRPAREN
36
+ range = range_between(
37
+ overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos,
38
+ overload.method_type.location.start_pos + tokens[block_arrow_index].location.start_pos
39
+ )
40
+ add_offense(range) do |corrector|
41
+ corrector.insert_before(range, '()')
42
+ end
43
+ end
44
+ end
45
+
46
+ overload.method_type.each_type do |type|
47
+ check_type(type)
48
+ end
49
+ end
50
+ end
51
+
52
+ def on_rbs_constant(const)
53
+ check_type(const.type)
54
+ end
55
+ alias on_rbs_global on_rbs_constant
56
+ alias on_rbs_type_alias on_rbs_constant
57
+ alias on_rbs_attribute on_rbs_constant
58
+
59
+ def check_type(type)
60
+ case type
61
+ when ::RBS::Types::Proc
62
+ check_proc(type)
63
+ else
64
+ type.each_type do |t|
65
+ check_type(t)
66
+ end
67
+ end
68
+ end
69
+
70
+ def check_proc(type)
71
+ tokens = tokenize(type.location.source)
72
+ if tokens[1].type != :pLPAREN
73
+ range = range_between(
74
+ type.location.start_pos + tokens[0].location.end_pos,
75
+ type.location.start_pos + tokens[0].location.end_pos
76
+ )
77
+ add_offense(range) do |corrector|
78
+ corrector.insert_after(range, '()')
79
+ end
80
+ end
81
+
82
+ if type.block
83
+ block_arrow_index = tokens.find_index { |t| t.type == :pARROW } or raise
84
+ if tokens[block_arrow_index - 1].type != :pRPAREN
85
+ range = range_between(
86
+ type.location.start_pos + tokens[block_arrow_index].location.start_pos,
87
+ type.location.start_pos + tokens[block_arrow_index].location.start_pos
88
+ )
89
+ add_offense(range) do |corrector|
90
+ corrector.insert_before(range, '()')
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def tokenize(source)
97
+ ::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -6,18 +6,17 @@ module RuboCop
6
6
  module Style
7
7
  # @example default
8
8
  # # bad
9
- # def initialize: () -> untyped
10
- #
11
- # # bad
12
9
  # def initialize: () -> nil
13
10
  #
14
11
  # # good
12
+ # def initialize: () -> untyped
13
+ #
14
+ # # good
15
15
  # def initialize: () -> void
16
16
  class InitializeReturnType < RuboCop::RBS::CopBase
17
17
  extend AutoCorrector
18
18
  MSG = '`#initialize` method should return `void`'
19
19
 
20
- # @sig decl: ::RBS::AST::Members::MethodDefinition
21
20
  def on_rbs_def(decl)
22
21
  return unless decl.name == :initialize
23
22
  return unless decl.kind == :instance
@@ -25,6 +24,7 @@ module RuboCop
25
24
 
26
25
  decl.overloads.each do |overload|
27
26
  return_type = overload.method_type.type.return_type
27
+ next if return_type.is_a?(::RBS::Types::Bases::Any)
28
28
  next if return_type.is_a?(::RBS::Types::Bases::Void)
29
29
 
30
30
  range = location_to_range(return_type.location)
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RBS
6
+ module Style
7
+ # @example default
8
+ # # bad
9
+ # def foo: () -> (bool)
10
+ #
11
+ # # bad
12
+ # def foo: (((true | false))) -> void
13
+ #
14
+ # # good
15
+ # def foo: () -> bool
16
+ #
17
+ # # good
18
+ # def foo: ((true | false)) -> bool
19
+ class RedundantParentheses < RuboCop::RBS::CopBase
20
+ module BeforeTokenIfLparen
21
+ def before_token_if_lparen(tokens, base, fun)
22
+ first_param = fun.each_param.first
23
+ return unless first_param
24
+
25
+ b, _ = token_before_after(tokens, first_param.location.start_pos - base)
26
+ return unless b&.type == :pLPAREN
27
+
28
+ yield b
29
+ end
30
+
31
+ private
32
+
33
+ def token_before_after(tokens, pos)
34
+ token_index = tokens.bsearch_index do |t|
35
+ t.location.start_pos >= pos
36
+ end
37
+ return unless token_index
38
+
39
+ [
40
+ tokens[token_index - 1],
41
+ tokens[token_index + 1]
42
+ ]
43
+ end
44
+ end
45
+
46
+ class ParenChecker
47
+ include BeforeTokenIfLparen
48
+ include RangeHelp
49
+ attr_reader :processed_source
50
+
51
+ def initialize(processed_source:, base:, tokens:, type:, skip:, cop:)
52
+ @processed_source = processed_source
53
+ @base = base
54
+ @tokens = tokens
55
+ @type = type
56
+ @skip = skip
57
+ @cop = cop
58
+ end
59
+
60
+ def check
61
+ @cop.on_type([::RBS::Types::Proc], @type) do |proc_type|
62
+ before_token_if_lparen(@tokens, @base, proc_type.type) do |b|
63
+ @skip << (b.location.start_pos + @base)
64
+ end
65
+ if proc_type.block
66
+ before_token_if_lparen(@tokens, @base, proc_type.block.type) do |b|
67
+ @skip << (b.location.start_pos + @base)
68
+ end
69
+ end
70
+ end
71
+
72
+ excludes = [
73
+ ::RBS::Types::Union,
74
+ ::RBS::Types::Intersection,
75
+ ::RBS::Types::Proc
76
+ ]
77
+ @cop.on_not_type(excludes, @type) do |type|
78
+ check_parentheses(type)
79
+ end
80
+ end
81
+
82
+ def check_parentheses(type)
83
+ type_token_start_index = @tokens.bsearch_index do |token|
84
+ (token.location.start_pos + @base) >= type.location.start_pos
85
+ end or raise
86
+ before_token = @tokens[type_token_start_index - 1]
87
+ return if @skip.include?(before_token.location.start_pos + @base)
88
+ return if before_token&.type != :pLPAREN
89
+
90
+ type_token_end_index = @tokens.bsearch_index do |token|
91
+ (token.location.start_pos + @base) >= type.location.end_pos
92
+ end or raise
93
+ after_token = @tokens[type_token_end_index]
94
+ return if after_token&.type != :pRPAREN
95
+
96
+ range = range_between(before_token.location.start_pos + @base, after_token.location.end_pos + @base)
97
+ @cop.add_offense(range, message: "Don't use parentheses around simple type.") do |corrector|
98
+ corrector.remove(range_between(before_token.location.start_pos + @base,
99
+ before_token.location.end_pos + @base))
100
+ corrector.remove(range_between(after_token.location.start_pos + @base,
101
+ after_token.location.end_pos + @base))
102
+ end
103
+ end
104
+ end
105
+
106
+ include BeforeTokenIfLparen
107
+ extend AutoCorrector
108
+
109
+ def on_rbs_def(decl)
110
+ base = decl.location.start_pos
111
+ tokens = tokenize(decl.location.source)
112
+ skip = Set.new
113
+ decl.overloads.each do |overload|
114
+ before_token_if_lparen(tokens, base, overload.method_type.type) do |b|
115
+ skip << (b.location.start_pos + base)
116
+ end
117
+ if overload.method_type.block
118
+ before_token_if_lparen(tokens, base, overload.method_type.block.type) do |b|
119
+ skip << (b.location.start_pos + base)
120
+ end
121
+ end
122
+ overload.method_type.each_type do |type|
123
+ check_type(tokens:, type:, base:, skip:)
124
+ end
125
+ end
126
+ end
127
+
128
+ def check_type(tokens:, type:, base:, skip: Set.new)
129
+ ParenChecker.new(
130
+ processed_source:,
131
+ base:,
132
+ tokens:,
133
+ type:,
134
+ skip:,
135
+ cop: self
136
+ ).check
137
+ end
138
+
139
+ def on_rbs_constant(const)
140
+ tokens = tokenize(const.location.source)
141
+ type = const.type
142
+ base = const.location.start_pos
143
+ check_type(tokens:, type:, base:)
144
+ end
145
+ alias on_rbs_global on_rbs_constant
146
+ alias on_rbs_type_alias on_rbs_constant
147
+ alias on_rbs_attribute on_rbs_constant
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -10,19 +10,22 @@ require_relative 'rbs/layout/indentation_width'
10
10
  require_relative 'rbs/layout/overload_indentation'
11
11
  require_relative 'rbs/layout/space_around_arrow'
12
12
  require_relative 'rbs/layout/space_around_braces'
13
+ require_relative 'rbs/layout/space_around_operators'
13
14
  require_relative 'rbs/layout/space_before_colon'
14
15
  require_relative 'rbs/layout/space_before_overload'
15
16
  require_relative 'rbs/layout/trailing_whitespace'
16
17
 
17
- require_relative 'rbs/lint/syntax'
18
- require_relative 'rbs/lint/type_params_arity'
18
+ require_relative 'rbs/lint/duplicate_overload'
19
+ require_relative 'rbs/lint/literal_intersection'
19
20
  require_relative 'rbs/lint/useless_overload_type_params'
21
+ require_relative 'rbs/lint/syntax'
20
22
  require_relative 'rbs/lint/will_syntax_error'
21
23
 
22
24
  require_relative 'rbs/style/block_return_boolish'
23
- require_relative 'rbs/style/true_false'
24
25
  require_relative 'rbs/style/classic_type'
25
- require_relative 'rbs/style/optional_nil'
26
26
  require_relative 'rbs/style/duplicated_type'
27
+ require_relative 'rbs/style/empty_argument'
27
28
  require_relative 'rbs/style/initialize_return_type'
28
- require_relative 'rbs/style/merge_untyped'
29
+ require_relative 'rbs/style/optional_nil'
30
+ require_relative 'rbs/style/redundant_parentheses'
31
+ require_relative 'rbs/style/true_false'
@@ -86,6 +86,32 @@ module RuboCop
86
86
  def location_to_range(location)
87
87
  range_between(location.start_pos, location.end_pos)
88
88
  end
89
+
90
+ def tokenize(source)
91
+ ::RBS::Parser.lex(source).value.reject { |t| t.type == :tTRIVIA }
92
+ end
93
+
94
+ def on_type(types, type, &block)
95
+ case type
96
+ when *types
97
+ yield type
98
+ end
99
+ type.each_type do |t|
100
+ on_type(types, t, &block)
101
+ end
102
+ end
103
+
104
+ def on_not_type(types, type, &block)
105
+ case type
106
+ when *types
107
+ # not
108
+ else
109
+ yield type
110
+ end
111
+ type.each_type do |t|
112
+ on_not_type(types, t, &block)
113
+ end
114
+ end
89
115
  end
90
116
  end
91
117
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module RBS
5
- VERSION = '0.2.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
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.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ksss
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-06 00:00:00.000000000 Z
11
+ date: 2024-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbs
@@ -59,19 +59,22 @@ files:
59
59
  - lib/rubocop/cop/rbs/layout/overload_indentation.rb
60
60
  - lib/rubocop/cop/rbs/layout/space_around_arrow.rb
61
61
  - lib/rubocop/cop/rbs/layout/space_around_braces.rb
62
+ - lib/rubocop/cop/rbs/layout/space_around_operators.rb
62
63
  - lib/rubocop/cop/rbs/layout/space_before_colon.rb
63
64
  - lib/rubocop/cop/rbs/layout/space_before_overload.rb
64
65
  - lib/rubocop/cop/rbs/layout/trailing_whitespace.rb
66
+ - lib/rubocop/cop/rbs/lint/duplicate_overload.rb
67
+ - lib/rubocop/cop/rbs/lint/literal_intersection.rb
65
68
  - lib/rubocop/cop/rbs/lint/syntax.rb
66
- - lib/rubocop/cop/rbs/lint/type_params_arity.rb
67
69
  - lib/rubocop/cop/rbs/lint/useless_overload_type_params.rb
68
70
  - lib/rubocop/cop/rbs/lint/will_syntax_error.rb
69
71
  - lib/rubocop/cop/rbs/style/block_return_boolish.rb
70
72
  - lib/rubocop/cop/rbs/style/classic_type.rb
71
73
  - lib/rubocop/cop/rbs/style/duplicated_type.rb
74
+ - lib/rubocop/cop/rbs/style/empty_argument.rb
72
75
  - lib/rubocop/cop/rbs/style/initialize_return_type.rb
73
- - lib/rubocop/cop/rbs/style/merge_untyped.rb
74
76
  - lib/rubocop/cop/rbs/style/optional_nil.rb
77
+ - lib/rubocop/cop/rbs/style/redundant_parentheses.rb
75
78
  - lib/rubocop/cop/rbs/style/true_false.rb
76
79
  - lib/rubocop/cop/rbs_cops.rb
77
80
  - lib/rubocop/rbs.rb
@@ -1,170 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RBS
6
- module Lint
7
- # This cop checks the arity of type parameters arity.
8
- # You can add expect settings in your .rubocop.yml.
9
- #
10
- # @example Expects settings
11
- # RBS/Lint/TypeParamsArity:
12
- # Expects:
13
- # Your::Class: 1
14
- #
15
- # @example default
16
- # # bad
17
- # type a = Array[Integer, String, Symbol]
18
- #
19
- # # bad
20
- # class Foo
21
- # include Enumerable
22
- # end
23
- class TypeParamsArity < RuboCop::RBS::CopBase
24
- Types = ::RBS::Types
25
-
26
- def on_rbs_module(decl)
27
- check_type_params(decl)
28
- decl.self_types.each do |self_type|
29
- check(
30
- name: self_type.name,
31
- args: self_type.args,
32
- location: self_type.location
33
- )
34
- end
35
- check_each_mixin(decl)
36
- end
37
-
38
- def on_rbs_class(decl)
39
- check_type_params(decl)
40
- if decl.super_class
41
- check(
42
- name: decl.super_class.name,
43
- args: decl.super_class.args,
44
- location: decl.super_class.location
45
- )
46
- end
47
- check_each_mixin(decl)
48
- end
49
-
50
- def on_rbs_interface(decl)
51
- check_type_params(decl)
52
- check_each_mixin(decl)
53
- end
54
-
55
- def on_rbs_constant(const)
56
- check_type(const.type)
57
- end
58
-
59
- def on_rbs_global(global)
60
- check_type(global.type)
61
- end
62
-
63
- def on_rbs_type_alias(decl)
64
- check_type_params(decl)
65
- check_type(decl.type)
66
- decl.type.each_type do |type|
67
- check_type(type)
68
- end
69
- end
70
-
71
- def on_rbs_def(member)
72
- member.overloads.each do |overload|
73
- overload.method_type.each_type do |type|
74
- check_type(type)
75
- end
76
- end
77
- end
78
-
79
- def on_rbs_attribute(attr)
80
- check_type(attr.type)
81
- end
82
-
83
- def check_each_mixin(decl)
84
- decl.each_mixin do |mixin|
85
- check(
86
- name: mixin.name,
87
- args: mixin.args,
88
- location: mixin.location
89
- )
90
- end
91
- end
92
-
93
- def check_type_params(decl)
94
- decl.type_params.each do |type_param|
95
- if type_param.upper_bound
96
- check(
97
- name: type_param.upper_bound.name,
98
- args: type_param.upper_bound.args,
99
- location: type_param.upper_bound.location
100
- )
101
- end
102
- end
103
- end
104
-
105
- def check_type(type)
106
- case type
107
- when Types::Record,
108
- Types::Tuple,
109
- Types::Union,
110
- Types::Intersection,
111
- Types::Optional,
112
- Types::Proc
113
- type.each_type.each do |t|
114
- check_type(t)
115
- end
116
- when Types::Interface,
117
- Types::Alias,
118
- Types::ClassInstance
119
- check(
120
- name: type.name,
121
- args: type.args,
122
- location: type.location,
123
- )
124
- end
125
- end
126
-
127
- def check(name:, args:, location:)
128
- return unless name.absolute?
129
- return unless location
130
-
131
- expect_size = expects[name.to_s]
132
- return unless expect_size
133
- return unless expect_size != args.size
134
-
135
- message = if args.size == 0
136
- "Type `#{name}` is generic but used as a non generic type."
137
- else
138
- "Type `#{name}` expects #{expect_size} arguments, but #{args.size} arguments are given."
139
- end
140
- add_offense(
141
- location_to_range(location),
142
- message: message,
143
- severity: :error
144
- )
145
- end
146
-
147
- def expects
148
- @expects ||= begin
149
- expects = cop_config['Expects']
150
- raise "Expects must be a hash" unless expects.is_a?(Hash)
151
-
152
- unless expects.all? { |k, _| k.is_a?(String) }
153
- raise "[RBS/Lint/TypeParamsArity] Keys of Expects must be strings"
154
- end
155
- unless expects.all? { |_, v| v.is_a?(Integer) }
156
- raise "[RBS/Lint/TypeParamsArity] Values of Expects must be integers"
157
- end
158
-
159
- expects.transform_keys! do |k|
160
- k.start_with?('::') ? k : "::#{k}"
161
- end
162
-
163
- expects
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end
170
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module RBS
6
- module Style
7
- # @example default
8
- # # bad
9
- # def foo: (untyped?) -> untyped?
10
- #
11
- # # bad
12
- # def foo: (Integer | untyped) -> (Integer | untyped)
13
- #
14
- # # bad
15
- # def foo: (Integer & untyped) -> (Integer & untyped)
16
- #
17
- # # good
18
- # def foo: (untyped) -> untyped
19
- class MergeUntyped < RuboCop::RBS::CopBase
20
- extend AutoCorrector
21
-
22
- # @sig decl: ::RBS::AST::Members::MethodDefinition
23
- def on_rbs_def(decl)
24
- decl.overloads.each do |overload|
25
- overload.method_type.type.tap do |fun|
26
- fun.each_param do |param|
27
- check_type(param.type)
28
- end
29
- check_type(fun.return_type)
30
- end
31
- end
32
- end
33
-
34
- def check_type(type)
35
- find_replacement(type) do |method, t, replaced|
36
- case method
37
- when :replace
38
- range = location_to_range(t.location)
39
- add_offense(range, message: "Use `#{replaced}` instead of `#{t}`") do |corrector|
40
- corrector.replace(range, replaced.to_s)
41
- end
42
- when :remove
43
- range = t
44
- add_offense(range, message: "Remove `?` in Optional") do |corrector|
45
- corrector.remove(range)
46
- end
47
- end
48
- end
49
- end
50
-
51
- def find_replacement(type, &block)
52
- case type
53
- when ::RBS::Types::Optional
54
- case type.type
55
- when ::RBS::Types::Bases::Any,
56
- ::RBS::Types::Bases::Nil,
57
- ::RBS::Types::Bases::Void,
58
- ::RBS::Types::Bases::Top,
59
- ::RBS::Types::Bases::Bottom
60
- # untyped? => untyped
61
- block.call([:replace, type, type.type])
62
- when ::RBS::Types::Optional
63
- # (Integer?)? => Integer?
64
- range = Parser::Source::Range.new(processed_source.buffer, type.type.location.end_pos - 1,
65
- type.type.location.end_pos)
66
- block.call([:remove, range])
67
- find_replacement(type.type, &block)
68
- when ::RBS::Types::Union, ::RBS::Types::Intersection
69
- find_replacement(type.type, &block)
70
- end
71
- when ::RBS::Types::Union, ::RBS::Types::Intersection
72
- # (untyped | Integer) => untyped
73
- # (untyped & Integer) => untyped
74
- if type.types.any? { |t| t.is_a?(::RBS::Types::Bases::Any) }
75
- block.call([:replace, type, 'untyped'])
76
- end
77
-
78
- uniqed = type.types.uniq
79
- if uniqed.size < type.types.size
80
- block.call([:replace, type, type.class.new(types: uniqed, location: nil)])
81
- end
82
- type.types.each do |t|
83
- find_replacement(t, &block)
84
- end
85
- end
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end