rubocop-rbs_inline 1.7.0 → 2.0.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/.claude/hooks/pre-commit-check.sh +42 -2
- data/.claude/hooks/protect-sig-files.sh +45 -0
- data/.claude/hooks/self-review.sh +89 -0
- data/.claude/settings.json +16 -1
- data/.rubocop.yml +17 -12
- data/CHANGELOG.md +30 -0
- data/CLAUDE.md +11 -14
- data/README.md +51 -6
- data/Rakefile +12 -3
- data/config/default.yml +2 -4
- data/lib/rubocop/cop/rbs_inline_cops.rb +16 -7
- data/lib/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rb +2 -9
- data/lib/rubocop/cop/style/rbs_inline/data_define_with_block.rb +13 -7
- data/lib/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rb +3 -2
- data/lib/rubocop/cop/style/rbs_inline/invalid_comment.rb +2 -2
- data/lib/rubocop/cop/style/rbs_inline/invalid_types.rb +1 -0
- data/lib/rubocop/cop/style/rbs_inline/keyword_separator.rb +2 -2
- data/lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb +3 -2
- data/lib/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rb +2 -9
- data/lib/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rb +2 -16
- data/lib/rubocop/cop/style/rbs_inline/missing_type_annotation.rb +3 -16
- data/lib/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rb +16 -0
- data/lib/rubocop/cop/style/rbs_inline/mixin/ast_utils.rb +75 -0
- data/lib/rubocop/cop/style/rbs_inline/{comment_parser.rb → mixin/comment_parser.rb} +8 -0
- data/lib/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rb +22 -0
- data/lib/rubocop/cop/style/rbs_inline/{data_struct_helper.rb → mixin/data_struct_helper.rb} +14 -5
- data/lib/rubocop/cop/style/rbs_inline/mixin/file_filter.rb +72 -0
- data/lib/rubocop/cop/style/rbs_inline/mixin/mode_config.rb +39 -0
- data/lib/rubocop/cop/style/rbs_inline/{source_code_helper.rb → mixin/source_code_helper.rb} +3 -5
- data/lib/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rb +32 -0
- data/lib/rubocop/cop/style/rbs_inline/parameters_separator.rb +2 -2
- data/lib/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rb +2 -11
- data/lib/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rb +1 -0
- data/lib/rubocop/cop/style/rbs_inline/redundant_type_annotation.rb +6 -15
- data/lib/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rb +35 -23
- data/lib/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rb +2 -16
- data/lib/rubocop/cop/style/rbs_inline/struct_new_with_block.rb +13 -7
- data/lib/rubocop/cop/style/rbs_inline/unmatched_annotations.rb +31 -6
- data/lib/rubocop/cop/style/rbs_inline/untyped_instance_variable.rb +16 -6
- data/lib/rubocop/cop/style/rbs_inline/variable_comment_spacing.rb +3 -2
- data/lib/rubocop/rbs_inline/version.rb +1 -1
- data/rbs_collection.lock.yaml +11 -11
- data/sig/gems/rubocop/rubocop.rbs +14 -0
- data/sig/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rbs +4 -5
- data/sig/rubocop/cop/style/rbs_inline/data_define_with_block.rbs +9 -2
- data/sig/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rbs +2 -0
- data/sig/rubocop/cop/style/rbs_inline/invalid_comment.rbs +4 -3
- data/sig/rubocop/cop/style/rbs_inline/invalid_types.rbs +2 -0
- data/sig/rubocop/cop/style/rbs_inline/keyword_separator.rbs +4 -3
- data/sig/rubocop/cop/style/rbs_inline/method_comment_spacing.rbs +2 -0
- data/sig/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rbs +4 -5
- data/sig/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rbs +4 -10
- data/sig/rubocop/cop/style/rbs_inline/missing_type_annotation.rbs +4 -8
- data/sig/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rbs +16 -0
- data/sig/rubocop/cop/style/rbs_inline/{ast_utils.rbs → mixin/ast_utils.rbs} +14 -1
- data/sig/rubocop/cop/style/rbs_inline/{class_comment_alignment.rbs → mixin/class_comment_alignment.rbs} +1 -1
- data/sig/rubocop/cop/style/rbs_inline/{comment_parser.rbs → mixin/comment_parser.rbs} +5 -1
- data/sig/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rbs +18 -0
- data/sig/rubocop/cop/style/rbs_inline/{data_struct_helper.rbs → mixin/data_struct_helper.rbs} +6 -1
- data/sig/rubocop/cop/style/rbs_inline/mixin/file_filter.rbs +53 -0
- data/sig/rubocop/cop/style/rbs_inline/{missing_class_annotation.rbs → mixin/missing_class_annotation.rbs} +1 -1
- data/sig/rubocop/cop/style/rbs_inline/mixin/mode_config.rbs +27 -0
- data/sig/rubocop/cop/style/rbs_inline/{source_code_helper.rbs → mixin/source_code_helper.rbs} +1 -1
- data/sig/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rbs +26 -0
- data/sig/rubocop/cop/style/rbs_inline/parameters_separator.rbs +4 -3
- data/sig/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rbs +4 -4
- data/sig/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rbs +2 -0
- data/sig/rubocop/cop/style/rbs_inline/redundant_type_annotation.rbs +4 -4
- data/sig/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rbs +22 -5
- data/sig/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rbs +4 -10
- data/sig/rubocop/cop/style/rbs_inline/struct_new_with_block.rbs +9 -2
- data/sig/rubocop/cop/style/rbs_inline/unmatched_annotations.rbs +13 -0
- data/sig/rubocop/cop/style/rbs_inline/untyped_instance_variable.rbs +10 -0
- data/sig/rubocop/cop/style/rbs_inline/variable_comment_spacing.rbs +2 -0
- metadata +28 -18
- data/lib/rubocop/cop/style/rbs_inline/ast_utils.rb +0 -46
- data/sig/rubocop/cop/style/rbs_inline/redundant_argument_type.rbs +0 -85
- data/sig/rubocop/cop/style/rbs_inline/redundant_return_type.rbs +0 -109
- /data/.claude/hooks/{setup.sh → claude-code-web-session-start.sh} +0 -0
- /data/lib/rubocop/cop/style/rbs_inline/{class_comment_alignment.rb → mixin/class_comment_alignment.rb} +0 -0
- /data/lib/rubocop/cop/style/rbs_inline/{missing_class_annotation.rb → mixin/missing_class_annotation.rb} +0 -0
|
@@ -20,12 +20,12 @@ module RuboCop
|
|
|
20
20
|
# # @rbs param: String
|
|
21
21
|
#
|
|
22
22
|
class InvalidComment < Base
|
|
23
|
+
prepend FileFilter
|
|
23
24
|
extend AutoCorrector
|
|
25
|
+
include AnnotationKeywords
|
|
24
26
|
|
|
25
27
|
MSG = "Invalid RBS annotation comment found."
|
|
26
28
|
|
|
27
|
-
# refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
|
|
28
|
-
RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
|
|
29
29
|
RBS_INLINE_KEYWORD_PATTERN = RBS_INLINE_KEYWORDS.join("|") #: String
|
|
30
30
|
|
|
31
31
|
SIGNATURE_PATTERN = '\(.*\)\s*(\??\s*{.*?}\s*)?->\s*.*'
|
|
@@ -15,14 +15,14 @@ module RuboCop
|
|
|
15
15
|
# # @rbs module-self String
|
|
16
16
|
#
|
|
17
17
|
class KeywordSeparator < Base
|
|
18
|
+
prepend FileFilter
|
|
18
19
|
extend AutoCorrector
|
|
20
|
+
include AnnotationKeywords
|
|
19
21
|
include CommentParser
|
|
20
22
|
include RangeHelp
|
|
21
23
|
|
|
22
24
|
MSG = "Do not use `:` after the keyword."
|
|
23
25
|
|
|
24
|
-
# refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
|
|
25
|
-
RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
|
|
26
26
|
# `override` and `skip` are standalone markers that take no arguments.
|
|
27
27
|
# Even before a method definition they may not be followed by `:` alone,
|
|
28
28
|
# because `# @rbs override:` (no type) is not a valid parameter annotation.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "source_code_helper"
|
|
4
|
-
require_relative "comment_parser"
|
|
3
|
+
require_relative "mixin/source_code_helper"
|
|
4
|
+
require_relative "mixin/comment_parser"
|
|
5
5
|
|
|
6
6
|
module RuboCop
|
|
7
7
|
module Cop
|
|
@@ -56,6 +56,7 @@ module RuboCop
|
|
|
56
56
|
# end
|
|
57
57
|
#
|
|
58
58
|
class MethodCommentSpacing < Base
|
|
59
|
+
prepend FileFilter
|
|
59
60
|
extend AutoCorrector
|
|
60
61
|
include RangeHelp
|
|
61
62
|
include SourceCodeHelper
|
|
@@ -21,7 +21,9 @@ module RuboCop
|
|
|
21
21
|
# )
|
|
22
22
|
#
|
|
23
23
|
class MissingDataClassAnnotation < Base
|
|
24
|
+
prepend FileFilter
|
|
24
25
|
include MissingClassAnnotation
|
|
26
|
+
include DataClassMatcher
|
|
25
27
|
extend AutoCorrector
|
|
26
28
|
|
|
27
29
|
MSG = "Missing inline type annotation for Data attribute (e.g., `#: Type`)."
|
|
@@ -32,15 +34,6 @@ module RuboCop
|
|
|
32
34
|
|
|
33
35
|
check_missing_annotations(node)
|
|
34
36
|
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
# @rbs node: RuboCop::AST::SendNode
|
|
39
|
-
def struct_like_class?(node) #: bool
|
|
40
|
-
return false unless node.method_name == :define
|
|
41
|
-
|
|
42
|
-
(r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Data
|
|
43
|
-
end
|
|
44
37
|
end
|
|
45
38
|
end
|
|
46
39
|
end
|
|
@@ -22,7 +22,9 @@ module RuboCop
|
|
|
22
22
|
# )
|
|
23
23
|
#
|
|
24
24
|
class MissingStructClassAnnotation < Base
|
|
25
|
+
prepend FileFilter
|
|
25
26
|
include MissingClassAnnotation
|
|
27
|
+
include StructClassMatcher
|
|
26
28
|
extend AutoCorrector
|
|
27
29
|
|
|
28
30
|
MSG = "Missing inline type annotation for Struct attribute (e.g., `#: Type`)."
|
|
@@ -33,22 +35,6 @@ module RuboCop
|
|
|
33
35
|
|
|
34
36
|
check_missing_annotations(node)
|
|
35
37
|
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
# @rbs node: RuboCop::AST::SendNode
|
|
40
|
-
def struct_like_class?(node) #: bool
|
|
41
|
-
return false unless node.method_name == :new
|
|
42
|
-
|
|
43
|
-
(r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Struct
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# `Struct.new` treats a leading string argument as the struct name, so only
|
|
47
|
-
# symbol arguments are attributes.
|
|
48
|
-
# @rbs arg: RuboCop::AST::Node
|
|
49
|
-
def attr_argument?(arg) #: bool
|
|
50
|
-
arg.sym_type?
|
|
51
|
-
end
|
|
52
38
|
end
|
|
53
39
|
end
|
|
54
40
|
end
|
|
@@ -22,7 +22,8 @@ module RuboCop
|
|
|
22
22
|
# - `all`: Checks all methods regardless of visibility (default)
|
|
23
23
|
# - `public`: Only checks public methods and `attr_*` declarations
|
|
24
24
|
#
|
|
25
|
-
# Methods annotated with `# @rbs skip`
|
|
25
|
+
# Methods annotated with `# @rbs skip` or `# @rbs override`, parameters with a leading
|
|
26
|
+
# `_`, and the `...` parameter are always excluded.
|
|
26
27
|
#
|
|
27
28
|
# @example EnforcedStyle: doc_style
|
|
28
29
|
# # bad
|
|
@@ -116,6 +117,7 @@ module RuboCop
|
|
|
116
117
|
# attr_reader :name #: String
|
|
117
118
|
#
|
|
118
119
|
class MissingTypeAnnotation < Base # rubocop:disable Metrics/ClassLength
|
|
120
|
+
prepend FileFilter
|
|
119
121
|
include ASTUtils
|
|
120
122
|
include CommentParser
|
|
121
123
|
include ConfigurableEnforcedStyle
|
|
@@ -347,21 +349,6 @@ module RuboCop
|
|
|
347
349
|
add_offense(node, message: ATTRIBUTE_METHOD_MESSAGE)
|
|
348
350
|
end
|
|
349
351
|
|
|
350
|
-
# Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
|
|
351
|
-
# @rbs node: RuboCop::AST::DefNode
|
|
352
|
-
def method_parameter_list_end_line(node) #: Integer
|
|
353
|
-
args_node = args_node_for(node)
|
|
354
|
-
end_line(args_node, default: node.location.line)
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
# @rbs node: RuboCop::AST::DefNode
|
|
358
|
-
def args_node_for(node) #: RuboCop::AST::Node
|
|
359
|
-
case node.type
|
|
360
|
-
when :defs then node.children[2]
|
|
361
|
-
else node.children[1]
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
352
|
# @rbs node: RuboCop::AST::DefNode
|
|
366
353
|
def method_has_arguments?(node) #: bool
|
|
367
354
|
args_node_for(node).children.any?
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
# Provides the list of keywords that may follow `# @rbs` in an annotation comment.
|
|
8
|
+
#
|
|
9
|
+
# refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
|
|
10
|
+
module AnnotationKeywords
|
|
11
|
+
RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
module ASTUtils
|
|
8
|
+
# @rbs node: RuboCop::AST::Node
|
|
9
|
+
# @rbs default: Integer
|
|
10
|
+
def end_line(node, default:) #: Integer
|
|
11
|
+
location = node.location #: untyped
|
|
12
|
+
location.end&.line || default
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns the arguments node of a method definition.
|
|
16
|
+
# @rbs node: RuboCop::AST::DefNode
|
|
17
|
+
def args_node_for(node) #: RuboCop::AST::Node
|
|
18
|
+
case node.type
|
|
19
|
+
when :def then node.children[1]
|
|
20
|
+
when :defs then node.children[2]
|
|
21
|
+
else raise
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
|
|
26
|
+
# @rbs node: RuboCop::AST::DefNode
|
|
27
|
+
def method_parameter_list_end_line(node) #: Integer
|
|
28
|
+
end_line(args_node_for(node), default: node.location.line)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @rbs node: RuboCop::AST::Node
|
|
32
|
+
def name_location(node) #: untyped
|
|
33
|
+
location = node.location #: untyped
|
|
34
|
+
location.name
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @rbs node: RuboCop::AST::Node
|
|
38
|
+
def source!(node) #: String
|
|
39
|
+
node.source || raise
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns the name of the constant `node` is assigned to, or `nil` when the name
|
|
43
|
+
# is not statically determinable (e.g. `self::Foo = ...`).
|
|
44
|
+
# @rbs node: RuboCop::AST::Node
|
|
45
|
+
def assigned_constant_name(node) #: String?
|
|
46
|
+
parent = node.parent
|
|
47
|
+
return nil unless parent.is_a?(RuboCop::AST::CasgnNode)
|
|
48
|
+
return nil unless parent.each_path.all? { _1.const_type? || _1.cbase_type? }
|
|
49
|
+
|
|
50
|
+
# `const_name` drops the leading `::`, which would name a different constant
|
|
51
|
+
# when the assignment appears inside a namespace.
|
|
52
|
+
parent.absolute? ? "::#{parent.const_name}" : parent.const_name
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#: (RuboCop::AST::SymbolNode) -> Symbol
|
|
56
|
+
#: (RuboCop::AST::StrNode) -> Symbol
|
|
57
|
+
#: (RuboCop::AST::Node) -> Symbol?
|
|
58
|
+
def value_to_sym(node)
|
|
59
|
+
case node
|
|
60
|
+
when RuboCop::AST::SymbolNode
|
|
61
|
+
node.value
|
|
62
|
+
when RuboCop::AST::StrNode
|
|
63
|
+
case (v = node.value)
|
|
64
|
+
when String
|
|
65
|
+
v.to_sym
|
|
66
|
+
else
|
|
67
|
+
value_to_sym(v)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -13,8 +13,16 @@ module RuboCop
|
|
|
13
13
|
module CommentParser
|
|
14
14
|
attr_reader :parsed_comments #: Array[RBS::Inline::AnnotationParser::ParsingResult]
|
|
15
15
|
|
|
16
|
+
# Fallback for cops that include CommentParser without prepending FileFilter;
|
|
17
|
+
# `FileFilter` overrides this to return the real per-file decision.
|
|
18
|
+
def rbs_inline_file_skipped? #: bool
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
16
22
|
# Parse comments from the source code
|
|
17
23
|
def parse_comments #: Array[RBS::Inline::AnnotationParser::ParsingResult]
|
|
24
|
+
return @parsed_comments = [] if rbs_inline_file_skipped?
|
|
25
|
+
|
|
18
26
|
parsed_result = Prism.parse(processed_source.buffer.source)
|
|
19
27
|
@parsed_comments = RBS::Inline::AnnotationParser.parse(parsed_result.comments)
|
|
20
28
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
# Matcher for `Data.define` calls, shared by the cops that check
|
|
8
|
+
# `Data.define` class definitions.
|
|
9
|
+
module DataClassMatcher
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
# @rbs node: RuboCop::AST::SendNode
|
|
13
|
+
def struct_like_class?(node) #: bool
|
|
14
|
+
return false unless node.method_name == :define
|
|
15
|
+
|
|
16
|
+
(r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Data
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -57,10 +57,13 @@ module RuboCop
|
|
|
57
57
|
comment unless comment&.text&.match?(/\A#:/)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# The column is determined by the attribute arguments only; non-attribute
|
|
61
|
+
# arguments (e.g. the `Struct.new` name or a `keyword_init:` keyword argument)
|
|
62
|
+
# never carry an annotation and so must not influence the alignment.
|
|
60
63
|
# @rbs node: RuboCop::AST::SendNode
|
|
61
64
|
def annotation_column(node) #: Integer
|
|
62
65
|
last_arg = node.arguments.last
|
|
63
|
-
max_end_col = node.
|
|
66
|
+
max_end_col = attr_arguments(node).map do |arg|
|
|
64
67
|
comma_length = arg.equal?(last_arg) ? 0 : 1
|
|
65
68
|
arg.location.column + source!(arg).length + comma_length
|
|
66
69
|
end.max || 0
|
|
@@ -68,10 +71,12 @@ module RuboCop
|
|
|
68
71
|
max_end_col + 2
|
|
69
72
|
end
|
|
70
73
|
|
|
74
|
+
# Only attribute arguments are considered, for the same reason as
|
|
75
|
+
# {#annotation_column}.
|
|
71
76
|
# @rbs node: RuboCop::AST::SendNode
|
|
72
77
|
def longest_argname(node) #: String
|
|
73
|
-
|
|
74
|
-
args = node.
|
|
78
|
+
last_arg = node.arguments.last
|
|
79
|
+
args = attr_arguments(node).map { _1.equal?(last_arg) ? _1.source.to_s : "#{_1.source}," }
|
|
75
80
|
args.max_by(&:length) || ""
|
|
76
81
|
end
|
|
77
82
|
|
|
@@ -84,8 +89,12 @@ module RuboCop
|
|
|
84
89
|
args_source = node.arguments.each_with_index.map do |arg, i|
|
|
85
90
|
comma = i < last_index ? "," : ""
|
|
86
91
|
prefix = "#{base_indent} #{arg.source}#{comma}"
|
|
87
|
-
|
|
88
|
-
|
|
92
|
+
if attr_argument?(arg)
|
|
93
|
+
padding = " " * (longest.length - source!(arg).length - comma.length + 2)
|
|
94
|
+
"#{prefix}#{padding}#: untyped"
|
|
95
|
+
else
|
|
96
|
+
prefix
|
|
97
|
+
end
|
|
89
98
|
end.join("\n")
|
|
90
99
|
|
|
91
100
|
"(\n#{args_source}\n#{base_indent})"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
# Filters files a cop reports offenses on, based on `Mode` configuration.
|
|
8
|
+
#
|
|
9
|
+
# When `Mode` is `opt_in`, offenses are only reported for files that contain
|
|
10
|
+
# a `# rbs_inline: enabled` magic comment. When `Mode` is `opt_out`, all files
|
|
11
|
+
# are checked unless they contain `# rbs_inline: disabled`.
|
|
12
|
+
#
|
|
13
|
+
# This module is designed to be `prepend`ed to a cop so that it can short-circuit
|
|
14
|
+
# the cop's heavy work (annotation parsing via `parse_comments`) and suppress any
|
|
15
|
+
# residual offense reporting for files that should be skipped.
|
|
16
|
+
#
|
|
17
|
+
# @rbs module-self RuboCop::Cop::Base
|
|
18
|
+
module FileFilter
|
|
19
|
+
include ModeConfig
|
|
20
|
+
|
|
21
|
+
MAGIC_COMMENT_ENABLED = /\A# rbs_inline: enabled\R?\z/ #: Regexp
|
|
22
|
+
MAGIC_COMMENT_DISABLED = /\A# rbs_inline: disabled\R?\z/ #: Regexp
|
|
23
|
+
|
|
24
|
+
# @rbs @rbs_inline_skip_file: bool
|
|
25
|
+
|
|
26
|
+
def on_new_investigation #: void
|
|
27
|
+
@rbs_inline_skip_file = skip_by_mode?
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @rbs *args: untyped
|
|
32
|
+
# @rbs **kwargs: untyped
|
|
33
|
+
def add_offense(*args, **kwargs, &) #: void
|
|
34
|
+
return if @rbs_inline_skip_file
|
|
35
|
+
|
|
36
|
+
super
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Exposes the FileFilter's per-file skip decision as a proper method so
|
|
40
|
+
# helper modules (e.g. `CommentParser`) can consult it explicitly instead
|
|
41
|
+
# of poking at `@rbs_inline_skip_file` directly.
|
|
42
|
+
def rbs_inline_file_skipped? #: bool
|
|
43
|
+
@rbs_inline_skip_file == true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def skip_by_mode? #: bool
|
|
49
|
+
# `# rbs_inline: disabled` always opts a file out, regardless of Mode
|
|
50
|
+
# (matches rbs-inline itself: rbs-inline skips disabled files in both
|
|
51
|
+
# opt_in and opt_out modes).
|
|
52
|
+
return true if rbs_inline_disabled?
|
|
53
|
+
|
|
54
|
+
configured_mode == :opt_in && !rbs_inline_enabled?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Iterate the already-materialized `processed_source.comments` so this
|
|
58
|
+
# matches RequireRbsInlineComment's detection exactly (line endings,
|
|
59
|
+
# indented comments, heredoc/string content are all handled correctly
|
|
60
|
+
# by the parser).
|
|
61
|
+
def rbs_inline_enabled? #: bool
|
|
62
|
+
processed_source.comments.any? { _1.text.match?(MAGIC_COMMENT_ENABLED) }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def rbs_inline_disabled? #: bool
|
|
66
|
+
processed_source.comments.any? { _1.text.match?(MAGIC_COMMENT_DISABLED) }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
# Resolves the `Mode` setting shared by every cop in the `Style/RbsInline`
|
|
8
|
+
# department.
|
|
9
|
+
#
|
|
10
|
+
# @rbs module-self RuboCop::Cop::Base
|
|
11
|
+
module ModeConfig
|
|
12
|
+
# @rbs! type mode = :opt_in | :opt_out
|
|
13
|
+
|
|
14
|
+
SUPPORTED_MODES = %i[opt_in opt_out].freeze #: Array[mode]
|
|
15
|
+
|
|
16
|
+
# Hook RuboCop calls while mobilizing its cops, so an unsupported `Mode`
|
|
17
|
+
# fails the run as a config error instead of an error on every file.
|
|
18
|
+
def validate_config #: void
|
|
19
|
+
configured_mode
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def configured_mode #: mode
|
|
25
|
+
raw = cop_config["Mode"]
|
|
26
|
+
# `raw.to_s.to_sym` handles YAML-native Integer / Boolean without
|
|
27
|
+
# raising NoMethodError on the plain `to_sym`.
|
|
28
|
+
mode = raw.to_s.to_sym
|
|
29
|
+
return mode if SUPPORTED_MODES.include?(mode)
|
|
30
|
+
|
|
31
|
+
raise ValidationError,
|
|
32
|
+
"`Style/RbsInline: Mode: #{raw.inspect}` is not supported. " \
|
|
33
|
+
"Expected one of: #{SUPPORTED_MODES.join(", ")}."
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -12,11 +12,9 @@ module RuboCop
|
|
|
12
12
|
# Convert byte offset to character offset
|
|
13
13
|
# @rbs byte_offset: Integer
|
|
14
14
|
def character_offset(byte_offset) #: Integer
|
|
15
|
-
source = processed_source.buffer.source
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
rescue StandardError
|
|
19
|
-
byte_offset
|
|
15
|
+
source = processed_source.buffer.source
|
|
16
|
+
prefix = source.byteslice(0, byte_offset) or raise
|
|
17
|
+
prefix.size
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
# @rbs pos: Integer
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
module RbsInline
|
|
7
|
+
# Matcher for `Struct.new` calls, shared by the cops that check `Struct.new`
|
|
8
|
+
# class definitions.
|
|
9
|
+
#
|
|
10
|
+
# Also overrides {DataStructHelper#attr_argument?} for `Struct.new` semantics,
|
|
11
|
+
# so cops that include both must include this module last.
|
|
12
|
+
module StructClassMatcher
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# @rbs node: RuboCop::AST::SendNode
|
|
16
|
+
def struct_like_class?(node) #: bool
|
|
17
|
+
return false unless node.method_name == :new
|
|
18
|
+
|
|
19
|
+
(r = node.receiver).is_a?(RuboCop::AST::ConstNode) && r.short_name == :Struct
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# `Struct.new` treats a leading string argument as the struct name, so only
|
|
23
|
+
# symbol arguments are attributes.
|
|
24
|
+
# @rbs arg: RuboCop::AST::Node
|
|
25
|
+
def attr_argument?(arg) #: bool
|
|
26
|
+
arg.sym_type?
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -20,13 +20,13 @@ module RuboCop
|
|
|
20
20
|
# # good
|
|
21
21
|
# # @rbs %a{pure}
|
|
22
22
|
class ParametersSeparator < Base
|
|
23
|
+
prepend FileFilter
|
|
23
24
|
extend AutoCorrector
|
|
25
|
+
include AnnotationKeywords
|
|
24
26
|
include RangeHelp
|
|
25
27
|
|
|
26
28
|
MSG = "Use `:` as a separator between parameter name and type."
|
|
27
29
|
|
|
28
|
-
# refs: https://github.com/soutaro/rbs-inline/blob/main/lib/rbs/inline/annotation_parser/tokenizer.rb
|
|
29
|
-
RBS_INLINE_KEYWORDS = %w[inherits override use module-self generic skip module class].freeze #: Array[String]
|
|
30
30
|
RBS_INLINE_REGEXP_KEYWORDS = [/%a{(\w|-)+}/, /%a\((\w|-)+\)/, /%a\[(\w|-)+\]/].freeze #: Array[Regexp]
|
|
31
31
|
|
|
32
32
|
def on_new_investigation #: void
|
|
@@ -58,7 +58,9 @@ module RuboCop
|
|
|
58
58
|
# end
|
|
59
59
|
#
|
|
60
60
|
class RedundantAnnotationWithSkip < Base
|
|
61
|
+
prepend FileFilter
|
|
61
62
|
extend AutoCorrector
|
|
63
|
+
include ASTUtils
|
|
62
64
|
include CommentParser
|
|
63
65
|
include RangeHelp
|
|
64
66
|
include SourceCodeHelper
|
|
@@ -182,17 +184,6 @@ module RuboCop
|
|
|
182
184
|
corrector.remove(removal_range)
|
|
183
185
|
end
|
|
184
186
|
end
|
|
185
|
-
|
|
186
|
-
# Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
|
|
187
|
-
# @rbs node: RuboCop::AST::DefNode
|
|
188
|
-
def method_parameter_list_end_line(node) #: Integer
|
|
189
|
-
args_node = case node.type
|
|
190
|
-
when :def then node.children[1]
|
|
191
|
-
when :defs then node.children[2]
|
|
192
|
-
else raise
|
|
193
|
-
end
|
|
194
|
-
args_node.location.end&.line || node.location.line
|
|
195
|
-
end
|
|
196
187
|
end
|
|
197
188
|
end
|
|
198
189
|
end
|
|
@@ -80,7 +80,9 @@ module RuboCop
|
|
|
80
80
|
# end
|
|
81
81
|
#
|
|
82
82
|
class RedundantTypeAnnotation < Base
|
|
83
|
+
prepend FileFilter
|
|
83
84
|
extend AutoCorrector
|
|
85
|
+
include ASTUtils
|
|
84
86
|
include CommentParser
|
|
85
87
|
include ConfigurableEnforcedStyle
|
|
86
88
|
include RangeHelp
|
|
@@ -129,17 +131,6 @@ module RuboCop
|
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
|
|
132
|
-
# Returns the last line of the method parameter list (the closing ) line, or the def line if no parens).
|
|
133
|
-
# @rbs node: RuboCop::AST::DefNode
|
|
134
|
-
def method_parameter_list_end_line(node) #: Integer
|
|
135
|
-
args_node = case node.type
|
|
136
|
-
when :def then node.children[1]
|
|
137
|
-
when :defs then node.children[2]
|
|
138
|
-
else raise
|
|
139
|
-
end
|
|
140
|
-
args_node.location.end&.line || node.location.line
|
|
141
|
-
end
|
|
142
|
-
|
|
143
134
|
# @rbs def_line: Integer
|
|
144
135
|
# @rbs parameter_list_end_line: Integer
|
|
145
136
|
def check_return_type_redundancy(def_line, parameter_list_end_line) #: void
|
|
@@ -165,7 +156,7 @@ module RuboCop
|
|
|
165
156
|
last = comments.last or return
|
|
166
157
|
range = first.loc.expression.join(last.loc.expression)
|
|
167
158
|
add_offense(range, message: MSG_METHOD_TYPE_SIGNATURE) do |corrector|
|
|
168
|
-
|
|
159
|
+
no_acceptable_style!
|
|
169
160
|
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
|
170
161
|
end
|
|
171
162
|
end
|
|
@@ -178,7 +169,7 @@ module RuboCop
|
|
|
178
169
|
def add_offense_for_doc_style_param(annotation) #: void
|
|
179
170
|
range = annotation_range(annotation) or return
|
|
180
171
|
add_offense(range, message: MSG_DOC_STYLE_PARAM) do |corrector|
|
|
181
|
-
|
|
172
|
+
no_acceptable_style!
|
|
182
173
|
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
|
183
174
|
end
|
|
184
175
|
end
|
|
@@ -199,7 +190,7 @@ module RuboCop
|
|
|
199
190
|
# @rbs comment: Parser::Source::Comment
|
|
200
191
|
def add_offense_for_trailing_return(comment) #: void
|
|
201
192
|
add_offense(comment, message: MSG_TRAILING_RETURN) do |corrector|
|
|
202
|
-
|
|
193
|
+
no_acceptable_style!
|
|
203
194
|
removal_range = range_with_surrounding_space(range: comment.loc.expression, side: :left, newlines: false)
|
|
204
195
|
corrector.remove(removal_range)
|
|
205
196
|
end
|
|
@@ -209,7 +200,7 @@ module RuboCop
|
|
|
209
200
|
def add_offense_for_doc_style_return(annotation) #: void
|
|
210
201
|
range = annotation_range(annotation) or return
|
|
211
202
|
add_offense(range, message: MSG_DOC_STYLE_RETURN) do |corrector|
|
|
212
|
-
|
|
203
|
+
no_acceptable_style!
|
|
213
204
|
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
|
214
205
|
end
|
|
215
206
|
end
|