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