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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/hooks/pre-commit-check.sh +42 -2
  3. data/.claude/hooks/protect-sig-files.sh +45 -0
  4. data/.claude/hooks/self-review.sh +89 -0
  5. data/.claude/settings.json +16 -1
  6. data/.rubocop.yml +17 -12
  7. data/CHANGELOG.md +30 -0
  8. data/CLAUDE.md +11 -14
  9. data/README.md +51 -6
  10. data/Rakefile +12 -3
  11. data/config/default.yml +2 -4
  12. data/lib/rubocop/cop/rbs_inline_cops.rb +16 -7
  13. data/lib/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rb +2 -9
  14. data/lib/rubocop/cop/style/rbs_inline/data_define_with_block.rb +13 -7
  15. data/lib/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rb +3 -2
  16. data/lib/rubocop/cop/style/rbs_inline/invalid_comment.rb +2 -2
  17. data/lib/rubocop/cop/style/rbs_inline/invalid_types.rb +1 -0
  18. data/lib/rubocop/cop/style/rbs_inline/keyword_separator.rb +2 -2
  19. data/lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb +3 -2
  20. data/lib/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rb +2 -9
  21. data/lib/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rb +2 -16
  22. data/lib/rubocop/cop/style/rbs_inline/missing_type_annotation.rb +3 -16
  23. data/lib/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rb +16 -0
  24. data/lib/rubocop/cop/style/rbs_inline/mixin/ast_utils.rb +75 -0
  25. data/lib/rubocop/cop/style/rbs_inline/{comment_parser.rb → mixin/comment_parser.rb} +8 -0
  26. data/lib/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rb +22 -0
  27. data/lib/rubocop/cop/style/rbs_inline/{data_struct_helper.rb → mixin/data_struct_helper.rb} +14 -5
  28. data/lib/rubocop/cop/style/rbs_inline/mixin/file_filter.rb +72 -0
  29. data/lib/rubocop/cop/style/rbs_inline/mixin/mode_config.rb +39 -0
  30. data/lib/rubocop/cop/style/rbs_inline/{source_code_helper.rb → mixin/source_code_helper.rb} +3 -5
  31. data/lib/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rb +32 -0
  32. data/lib/rubocop/cop/style/rbs_inline/parameters_separator.rb +2 -2
  33. data/lib/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rb +2 -11
  34. data/lib/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rb +1 -0
  35. data/lib/rubocop/cop/style/rbs_inline/redundant_type_annotation.rb +6 -15
  36. data/lib/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rb +35 -23
  37. data/lib/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rb +2 -16
  38. data/lib/rubocop/cop/style/rbs_inline/struct_new_with_block.rb +13 -7
  39. data/lib/rubocop/cop/style/rbs_inline/unmatched_annotations.rb +31 -6
  40. data/lib/rubocop/cop/style/rbs_inline/untyped_instance_variable.rb +16 -6
  41. data/lib/rubocop/cop/style/rbs_inline/variable_comment_spacing.rb +3 -2
  42. data/lib/rubocop/rbs_inline/version.rb +1 -1
  43. data/rbs_collection.lock.yaml +11 -11
  44. data/sig/gems/rubocop/rubocop.rbs +14 -0
  45. data/sig/rubocop/cop/style/rbs_inline/data_class_comment_alignment.rbs +4 -5
  46. data/sig/rubocop/cop/style/rbs_inline/data_define_with_block.rbs +9 -2
  47. data/sig/rubocop/cop/style/rbs_inline/embedded_rbs_spacing.rbs +2 -0
  48. data/sig/rubocop/cop/style/rbs_inline/invalid_comment.rbs +4 -3
  49. data/sig/rubocop/cop/style/rbs_inline/invalid_types.rbs +2 -0
  50. data/sig/rubocop/cop/style/rbs_inline/keyword_separator.rbs +4 -3
  51. data/sig/rubocop/cop/style/rbs_inline/method_comment_spacing.rbs +2 -0
  52. data/sig/rubocop/cop/style/rbs_inline/missing_data_class_annotation.rbs +4 -5
  53. data/sig/rubocop/cop/style/rbs_inline/missing_struct_class_annotation.rbs +4 -10
  54. data/sig/rubocop/cop/style/rbs_inline/missing_type_annotation.rbs +4 -8
  55. data/sig/rubocop/cop/style/rbs_inline/mixin/annotation_keywords.rbs +16 -0
  56. data/sig/rubocop/cop/style/rbs_inline/{ast_utils.rbs → mixin/ast_utils.rbs} +14 -1
  57. data/sig/rubocop/cop/style/rbs_inline/{class_comment_alignment.rbs → mixin/class_comment_alignment.rbs} +1 -1
  58. data/sig/rubocop/cop/style/rbs_inline/{comment_parser.rbs → mixin/comment_parser.rbs} +5 -1
  59. data/sig/rubocop/cop/style/rbs_inline/mixin/data_class_matcher.rbs +18 -0
  60. data/sig/rubocop/cop/style/rbs_inline/{data_struct_helper.rbs → mixin/data_struct_helper.rbs} +6 -1
  61. data/sig/rubocop/cop/style/rbs_inline/mixin/file_filter.rbs +53 -0
  62. data/sig/rubocop/cop/style/rbs_inline/{missing_class_annotation.rbs → mixin/missing_class_annotation.rbs} +1 -1
  63. data/sig/rubocop/cop/style/rbs_inline/mixin/mode_config.rbs +27 -0
  64. data/sig/rubocop/cop/style/rbs_inline/{source_code_helper.rbs → mixin/source_code_helper.rbs} +1 -1
  65. data/sig/rubocop/cop/style/rbs_inline/mixin/struct_class_matcher.rbs +26 -0
  66. data/sig/rubocop/cop/style/rbs_inline/parameters_separator.rbs +4 -3
  67. data/sig/rubocop/cop/style/rbs_inline/redundant_annotation_with_skip.rbs +4 -4
  68. data/sig/rubocop/cop/style/rbs_inline/redundant_instance_variable_annotation.rbs +2 -0
  69. data/sig/rubocop/cop/style/rbs_inline/redundant_type_annotation.rbs +4 -4
  70. data/sig/rubocop/cop/style/rbs_inline/require_rbs_inline_comment.rbs +22 -5
  71. data/sig/rubocop/cop/style/rbs_inline/struct_class_comment_alignment.rbs +4 -10
  72. data/sig/rubocop/cop/style/rbs_inline/struct_new_with_block.rbs +9 -2
  73. data/sig/rubocop/cop/style/rbs_inline/unmatched_annotations.rbs +13 -0
  74. data/sig/rubocop/cop/style/rbs_inline/untyped_instance_variable.rbs +10 -0
  75. data/sig/rubocop/cop/style/rbs_inline/variable_comment_spacing.rbs +2 -0
  76. metadata +28 -18
  77. data/lib/rubocop/cop/style/rbs_inline/ast_utils.rb +0 -46
  78. data/sig/rubocop/cop/style/rbs_inline/redundant_argument_type.rbs +0 -85
  79. data/sig/rubocop/cop/style/rbs_inline/redundant_return_type.rbs +0 -109
  80. /data/.claude/hooks/{setup.sh → claude-code-web-session-start.sh} +0 -0
  81. /data/lib/rubocop/cop/style/rbs_inline/{class_comment_alignment.rb → mixin/class_comment_alignment.rb} +0 -0
  82. /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*.*'
