Class: RuboCop::Cop::Style::RbsInline::MethodCommentSpacing

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
RangeHelp, CommentParser, SourceCodeHelper
Defined in:
lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb,
sig/rubocop/cop/style/rbs_inline/method_comment_spacing.rbs

Overview

Checks that method-related @rbs annotations are placed immediately before method definitions.

Method-related annotations (@rbs param, @rbs return, @rbs &block, @rbs override, @rbs skip, @rbs %a{...}, # @rbs (...) -> Type, #: (...) -> Type) must be placed directly before the method definition they describe, without any blank lines in between. These annotations should not appear in standalone locations without an immediately following method definition.

Examples:

# bad
# @rbs param x: Integer
# @rbs return: String

def method(x)
end

# bad
#: (Integer) -> String

def method(x)
end

# bad
# @rbs param x: Integer
# @rbs return: String
puts "something"

# good
# @rbs param x: Integer
# @rbs return: String
def method(x)
end

# good
#: (Integer) -> String
def method(x)
end

# good
# @rbs x: Integer
private_class_method def self.method(x)
end

# good
# @rbs x: Integer
private def method(x)
end

Constant Summary collapse

MSG =

Returns:

  • (::String)
'Method-related `@rbs` annotation must be immediately before a method definition.'
MSG_WITH_BLANK_LINE =

Returns:

  • (::String)
'Remove blank line between method annotation and method definition.'
METHOD_DEFINITION_PATTERN =

Returns:

  • (Regexp)
/\A(?:(?:private|protected|public|private_class_method|module_function)\s+)?def\s/

Instance Attribute Summary collapse

Attributes included from CommentParser

#parsed_comments

Instance Method Summary collapse

Methods included from CommentParser

#find_doc_style_param_annotations, #find_doc_style_return_annotation, #find_last_consecutive_comment, #find_leading_annotation, #find_method_type_signature_comments, #find_trailing_comment, #overload_type_signatures?, #parse_comments

Methods included from SourceCodeHelper

#annotation_range, #blank_line?, #char_at, #character_offset, #comment_at, #comment_range, #line_range, #location_to_range, #source_code_at

Instance Attribute Details

#processed_commentsArray[RBS::Inline::AnnotationParser::ParsingResult] (readonly)

: Array

Returns:

  • (Array[RBS::Inline::AnnotationParser::ParsingResult])


69
70
71
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 69

def processed_comments
  @processed_comments
end

Instance Method Details

#check_blank_line_case(comment, blank_line_number) ⇒ void

This method returns an undefined value.

Parameters:

  • comment (Prism::Comment)
  • blank_line_number (Integer)


148
149
150
151
152
153
154
155
156
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 148

def check_blank_line_case(comment, blank_line_number) #: void
  line_after_blank = blank_line_number + 1
  if method_definition_line?(line_after_blank)
    register_blank_line_offense(blank_line_number)
  else
    range = comment_range(comment)
    add_offense(range, message: MSG)
  end
end

#check_method_annotation(comment) ⇒ void

This method returns an undefined value.

Parameters:

  • comment (RBS::Inline::AnnotationParser::ParsingResult)


101
102
103
104
105
106
107
108
109
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 101

def check_method_annotation(comment) #: void
  return unless method_related_annotation?(comment)

  processed_comments << comment

  last_comment = comment.comments.last or return
  next_line_number = last_comment.location.start_line + 1
  check_spacing_after_annotation(comment, next_line_number)
end

#check_method_comment_spacingvoid

This method returns an undefined value.

: void



79
80
81
82
83
84
85
86
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 79

def check_method_comment_spacing #: void
  parsed_comments.each do |comment|
    next if processed_comments.include?(comment)
    next if trailing_comment?(comment)

    check_method_annotation(comment)
  end
end

#check_spacing_after_annotation(comment, next_line_number) ⇒ void

This method returns an undefined value.

Parameters:

  • comment (RBS::Inline::AnnotationParser::ParsingResult)
  • next_line_number (Integer)


135
136
137
138
139
140
141
142
143
144
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 135

def check_spacing_after_annotation(comment, next_line_number) #: void
  last_comment = comment.comments.last or return

  if blank_line?(next_line_number)
    check_blank_line_case(last_comment, next_line_number)
  elsif !method_definition_line?(next_line_number) && !skip_only_annotation?(comment)
    range = comment_range(last_comment)
    add_offense(range, message: MSG)
  end
end

#method_definition_line?(line_number) ⇒ Boolean

Parameters:

  • line_number (Integer)

Returns:

  • (Boolean)


174
175
176
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 174

def method_definition_line?(line_number) #: bool
  METHOD_DEFINITION_PATTERN.match?(source_code_at(line_number).strip)
end

Parameters:

  • comment (RBS::Inline::AnnotationParser::ParsingResult)

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 112

def method_related_annotation?(comment) #: bool
  comment.each_annotation do |annotation|
    case annotation
    when RBS::Inline::AST::Annotations::VarType
      # VarType includes both parameter types and variable types (@ivar, @@cvar)
      # Only consider it method-related if it's a parameter annotation (name doesn't start with @)
      return true unless annotation.name.start_with?('@')
    when RBS::Inline::AST::Annotations::ReturnType,
         RBS::Inline::AST::Annotations::BlockType,
         RBS::Inline::AST::Annotations::Override,
         RBS::Inline::AST::Annotations::RBSAnnotation,
         RBS::Inline::AST::Annotations::Skip,
         RBS::Inline::AST::Annotations::Method,
         RBS::Inline::AST::Annotations::MethodTypeAssertion
      return true
    end
  end

  false
end

#on_new_investigationvoid

This method returns an undefined value.

: void



71
72
73
74
75
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 71

def on_new_investigation #: void
  @processed_comments = []
  parse_comments
  check_method_comment_spacing
end

#register_blank_line_offense(blank_line_number) ⇒ void

This method returns an undefined value.

Parameters:

  • blank_line_number (Integer)


159
160
161
162
163
164
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 159

def register_blank_line_offense(blank_line_number) #: void
  range = line_range(blank_line_number)
  add_offense(range, message: MSG_WITH_BLANK_LINE) do |corrector|
    corrector.remove(range_by_whole_lines(range, include_final_newline: true))
  end
end

#skip_only_annotation?(comment) ⇒ Boolean

Parameters:

  • comment (RBS::Inline::AnnotationParser::ParsingResult)

Returns:

  • (Boolean)


167
168
169
170
171
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 167

def skip_only_annotation?(comment) #: bool
  annotations = [] #: Array[RBS::Inline::AST::Annotations::t]
  comment.each_annotation { |a| annotations << a }
  annotations.any? && annotations.all?(RBS::Inline::AST::Annotations::Skip)
end

#trailing_comment?(comment) ⇒ Boolean

Check if this is a trailing comment after Ruby code on the same line

Parameters:

  • comment (RBS::Inline::AnnotationParser::ParsingResult)

Returns:

  • (Boolean)


90
91
92
93
94
95
96
97
98
# File 'lib/rubocop/cop/style/rbs_inline/method_comment_spacing.rb', line 90

def trailing_comment?(comment) #: bool
  return false unless comment.comments.size == 1

  first_comment = comment.comments.first or return false
  line_number = first_comment.location.start_line
  line = processed_source.lines[line_number - 1] or return false
  source = line[0, first_comment.location.start_column] || raise
  !source.strip.empty?
end