rubocop-rbs_inline 1.5.4 → 1.6.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 +4 -4
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +2 -1
- data/Rakefile +20 -4
- data/config/default.yml +51 -0
- data/lib/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rb +1 -1
- data/lib/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rb +1 -1
- data/lib/rubocop/cop/style/rbs_inline/missing_type_annotation.rb +10 -0
- data/lib/rubocop/cop/style/rbs_inline/parameters_separator.rb +2 -0
- data/lib/rubocop/cop/style/rbs_inline/untyped_instance_variable.rb +86 -17
- data/lib/rubocop/rbs_inline/version.rb +1 -1
- data/rbs_collection.lock.yaml +18 -14
- data/sig/rubocop/cop/style/rbs_inline/missing_type_annotation.rbs +3 -0
- data/sig/rubocop/cop/style/rbs_inline/untyped_instance_variable.rbs +38 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13356ee2ff7161f55fabd910db6c5baf0e49a9c45baf4f45cb056c0dd530d1bc
|
|
4
|
+
data.tar.gz: 02fa848f90ced8e1262cdb7fca6fc17f62472594f374b03ce103ebfb978aac15
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60d860bb7082c040502b9bbba4cdf00ca265f9cc2cb5a7df9a71b597f50241fb722f9c0e234db67eecccf0e9f75611fbc92099fbd76eb063372953b79ac9a259
|
|
7
|
+
data.tar.gz: ffa3593debf4c47cfb605f4da9f6e23615d628253044eb05da335cdf4019535e1f3bf676c55de6ed4290c49c58b17f2fd50a6056c99d6eba4165fcd4ed5a58f4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.0 (2026-07-05)
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- All cops now exclude `spec/**/*` and `test/**/*` by default. Override with `Exclude: []` per cop to lint annotations in test code.
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **Style/RbsInline/UntypedInstanceVariable**: No longer reports a false positive for class instance variables (assigned inside `class << self` or `def self.foo`) that have a `# @rbs self.@name: Type` annotation.
|
|
12
|
+
|
|
13
|
+
## 1.5.5 (2026-05-19)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **Style/RbsInline/ParametersSeparator**: No longer reports false positives for `# @rbs` method type signature annotations such as `# @rbs (Type) -> ReturnType` or `# @rbs [T] (T) -> T`.
|
|
18
|
+
- **Style/RbsInline/MissingTypeAnnotation**: Recognizes `# @rbs` method type signature annotations (e.g. `# @rbs (Type) -> ReturnType`) as satisfying the `method_type_signature` and `method_type_signature_or_return_annotation` styles.
|
|
19
|
+
|
|
3
20
|
## 1.5.4 (2026-03-30)
|
|
4
21
|
|
|
5
22
|
### Internal
|
data/CLAUDE.md
CHANGED
|
@@ -20,7 +20,8 @@ bundle exec rake rubocop:autocorrect # safe autocorrect
|
|
|
20
20
|
bundle exec rake rubocop:autocorrect_all # all autocorrect
|
|
21
21
|
|
|
22
22
|
# Type check
|
|
23
|
-
bundle exec rake
|
|
23
|
+
bundle exec rake steep # runs steep check
|
|
24
|
+
bundle exec rake rbs:validate # validates RBS signatures
|
|
24
25
|
|
|
25
26
|
# Default rake task (runs specs, rubocop, and type check)
|
|
26
27
|
bundle exec rake
|
data/Rakefile
CHANGED
|
@@ -5,7 +5,9 @@ require 'rubocop/rake_task'
|
|
|
5
5
|
|
|
6
6
|
RuboCop::RakeTask.new
|
|
7
7
|
|
|
8
|
-
task default:
|
|
8
|
+
task default: :ci
|
|
9
|
+
|
|
10
|
+
task ci: %i[rubocop spec steep rbs:validate]
|
|
9
11
|
|
|
10
12
|
require 'rspec/core/rake_task'
|
|
11
13
|
|
|
@@ -33,9 +35,23 @@ task :new_cop, [:cop] do |_task, args|
|
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
namespace :rbs do
|
|
36
|
-
desc '
|
|
37
|
-
task :
|
|
38
|
+
desc 'Install RBS signatures'
|
|
39
|
+
task :install do
|
|
40
|
+
sh 'bundle', 'exec', 'rbs', 'collection', 'install', '--frozen'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc 'Generate RBS files'
|
|
44
|
+
task :generate do
|
|
45
|
+
sh 'rbs-inline', '--opt-out', '--output=sig', 'lib'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc 'Validate RBS files'
|
|
49
|
+
task validate: 'rbs:install' do
|
|
38
50
|
sh 'rbs', '-Isig', 'validate'
|
|
39
|
-
sh 'bundle', 'exec', 'steep', 'check'
|
|
40
51
|
end
|
|
41
52
|
end
|
|
53
|
+
|
|
54
|
+
desc 'Run Steep type checker'
|
|
55
|
+
task steep: 'rbs:install' do
|
|
56
|
+
sh 'bundle', 'exec', 'steep', 'check'
|
|
57
|
+
end
|
data/config/default.yml
CHANGED
|
@@ -2,41 +2,65 @@ Style/RbsInline/DataClassCommentAlignment:
|
|
|
2
2
|
Description: "Checks that `#:` inline type annotations in `Data.define` blocks are aligned."
|
|
3
3
|
Enabled: true
|
|
4
4
|
VersionAdded: '1.5.0'
|
|
5
|
+
Exclude:
|
|
6
|
+
- 'spec/**/*'
|
|
7
|
+
- 'test/**/*'
|
|
5
8
|
|
|
6
9
|
Style/RbsInline/DataDefineWithBlock:
|
|
7
10
|
Description: "Checks for `Data.define` calls with a block, which RBS::Inline does not parse."
|
|
8
11
|
Enabled: true
|
|
9
12
|
VersionAdded: '1.5.0'
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'spec/**/*'
|
|
15
|
+
- 'test/**/*'
|
|
10
16
|
|
|
11
17
|
Style/RbsInline/EmbeddedRbsSpacing:
|
|
12
18
|
Description: 'Checks that `@rbs!` comments (embedded RBS) are followed by a blank line.'
|
|
13
19
|
Enabled: true
|
|
14
20
|
VersionAdded: '1.5.0'
|
|
21
|
+
Exclude:
|
|
22
|
+
- 'spec/**/*'
|
|
23
|
+
- 'test/**/*'
|
|
15
24
|
|
|
16
25
|
Style/RbsInline/InvalidComment:
|
|
17
26
|
Description: "Checks the rbs-inline annotation comment is valid."
|
|
18
27
|
Enabled: true
|
|
19
28
|
VersionAdded: "1.0.0"
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'spec/**/*'
|
|
31
|
+
- 'test/**/*'
|
|
20
32
|
|
|
21
33
|
Style/RbsInline/InvalidTypes:
|
|
22
34
|
Description: "Checks the rbs-inline annotation comment uses valid types."
|
|
23
35
|
Enabled: true
|
|
24
36
|
VersionAdded: "1.0.0"
|
|
37
|
+
Exclude:
|
|
38
|
+
- 'spec/**/*'
|
|
39
|
+
- 'test/**/*'
|
|
25
40
|
|
|
26
41
|
Style/RbsInline/KeywordSeparator:
|
|
27
42
|
Description: "Checks the rbs-inline annotation comment does not use a separator after the keywords."
|
|
28
43
|
Enabled: true
|
|
29
44
|
VersionAdded: "1.0.0"
|
|
45
|
+
Exclude:
|
|
46
|
+
- 'spec/**/*'
|
|
47
|
+
- 'test/**/*'
|
|
30
48
|
|
|
31
49
|
Style/RbsInline/MethodCommentSpacing:
|
|
32
50
|
Description: 'Checks that method-related `@rbs` annotations are placed immediately before method definitions.'
|
|
33
51
|
Enabled: true
|
|
34
52
|
VersionAdded: '1.5.0'
|
|
53
|
+
Exclude:
|
|
54
|
+
- 'spec/**/*'
|
|
55
|
+
- 'test/**/*'
|
|
35
56
|
|
|
36
57
|
Style/RbsInline/MissingDataClassAnnotation:
|
|
37
58
|
Description: "Checks that `Data.define` attributes have inline type annotations."
|
|
38
59
|
Enabled: true
|
|
39
60
|
VersionAdded: '1.5.0'
|
|
61
|
+
Exclude:
|
|
62
|
+
- 'spec/**/*'
|
|
63
|
+
- 'test/**/*'
|
|
40
64
|
|
|
41
65
|
Style/RbsInline/MissingTypeAnnotation:
|
|
42
66
|
Description: "Checks that method definitions and attr_* declarations have RBS inline type annotations."
|
|
@@ -49,22 +73,34 @@ Style/RbsInline/MissingTypeAnnotation:
|
|
|
49
73
|
- method_type_signature
|
|
50
74
|
- method_type_signature_or_return_annotation
|
|
51
75
|
Visibility: all
|
|
76
|
+
Exclude:
|
|
77
|
+
- 'spec/**/*'
|
|
78
|
+
- 'test/**/*'
|
|
52
79
|
|
|
53
80
|
Style/RbsInline/ParametersSeparator:
|
|
54
81
|
Description: "Checks the rbs-inline annotation comment uses a separator to parameters"
|
|
55
82
|
Enabled: true
|
|
56
83
|
VersionAdded: "1.0.0"
|
|
84
|
+
Exclude:
|
|
85
|
+
- 'spec/**/*'
|
|
86
|
+
- 'test/**/*'
|
|
57
87
|
|
|
58
88
|
Style/RbsInline/RedundantAnnotationWithSkip:
|
|
59
89
|
Description: "Checks for redundant type annotations when `@rbs skip` or `@rbs override` is present."
|
|
60
90
|
Enabled: true
|
|
61
91
|
SafeAutoCorrect: false
|
|
62
92
|
VersionAdded: '1.5.0'
|
|
93
|
+
Exclude:
|
|
94
|
+
- 'spec/**/*'
|
|
95
|
+
- 'test/**/*'
|
|
63
96
|
|
|
64
97
|
Style/RbsInline/RedundantInstanceVariableAnnotation:
|
|
65
98
|
Description: "Checks for redundant `@rbs` instance variable type annotation when `attr_*` with an inline type annotation is already defined."
|
|
66
99
|
Enabled: true
|
|
67
100
|
VersionAdded: '1.5.0'
|
|
101
|
+
Exclude:
|
|
102
|
+
- 'spec/**/*'
|
|
103
|
+
- 'test/**/*'
|
|
68
104
|
|
|
69
105
|
Style/RbsInline/RedundantTypeAnnotation:
|
|
70
106
|
Description: "Checks for redundant type annotations when multiple type specifications exist for the same method definition."
|
|
@@ -76,6 +112,9 @@ Style/RbsInline/RedundantTypeAnnotation:
|
|
|
76
112
|
- method_type_signature
|
|
77
113
|
- doc_style
|
|
78
114
|
- doc_style_and_return_annotation
|
|
115
|
+
Exclude:
|
|
116
|
+
- 'spec/**/*'
|
|
117
|
+
- 'test/**/*'
|
|
79
118
|
|
|
80
119
|
Style/RbsInline/RequireRbsInlineComment:
|
|
81
120
|
Description: "Checks the presence or absence of `# rbs_inline: enabled` magic comment."
|
|
@@ -85,18 +124,30 @@ Style/RbsInline/RequireRbsInlineComment:
|
|
|
85
124
|
SupportedStyles:
|
|
86
125
|
- always
|
|
87
126
|
- never
|
|
127
|
+
Exclude:
|
|
128
|
+
- 'spec/**/*'
|
|
129
|
+
- 'test/**/*'
|
|
88
130
|
|
|
89
131
|
Style/RbsInline/UnmatchedAnnotations:
|
|
90
132
|
Description: "Checks the rbs-inline annotation comment is surely matched."
|
|
91
133
|
Enabled: true
|
|
92
134
|
VersionAdded: "1.0.0"
|
|
135
|
+
Exclude:
|
|
136
|
+
- 'spec/**/*'
|
|
137
|
+
- 'test/**/*'
|
|
93
138
|
|
|
94
139
|
Style/RbsInline/UntypedInstanceVariable:
|
|
95
140
|
Description: "Checks that instance variables in classes/modules have RBS type annotations."
|
|
96
141
|
Enabled: true
|
|
97
142
|
VersionAdded: '1.5.0'
|
|
143
|
+
Exclude:
|
|
144
|
+
- 'spec/**/*'
|
|
145
|
+
- 'test/**/*'
|
|
98
146
|
|
|
99
147
|
Style/RbsInline/VariableCommentSpacing:
|
|
100
148
|
Description: 'Checks that `@rbs` variable comments are followed by a blank line.'
|
|
101
149
|
Enabled: true
|
|
102
150
|
VersionAdded: '1.5.0'
|
|
151
|
+
Exclude:
|
|
152
|
+
- 'spec/**/*'
|
|
153
|
+
- 'test/**/*'
|
|
@@ -281,6 +281,7 @@ module RuboCop
|
|
|
281
281
|
# @rbs node: RuboCop::AST::DefNode
|
|
282
282
|
def check_method_type_signature(node) #: void
|
|
283
283
|
return if find_method_type_signature_comments(node.location.line)
|
|
284
|
+
return if rbs_method_type_annotation?(node.location.line)
|
|
284
285
|
|
|
285
286
|
add_offense(offense_range_for_def(node), message: METHOD_TYPE_SIGNATURE_MESSAGE)
|
|
286
287
|
end
|
|
@@ -298,6 +299,7 @@ module RuboCop
|
|
|
298
299
|
def check_method_type_signature_or_return_annotation(node) #: void
|
|
299
300
|
return if find_method_type_signature_comments(node.location.line)
|
|
300
301
|
return if find_trailing_comment(method_parameter_list_end_line(node))
|
|
302
|
+
return if rbs_method_type_annotation?(node.location.line)
|
|
301
303
|
|
|
302
304
|
add_offense(offense_range_for_def(node), message: METHOD_TYPE_SIGNATURE_OR_RETURN_ANNOTATION_MESSAGE)
|
|
303
305
|
end
|
|
@@ -393,6 +395,14 @@ module RuboCop
|
|
|
393
395
|
annotation.comments.any? { |c| c.location.slice.match?(/\A#\s+@rbs\s+(skip|override)\b/) }
|
|
394
396
|
end
|
|
395
397
|
|
|
398
|
+
# @rbs line: Integer
|
|
399
|
+
def rbs_method_type_annotation?(line) #: bool
|
|
400
|
+
annotation = find_leading_annotation(line)
|
|
401
|
+
return false unless annotation
|
|
402
|
+
|
|
403
|
+
annotation.each_annotation.any?(RBS::Inline::AST::Annotations::Method)
|
|
404
|
+
end
|
|
405
|
+
|
|
396
406
|
# Returns acceptable annotation name variants for the parameter, or nil for unrecognized types.
|
|
397
407
|
# @rbs argument: RuboCop::AST::Node
|
|
398
408
|
# @rbs name: String
|
|
@@ -51,6 +51,8 @@ module RuboCop
|
|
|
51
51
|
return true if RBS_INLINE_KEYWORDS.include?(matched)
|
|
52
52
|
return true if RBS_INLINE_REGEXP_KEYWORDS.any? { |regexp| matched =~ regexp }
|
|
53
53
|
return true if matched.end_with?(':')
|
|
54
|
+
# method type signature, e.g. `# @rbs (Integer) -> String` or `# @rbs [T] (T) -> T`
|
|
55
|
+
return true if matched.start_with?('(', '[')
|
|
54
56
|
|
|
55
57
|
false
|
|
56
58
|
end
|
|
@@ -10,6 +10,8 @@ module RuboCop
|
|
|
10
10
|
#
|
|
11
11
|
# Instance variables must either have a `# @rbs @ivar: Type` annotation
|
|
12
12
|
# or be covered by a typed `attr_reader/writer/accessor` declaration.
|
|
13
|
+
# Class-level (singleton) instance variables, assigned inside `class << self`
|
|
14
|
+
# or `def self.x`, must be annotated with `# @rbs self.@ivar: Type` instead.
|
|
13
15
|
#
|
|
14
16
|
# Only instance variables that are **assigned** within the class/module are checked.
|
|
15
17
|
# Read-only references are ignored because the variable may be defined in a parent class.
|
|
@@ -47,30 +49,49 @@ module RuboCop
|
|
|
47
49
|
# end
|
|
48
50
|
# end
|
|
49
51
|
#
|
|
50
|
-
class
|
|
52
|
+
# # good (class-level ivar annotated with `self.@`)
|
|
53
|
+
# class Foo
|
|
54
|
+
# # @rbs self.@instance: Foo
|
|
55
|
+
#
|
|
56
|
+
# def self.instance
|
|
57
|
+
# @instance ||= new
|
|
58
|
+
# end
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
class UntypedInstanceVariable < Base # rubocop:disable Metrics/ClassLength
|
|
51
62
|
include ASTUtils
|
|
52
63
|
include CommentParser
|
|
53
64
|
include RangeHelp
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
MSG_IVAR = 'Instance variable `%<name>s` is not typed. ' \
|
|
67
|
+
'Add `# @rbs %<name>s: Type` or use `attr_* :%<bare_name>s #: Type`.'
|
|
68
|
+
MSG_CIVAR = 'Class instance variable `%<name>s` is not typed. ' \
|
|
69
|
+
'Add `# @rbs self.%<name>s: Type` or use `attr_* :%<bare_name>s #: Type`.'
|
|
57
70
|
|
|
58
71
|
ATTR_METHODS = %i[attr_reader attr_writer attr_accessor].freeze
|
|
59
72
|
|
|
60
|
-
# @rbs! type scope = {
|
|
73
|
+
# @rbs! type scope = {
|
|
74
|
+
# typed_ivars: Set[Symbol],
|
|
75
|
+
# typed_class_ivars: Set[Symbol],
|
|
76
|
+
# assigned_ivars: Hash[Symbol, RuboCop::AST::Node],
|
|
77
|
+
# assigned_class_ivars: Hash[Symbol, RuboCop::AST::Node],
|
|
78
|
+
# singleton_depth: Integer
|
|
79
|
+
# }
|
|
61
80
|
|
|
62
81
|
attr_reader :scope_stack #: Array[scope]
|
|
63
82
|
attr_reader :ivar_type_annotations #: Hash[Integer, Symbol]
|
|
83
|
+
attr_reader :civar_type_annotations #: Hash[Integer, Symbol]
|
|
64
84
|
|
|
65
85
|
def on_new_investigation #: void
|
|
66
86
|
parse_comments
|
|
67
87
|
@scope_stack = []
|
|
68
|
-
@ivar_type_annotations = collect_ivar_type_annotations
|
|
88
|
+
@ivar_type_annotations, @civar_type_annotations = collect_ivar_type_annotations
|
|
69
89
|
push_scope
|
|
70
90
|
end
|
|
71
91
|
|
|
72
92
|
def on_investigation_end #: void
|
|
73
93
|
ivar_type_annotations.each_value { |name| current_scope[:typed_ivars] << name }
|
|
94
|
+
civar_type_annotations.each_value { |name| current_scope[:typed_class_ivars] << name }
|
|
74
95
|
report_offenses
|
|
75
96
|
pop_scope
|
|
76
97
|
end
|
|
@@ -91,10 +112,26 @@ module RuboCop
|
|
|
91
112
|
|
|
92
113
|
alias after_module after_class
|
|
93
114
|
|
|
115
|
+
# @rbs _node: RuboCop::AST::Node
|
|
116
|
+
def on_sclass(_node) #: void
|
|
117
|
+
current_scope[:singleton_depth] += 1
|
|
118
|
+
end
|
|
119
|
+
alias on_defs on_sclass
|
|
120
|
+
|
|
121
|
+
# @rbs _node: RuboCop::AST::Node
|
|
122
|
+
def after_sclass(_node) #: void
|
|
123
|
+
current_scope[:singleton_depth] -= 1
|
|
124
|
+
end
|
|
125
|
+
alias after_defs after_sclass
|
|
126
|
+
|
|
94
127
|
# @rbs node: RuboCop::AST::Node
|
|
95
128
|
def on_ivasgn(node) #: void
|
|
96
129
|
name = node.children.first #: Symbol
|
|
97
|
-
|
|
130
|
+
if singleton_context?
|
|
131
|
+
current_scope[:assigned_class_ivars][name] ||= node
|
|
132
|
+
else
|
|
133
|
+
current_scope[:assigned_ivars][name] ||= node
|
|
134
|
+
end
|
|
98
135
|
end
|
|
99
136
|
|
|
100
137
|
# @rbs node: RuboCop::AST::SendNode
|
|
@@ -113,16 +150,23 @@ module RuboCop
|
|
|
113
150
|
|
|
114
151
|
# @rbs node: RuboCop::AST::SendNode
|
|
115
152
|
def register_attr_ivars(node) #: void
|
|
153
|
+
typed = singleton_context? ? current_scope[:typed_class_ivars] : current_scope[:typed_ivars]
|
|
116
154
|
node.arguments.each do |arg|
|
|
117
155
|
case arg
|
|
118
156
|
when RuboCop::AST::SymbolNode, RuboCop::AST::StrNode
|
|
119
|
-
|
|
157
|
+
typed << :"@#{arg.value}"
|
|
120
158
|
end
|
|
121
159
|
end
|
|
122
160
|
end
|
|
123
161
|
|
|
124
162
|
def push_scope #: void
|
|
125
|
-
scope_stack.push({
|
|
163
|
+
scope_stack.push({
|
|
164
|
+
typed_ivars: Set.new,
|
|
165
|
+
typed_class_ivars: Set.new,
|
|
166
|
+
assigned_ivars: {},
|
|
167
|
+
assigned_class_ivars: {},
|
|
168
|
+
singleton_depth: 0
|
|
169
|
+
})
|
|
126
170
|
end
|
|
127
171
|
|
|
128
172
|
def pop_scope #: void
|
|
@@ -133,6 +177,10 @@ module RuboCop
|
|
|
133
177
|
scope_stack.last || raise
|
|
134
178
|
end
|
|
135
179
|
|
|
180
|
+
def singleton_context? #: bool
|
|
181
|
+
current_scope[:singleton_depth].positive?
|
|
182
|
+
end
|
|
183
|
+
|
|
136
184
|
# @rbs node: RuboCop::AST::Node
|
|
137
185
|
def collect_typed_ivars_for_scope(node) #: void
|
|
138
186
|
class_start = node.location.line
|
|
@@ -140,24 +188,45 @@ module RuboCop
|
|
|
140
188
|
ivar_type_annotations.reject! do |line, name|
|
|
141
189
|
current_scope[:typed_ivars] << name if line.between?(class_start, class_end)
|
|
142
190
|
end
|
|
191
|
+
civar_type_annotations.reject! do |line, name|
|
|
192
|
+
current_scope[:typed_class_ivars] << name if line.between?(class_start, class_end)
|
|
193
|
+
end
|
|
143
194
|
end
|
|
144
195
|
|
|
145
|
-
def collect_ivar_type_annotations #: Hash[Integer, Symbol]
|
|
146
|
-
|
|
196
|
+
def collect_ivar_type_annotations #: [Hash[Integer, Symbol], Hash[Integer, Symbol]]
|
|
197
|
+
ivar = {} #: Hash[Integer, Symbol]
|
|
198
|
+
civar = {} #: Hash[Integer, Symbol]
|
|
199
|
+
parsed_comments.flat_map { |r| r.each_annotation.to_a }.each do |ann|
|
|
147
200
|
next unless ann.is_a?(RBS::Inline::AST::Annotations::IvarType)
|
|
148
|
-
next if ann.class_instance
|
|
149
201
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
202
|
+
if ann.class_instance
|
|
203
|
+
civar[annotation_line(ann)] = ann.name
|
|
204
|
+
else
|
|
205
|
+
ivar[annotation_line(ann)] = ann.name
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
[ivar, civar]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @rbs ann: RBS::Inline::AST::Annotations::IvarType
|
|
212
|
+
def annotation_line(ann) #: Integer
|
|
213
|
+
ann.source.comments.first&.location&.start_line || 0
|
|
153
214
|
end
|
|
154
215
|
|
|
155
216
|
def report_offenses #: void
|
|
156
|
-
current_scope[:assigned_ivars]
|
|
157
|
-
|
|
217
|
+
report_untyped(current_scope[:assigned_ivars], current_scope[:typed_ivars], MSG_IVAR)
|
|
218
|
+
report_untyped(current_scope[:assigned_class_ivars], current_scope[:typed_class_ivars], MSG_CIVAR)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# @rbs assigned: Hash[Symbol, RuboCop::AST::Node]
|
|
222
|
+
# @rbs typed: Set[Symbol]
|
|
223
|
+
# @rbs message_template: String
|
|
224
|
+
def report_untyped(assigned, typed, message_template) #: void
|
|
225
|
+
assigned.each do |name, node|
|
|
226
|
+
next if typed.include?(name)
|
|
158
227
|
|
|
159
228
|
bare_name = name.to_s.delete_prefix('@')
|
|
160
|
-
add_offense(name_location(node), message: format(
|
|
229
|
+
add_offense(name_location(node), message: format(message_template, name:, bare_name:))
|
|
161
230
|
end
|
|
162
231
|
end
|
|
163
232
|
end
|
data/rbs_collection.lock.yaml
CHANGED
|
@@ -6,7 +6,7 @@ gems:
|
|
|
6
6
|
source:
|
|
7
7
|
type: git
|
|
8
8
|
name: ruby/gem_rbs_collection
|
|
9
|
-
revision:
|
|
9
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
10
10
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
11
11
|
repo_dir: gems
|
|
12
12
|
- name: diff-lcs
|
|
@@ -14,7 +14,7 @@ gems:
|
|
|
14
14
|
source:
|
|
15
15
|
type: git
|
|
16
16
|
name: ruby/gem_rbs_collection
|
|
17
|
-
revision:
|
|
17
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
18
18
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
19
19
|
repo_dir: gems
|
|
20
20
|
- name: fileutils
|
|
@@ -30,13 +30,17 @@ gems:
|
|
|
30
30
|
source:
|
|
31
31
|
type: git
|
|
32
32
|
name: ruby/gem_rbs_collection
|
|
33
|
-
revision:
|
|
33
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
34
34
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
35
35
|
repo_dir: gems
|
|
36
36
|
- name: logger
|
|
37
|
-
version: '
|
|
37
|
+
version: '1.7'
|
|
38
38
|
source:
|
|
39
|
-
type:
|
|
39
|
+
type: git
|
|
40
|
+
name: ruby/gem_rbs_collection
|
|
41
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
42
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
43
|
+
repo_dir: gems
|
|
40
44
|
- name: monitor
|
|
41
45
|
version: '0'
|
|
42
46
|
source:
|
|
@@ -50,7 +54,7 @@ gems:
|
|
|
50
54
|
source:
|
|
51
55
|
type: git
|
|
52
56
|
name: ruby/gem_rbs_collection
|
|
53
|
-
revision:
|
|
57
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
54
58
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
55
59
|
repo_dir: gems
|
|
56
60
|
- name: parser
|
|
@@ -58,7 +62,7 @@ gems:
|
|
|
58
62
|
source:
|
|
59
63
|
type: git
|
|
60
64
|
name: ruby/gem_rbs_collection
|
|
61
|
-
revision:
|
|
65
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
62
66
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
63
67
|
repo_dir: gems
|
|
64
68
|
- name: prism
|
|
@@ -70,7 +74,7 @@ gems:
|
|
|
70
74
|
source:
|
|
71
75
|
type: git
|
|
72
76
|
name: ruby/gem_rbs_collection
|
|
73
|
-
revision:
|
|
77
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
74
78
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
75
79
|
repo_dir: gems
|
|
76
80
|
- name: rake
|
|
@@ -78,15 +82,15 @@ gems:
|
|
|
78
82
|
source:
|
|
79
83
|
type: git
|
|
80
84
|
name: ruby/gem_rbs_collection
|
|
81
|
-
revision:
|
|
85
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
82
86
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
83
87
|
repo_dir: gems
|
|
84
88
|
- name: rbs
|
|
85
|
-
version:
|
|
89
|
+
version: 4.0.2
|
|
86
90
|
source:
|
|
87
91
|
type: rubygems
|
|
88
92
|
- name: rbs-inline
|
|
89
|
-
version: 0.
|
|
93
|
+
version: 0.14.0
|
|
90
94
|
source:
|
|
91
95
|
type: rubygems
|
|
92
96
|
- name: rdoc
|
|
@@ -98,7 +102,7 @@ gems:
|
|
|
98
102
|
source:
|
|
99
103
|
type: git
|
|
100
104
|
name: ruby/gem_rbs_collection
|
|
101
|
-
revision:
|
|
105
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
102
106
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
103
107
|
repo_dir: gems
|
|
104
108
|
- name: rubocop
|
|
@@ -106,7 +110,7 @@ gems:
|
|
|
106
110
|
source:
|
|
107
111
|
type: git
|
|
108
112
|
name: ruby/gem_rbs_collection
|
|
109
|
-
revision:
|
|
113
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
110
114
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
111
115
|
repo_dir: gems
|
|
112
116
|
- name: rubocop-ast
|
|
@@ -114,7 +118,7 @@ gems:
|
|
|
114
118
|
source:
|
|
115
119
|
type: git
|
|
116
120
|
name: ruby/gem_rbs_collection
|
|
117
|
-
revision:
|
|
121
|
+
revision: 5689759efdc7875d533e8e5b2376b4ab89472e36
|
|
118
122
|
remote: https://github.com/ruby/gem_rbs_collection.git
|
|
119
123
|
repo_dir: gems
|
|
120
124
|
- name: strscan
|
|
@@ -246,6 +246,9 @@ module RuboCop
|
|
|
246
246
|
# @rbs line: Integer
|
|
247
247
|
def skip_annotation?: (Integer line) -> bool
|
|
248
248
|
|
|
249
|
+
# @rbs line: Integer
|
|
250
|
+
def rbs_method_type_annotation?: (Integer line) -> bool
|
|
251
|
+
|
|
249
252
|
# Returns acceptable annotation name variants for the parameter, or nil for unrecognized types.
|
|
250
253
|
# @rbs argument: RuboCop::AST::Node
|
|
251
254
|
# @rbs name: String
|
|
@@ -8,6 +8,8 @@ module RuboCop
|
|
|
8
8
|
#
|
|
9
9
|
# Instance variables must either have a `# @rbs @ivar: Type` annotation
|
|
10
10
|
# or be covered by a typed `attr_reader/writer/accessor` declaration.
|
|
11
|
+
# Class-level (singleton) instance variables, assigned inside `class << self`
|
|
12
|
+
# or `def self.x`, must be annotated with `# @rbs self.@ivar: Type` instead.
|
|
11
13
|
#
|
|
12
14
|
# Only instance variables that are **assigned** within the class/module are checked.
|
|
13
15
|
# Read-only references are ignored because the variable may be defined in a parent class.
|
|
@@ -44,6 +46,15 @@ module RuboCop
|
|
|
44
46
|
# @baz
|
|
45
47
|
# end
|
|
46
48
|
# end
|
|
49
|
+
#
|
|
50
|
+
# # good (class-level ivar annotated with `self.@`)
|
|
51
|
+
# class Foo
|
|
52
|
+
# # @rbs self.@instance: Foo
|
|
53
|
+
#
|
|
54
|
+
# def self.instance
|
|
55
|
+
# @instance ||= new
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
47
58
|
class UntypedInstanceVariable < Base
|
|
48
59
|
include ASTUtils
|
|
49
60
|
|
|
@@ -51,16 +62,20 @@ module RuboCop
|
|
|
51
62
|
|
|
52
63
|
include RangeHelp
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
MSG_IVAR: ::String
|
|
66
|
+
|
|
67
|
+
MSG_CIVAR: ::String
|
|
55
68
|
|
|
56
69
|
ATTR_METHODS: untyped
|
|
57
70
|
|
|
58
|
-
type scope = { typed_ivars: Set[Symbol], assigned_ivars: Hash[Symbol, RuboCop::AST::Node] }
|
|
71
|
+
type scope = { typed_ivars: Set[Symbol], typed_class_ivars: Set[Symbol], assigned_ivars: Hash[Symbol, RuboCop::AST::Node], assigned_class_ivars: Hash[Symbol, RuboCop::AST::Node], singleton_depth: Integer }
|
|
59
72
|
|
|
60
73
|
attr_reader scope_stack: Array[scope]
|
|
61
74
|
|
|
62
75
|
attr_reader ivar_type_annotations: Hash[Integer, Symbol]
|
|
63
76
|
|
|
77
|
+
attr_reader civar_type_annotations: Hash[Integer, Symbol]
|
|
78
|
+
|
|
64
79
|
def on_new_investigation: () -> void
|
|
65
80
|
|
|
66
81
|
def on_investigation_end: () -> void
|
|
@@ -75,6 +90,16 @@ module RuboCop
|
|
|
75
90
|
|
|
76
91
|
alias after_module after_class
|
|
77
92
|
|
|
93
|
+
# @rbs _node: RuboCop::AST::Node
|
|
94
|
+
def on_sclass: (untyped _node) -> void
|
|
95
|
+
|
|
96
|
+
alias on_defs on_sclass
|
|
97
|
+
|
|
98
|
+
# @rbs _node: RuboCop::AST::Node
|
|
99
|
+
def after_sclass: (untyped _node) -> void
|
|
100
|
+
|
|
101
|
+
alias after_defs after_sclass
|
|
102
|
+
|
|
78
103
|
# @rbs node: RuboCop::AST::Node
|
|
79
104
|
def on_ivasgn: (RuboCop::AST::Node node) -> void
|
|
80
105
|
|
|
@@ -95,12 +120,22 @@ module RuboCop
|
|
|
95
120
|
|
|
96
121
|
def current_scope: () -> scope
|
|
97
122
|
|
|
123
|
+
def singleton_context?: () -> bool
|
|
124
|
+
|
|
98
125
|
# @rbs node: RuboCop::AST::Node
|
|
99
126
|
def collect_typed_ivars_for_scope: (RuboCop::AST::Node node) -> void
|
|
100
127
|
|
|
101
|
-
def collect_ivar_type_annotations: () -> Hash[Integer, Symbol]
|
|
128
|
+
def collect_ivar_type_annotations: () -> [ Hash[Integer, Symbol], Hash[Integer, Symbol] ]
|
|
129
|
+
|
|
130
|
+
# @rbs ann: RBS::Inline::AST::Annotations::IvarType
|
|
131
|
+
def annotation_line: (RBS::Inline::AST::Annotations::IvarType ann) -> Integer
|
|
102
132
|
|
|
103
133
|
def report_offenses: () -> void
|
|
134
|
+
|
|
135
|
+
# @rbs assigned: Hash[Symbol, RuboCop::AST::Node]
|
|
136
|
+
# @rbs typed: Set[Symbol]
|
|
137
|
+
# @rbs message_template: String
|
|
138
|
+
def report_untyped: (Hash[Symbol, RuboCop::AST::Node] assigned, Set[Symbol] typed, String message_template) -> void
|
|
104
139
|
end
|
|
105
140
|
end
|
|
106
141
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-rbs_inline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Takeshi KOMIYA
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lint_roller
|