@@ -21,6 +21,7 @@ module RuboCop
21
21
  # def method(arg); end
22
22
  #
23
23
  class InvalidTypes < Base
24
+ prepend FileFilter
24
25
  include CommentParser
25
26
  include RangeHelp
26
27
  include SourceCodeHelper
@@ -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` are always excluded from inspection.
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.arguments.map do |arg|
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
- last_index = node.arguments.size - 1
74
- args = node.arguments.each_with_index.map { |a, i| i < last_index ? "#{a.source}," : a.source.to_s }
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
- padding = " " * (longest.length - source!(arg).length - comma.length + 2)
88
- attr_argument?(arg) ? "#{prefix}#{padding}#: untyped" : prefix
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.dup.force_encoding("ASCII")
16
- text = source[...byte_offset] or raise
17
- text.force_encoding(processed_source.buffer.source.encoding).size
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
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # attr_reader :foo
29
29
  #
30
30
  class RedundantInstanceVariableAnnotation < Base
31
+ prepend FileFilter
31
32
  extend AutoCorrector
32
33
  include ASTUtils
33
34
  include CommentParser
@@ -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
- unexpected_style_detected(:method_type_signature)
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
- unexpected_style_detected(:doc_style)
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
- unexpected_style_detected(:return_type_annotation)
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
- unexpected_style_detected(:doc_style)
203
+ no_acceptable_style!
213
204
  corrector.remove(range_by_whole_lines(range, include_final_newline: true))
214
205
  end
215
206
  end