rubocop 1.60.2 → 1.63.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/assets/output.css.erb +159 -0
  4. data/assets/output.html.erb +1 -160
  5. data/config/default.yml +64 -15
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  7. data/lib/rubocop/cli/command/lsp.rb +2 -2
  8. data/lib/rubocop/cli.rb +6 -1
  9. data/lib/rubocop/config.rb +37 -10
  10. data/lib/rubocop/config_finder.rb +12 -2
  11. data/lib/rubocop/config_obsoletion.rb +1 -1
  12. data/lib/rubocop/config_validator.rb +14 -5
  13. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  14. data/lib/rubocop/cop/base.rb +52 -6
  15. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  16. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  17. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  18. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -0
  19. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  20. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +122 -28
  21. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  22. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  23. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  24. data/lib/rubocop/cop/layout/end_alignment.rb +3 -1
  25. data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -3
  26. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  27. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  28. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -4
  29. data/lib/rubocop/cop/lint/debugger.rb +27 -2
  30. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  31. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
  32. data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -0
  33. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  34. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  35. data/lib/rubocop/cop/lint/syntax.rb +1 -1
  36. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
  37. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  38. data/lib/rubocop/cop/lint/void.rb +6 -1
  39. data/lib/rubocop/cop/mixin/code_length.rb +12 -1
  40. data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
  41. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  42. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
  43. data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
  44. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  45. data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
  46. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  47. data/lib/rubocop/cop/registry.rb +1 -1
  48. data/lib/rubocop/cop/style/alias.rb +1 -0
  49. data/lib/rubocop/cop/style/arguments_forwarding.rb +29 -8
  50. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  51. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  52. data/lib/rubocop/cop/style/collection_compact.rb +3 -3
  53. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  54. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -5
  55. data/lib/rubocop/cop/style/copyright.rb +16 -11
  56. data/lib/rubocop/cop/style/eval_with_location.rb +2 -0
  57. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  58. data/lib/rubocop/cop/style/for.rb +2 -0
  59. data/lib/rubocop/cop/style/format_string.rb +9 -9
  60. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
  61. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  62. data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
  63. data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -5
  64. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +5 -8
  65. data/lib/rubocop/cop/style/map_into_array.rb +175 -0
  66. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  67. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  68. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
  69. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  70. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -0
  71. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  72. data/lib/rubocop/cop/style/object_then.rb +5 -3
  73. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
  74. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  75. data/lib/rubocop/cop/style/redundant_argument.rb +25 -2
  76. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  77. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
  78. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  79. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  80. data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -0
  81. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_return.rb +6 -0
  83. data/lib/rubocop/cop/style/sample.rb +1 -3
  84. data/lib/rubocop/cop/team.rb +3 -0
  85. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  86. data/lib/rubocop/cops_documentation_generator.rb +4 -2
  87. data/lib/rubocop/directive_comment.rb +10 -8
  88. data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
  89. data/lib/rubocop/formatter/html_formatter.rb +30 -10
  90. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  91. data/lib/rubocop/formatter/tap_formatter.rb +3 -7
  92. data/lib/rubocop/lockfile.rb +34 -4
  93. data/lib/rubocop/lsp/logger.rb +1 -1
  94. data/lib/rubocop/lsp/routes.rb +1 -1
  95. data/lib/rubocop/lsp/runtime.rb +1 -1
  96. data/lib/rubocop/lsp/server.rb +5 -2
  97. data/lib/rubocop/lsp/severity.rb +1 -1
  98. data/lib/rubocop/lsp.rb +29 -0
  99. data/lib/rubocop/magic_comment.rb +1 -1
  100. data/lib/rubocop/options.rb +11 -0
  101. data/lib/rubocop/path_util.rb +6 -2
  102. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  103. data/lib/rubocop/rspec/expect_offense.rb +16 -8
  104. data/lib/rubocop/rspec/shared_contexts.rb +49 -18
  105. data/lib/rubocop/rspec/support.rb +2 -1
  106. data/lib/rubocop/runner.rb +12 -2
  107. data/lib/rubocop/target_finder.rb +84 -78
  108. data/lib/rubocop/target_ruby.rb +82 -80
  109. data/lib/rubocop/version.rb +19 -4
  110. data/lib/rubocop.rb +1 -0
  111. metadata +10 -6
@@ -27,9 +27,9 @@ module RuboCop
27
27
  MSG = 'Add an empty line after magic comments.'
28
28
 
29
29
  def on_new_investigation
30
- return unless processed_source.ast &&
31
- (last_magic_comment = last_magic_comment(processed_source))
32
- return if processed_source[last_magic_comment.loc.line].strip.empty?
30
+ return unless (last_magic_comment = last_magic_comment(processed_source))
31
+ return unless (next_line = processed_source[last_magic_comment.loc.line])
32
+ return if next_line.strip.empty?
33
33
 
34
34
  offending_range = offending_range(last_magic_comment)
35
35
 
@@ -46,18 +46,25 @@ module RuboCop
46
46
 
47
47
  # Find the last magic comment in the source file.
48
48
  #
49
- # Take all comments that precede the first line of code, select the
49
+ # Take all comments that precede the first line of code (or just take
50
+ # them all in the case when there is no code), select the
50
51
  # magic comments, and return the last magic comment in the file.
51
52
  #
52
53
  # @return [Parser::Source::Comment] if magic comments exist before code
53
54
  # @return [nil] otherwise
54
55
  def last_magic_comment(source)
55
- source
56
- .comments
57
- .take_while { |comment| comment.loc.line < source.ast.loc.line }
56
+ comments_before_code(source)
58
57
  .reverse
59
58
  .find { |comment| MagicComment.parse(comment.text).any? }
60
59
  end
60
+
61
+ def comments_before_code(source)
62
+ if source.ast
63
+ source.comments.take_while { |comment| comment.loc.line < source.ast.loc.line }
64
+ else
65
+ source.comments
66
+ end
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -20,7 +20,9 @@ module RuboCop
20
20
  # This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
21
21
  # by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with
22
22
  # `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends
23
- # to align with the start of the line. These style can be configured by each cop.
23
+ # to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with
24
+ # `EnforcedStyleAlignWith: start_of_line` by default.
25
+ # These style can be configured by each cop.
24
26
  #
25
27
  # @example EnforcedStyleAlignWith: keyword (default)
26
28
  # # bad
@@ -84,12 +84,20 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def offense?(node)
87
- node.multiline? && !too_long?(node) && suitable_as_single_line?(node) &&
88
- !index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
87
+ return false if !node.multiline? || too_long?(node) || !suitable_as_single_line?(node)
88
+ return require_backslash?(node) if node.and_type? || node.or_type?
89
+
90
+ !index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
91
+ end
92
+
93
+ def require_backslash?(node)
94
+ processed_source.lines[node.loc.operator.line - 1].end_with?('\\')
89
95
  end
90
96
 
91
97
  def index_access_call_chained?(node)
92
- node.send_type? && node.method?(:[]) && node.children.first.method?(:[])
98
+ return false unless node.send_type? && node.method?(:[])
99
+
100
+ node.children.first.send_type? && node.children.first.method?(:[])
93
101
  end
94
102
 
95
103
  def configured_to_not_be_inspected?(node)
@@ -81,19 +81,28 @@ module RuboCop
81
81
  private
82
82
 
83
83
  def check_empty(left_brace, space_plus_brace, used_style)
84
- return if style_for_empty_braces == used_style
85
-
86
- config_to_allow_offenses['EnforcedStyleForEmptyBraces'] = used_style.to_s
84
+ if style_for_empty_braces == used_style
85
+ handle_different_styles_for_empty_braces(used_style)
86
+ return
87
+ elsif !config_to_allow_offenses.key?('Enabled')
88
+ config_to_allow_offenses['EnforcedStyleForEmptyBraces'] = used_style.to_s
89
+ end
87
90
 
88
91
  if style_for_empty_braces == :space
89
- add_offense(left_brace, message: MISSING_MSG) do |corrector|
90
- autocorrect(corrector, left_brace)
91
- end
92
+ range = left_brace
93
+ msg = MISSING_MSG
92
94
  else
93
- space = range_between(space_plus_brace.begin_pos, left_brace.begin_pos)
94
- add_offense(space, message: DETECTED_MSG) do |corrector|
95
- autocorrect(corrector, space)
96
- end
95
+ range = range_between(space_plus_brace.begin_pos, left_brace.begin_pos)
96
+ msg = DETECTED_MSG
97
+ end
98
+ add_offense(range, message: msg) { |corrector| autocorrect(corrector, range) }
99
+ end
100
+
101
+ def handle_different_styles_for_empty_braces(used_style)
102
+ if config_to_allow_offenses['EnforcedStyleForEmptyBraces'] &&
103
+ config_to_allow_offenses['EnforcedStyleForEmptyBraces'].to_sym != used_style
104
+ config_to_allow_offenses.clear
105
+ config_to_allow_offenses['Enabled'] = false
97
106
  end
98
107
  end
99
108
 
@@ -116,7 +116,7 @@ module RuboCop
116
116
 
117
117
  def incorrect_style_detected(token1, token2,
118
118
  expect_space, is_empty_braces)
119
- brace = (token1.text == '{' ? token1 : token2).pos
119
+ brace = (token1.left_brace? ? token1 : token2).pos
120
120
  range = expect_space ? brace : space_range(brace)
121
121
  detected_style = expect_space ? 'no_space' : 'space'
122
122
 
@@ -50,7 +50,7 @@ module RuboCop
50
50
  MSG_WITHOUT_SAFE_ASSIGNMENT_ALLOWED =
51
51
  'Use `==` if you meant to do a comparison or move the assignment ' \
52
52
  'up out of the condition.'
53
- ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send].freeze
53
+ ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send, :csend].freeze
54
54
 
55
55
  def on_if(node)
56
56
  return if node.condition.block_type?
@@ -88,9 +88,7 @@ module RuboCop
88
88
  end
89
89
 
90
90
  def skip_children?(asgn_node)
91
- (asgn_node.send_type? && !asgn_node.assignment_method?) ||
92
- empty_condition?(asgn_node) ||
93
- (safe_assignment_allowed? && safe_assignment?(asgn_node))
91
+ empty_condition?(asgn_node) || (safe_assignment_allowed? && safe_assignment?(asgn_node))
94
92
  end
95
93
 
96
94
  def traverse_node(node, &block)
@@ -29,6 +29,11 @@ module RuboCop
29
29
  # MyDebugger.debug_this
30
30
  # ----
31
31
  #
32
+ # Some gems also ship files that will start a debugging session when required,
33
+ # for example `require 'debug/start'` from `ruby/debug`. These requires can
34
+ # be configured through `DebuggerRequires`. It has the same structure as
35
+ # `DebuggerMethods`, which you can read about above.
36
+ #
32
37
  # @example
33
38
  #
34
39
  # # bad (ok during development)
@@ -64,14 +69,20 @@ module RuboCop
64
69
  # def some_method
65
70
  # my_debugger
66
71
  # end
72
+ #
73
+ # @example DebuggerRequires: [my_debugger/start]
74
+ #
75
+ # # bad (ok during development)
76
+ #
77
+ # require 'my_debugger/start'
67
78
  class Debugger < Base
68
79
  MSG = 'Remove debugger entry point `%<source>s`.'
69
80
  BLOCK_TYPES = %i[block numblock kwbegin].freeze
70
81
 
71
82
  def on_send(node)
72
- return if !debugger_method?(node) || assumed_usage_context?(node)
83
+ return if assumed_usage_context?(node)
73
84
 
74
- add_offense(node)
85
+ add_offense(node) if debugger_method?(node) || debugger_require?(node)
75
86
  end
76
87
 
77
88
  private
@@ -87,12 +98,26 @@ module RuboCop
87
98
  end
88
99
  end
89
100
 
101
+ def debugger_requires
102
+ @debugger_requires ||= begin
103
+ config = cop_config.fetch('DebuggerRequires', [])
104
+ config.is_a?(Array) ? config : config.values.flatten
105
+ end
106
+ end
107
+
90
108
  def debugger_method?(send_node)
91
109
  return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
92
110
 
93
111
  debugger_methods.include?(chained_method_name(send_node))
94
112
  end
95
113
 
114
+ def debugger_require?(send_node)
115
+ return false unless send_node.method?(:require) && send_node.arguments.one?
116
+ return false unless (argument = send_node.first_argument).str_type?
117
+
118
+ debugger_requires.include?(argument.value)
119
+ end
120
+
96
121
  def assumed_usage_context?(node)
97
122
  # Basically, debugger methods are not used as a method argument without arguments.
98
123
  return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
@@ -104,7 +104,7 @@ module RuboCop
104
104
  def correct_other_branches(corrector, node)
105
105
  return unless require_other_branches_correction?(node)
106
106
 
107
- if node.else_branch&.if_type?
107
+ if node.else_branch&.if_type? && !node.else_branch.modifier_form?
108
108
  # Replace an orphaned `elsif` with `if`
109
109
  corrector.replace(node.else_branch.loc.keyword, 'if')
110
110
  else
@@ -5,7 +5,8 @@ module RuboCop
5
5
  module Lint
6
6
  # Checks for redundant safe navigation calls.
7
7
  # Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
8
- # and an offense is not detected when the receiver is a snake case constant.
8
+ # and an offense is not detected when the receiver is a constant. The detection also applies
9
+ # to literal receivers, except for `nil`.
9
10
  #
10
11
  # For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
11
12
  # and `equal?` methods are checked by default.
@@ -76,10 +77,9 @@ module RuboCop
76
77
  #
77
78
  class RedundantSafeNavigation < Base
78
79
  include AllowedMethods
79
- include RangeHelp
80
80
  extend AutoCorrector
81
81
 
82
- MSG = 'Redundant safe navigation detected.'
82
+ MSG = 'Redundant safe navigation detected, use `.` instead.'
83
83
  MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
84
84
 
85
85
  NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
@@ -105,24 +105,23 @@ module RuboCop
105
105
 
106
106
  # rubocop:disable Metrics/AbcSize
107
107
  def on_csend(node)
108
- unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
108
+ unless assume_receiver_instance_exists?(node.receiver)
109
109
  return unless check?(node) && allowed_method?(node.method_name)
110
110
  return if respond_to_nil_specific_method?(node)
111
111
  end
112
112
 
113
- range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
114
- add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
113
+ range = node.loc.dot
114
+ add_offense(range) { |corrector| corrector.replace(range, '.') }
115
115
  end
116
116
 
117
117
  def on_or(node)
118
118
  conversion_with_default?(node) do |send_node|
119
- range = range_between(send_node.loc.dot.begin_pos, node.source_range.end_pos)
119
+ range = send_node.loc.dot.begin.join(node.source_range.end)
120
120
 
121
121
  add_offense(range, message: MSG_LITERAL) do |corrector|
122
122
  corrector.replace(send_node.loc.dot, '.')
123
123
 
124
- range_with_default = range_between(node.lhs.source_range.end.begin_pos,
125
- node.source_range.end.end_pos)
124
+ range_with_default = node.lhs.source_range.end.begin.join(node.source_range.end)
126
125
  corrector.remove(range_with_default)
127
126
  end
128
127
  end
@@ -131,6 +130,12 @@ module RuboCop
131
130
 
132
131
  private
133
132
 
133
+ def assume_receiver_instance_exists?(receiver)
134
+ return true if receiver.const_type? && !receiver.source.match?(SNAKE_CASE)
135
+
136
+ receiver.literal? && !receiver.nil_type?
137
+ end
138
+
134
139
  def check?(node)
135
140
  parent = node.parent
136
141
  return false unless parent
@@ -33,7 +33,10 @@ module RuboCop
33
33
  MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
34
34
  MSG_WITH_INDEX = 'Remove redundant `with_index`.'
35
35
 
36
+ # rubocop:disable Metrics/AbcSize
36
37
  def on_block(node)
38
+ return unless node.receiver
39
+ return if node.method?(:with_index) && !node.receiver.receiver
37
40
  return unless (send = redundant_with_index?(node))
38
41
 
39
42
  range = with_index_range(send)
@@ -47,6 +50,7 @@ module RuboCop
47
50
  end
48
51
  end
49
52
  end
53
+ # rubocop:enable Metrics/AbcSize
50
54
 
51
55
  alias on_numblock on_block
52
56
 
@@ -59,9 +59,7 @@ module RuboCop
59
59
 
60
60
  def autocorrect(corrector, node)
61
61
  rescued, _, _body = *node
62
- range = Parser::Source::Range.new(node.source_range.source_buffer,
63
- node.loc.keyword.end_pos,
64
- rescued.source_range.end_pos)
62
+ range = node.loc.keyword.end.join(rescued.source_range.end)
65
63
 
66
64
  corrector.replace(range, correction(*rescued))
67
65
  end
@@ -46,14 +46,14 @@ module RuboCop
46
46
  message = format_message_from(processed_source)
47
47
 
48
48
  add_offense(comment, message: message) do
49
- autocorrect(comment) if autocorrect_requested?
49
+ autocorrect if autocorrect_requested?
50
50
  end
51
51
  end
52
52
 
53
53
  private
54
54
 
55
- def autocorrect(comment)
56
- FileUtils.chmod('+x', comment.source_range.source_buffer.name)
55
+ def autocorrect
56
+ FileUtils.chmod('+x', processed_source.file_path)
57
57
  end
58
58
 
59
59
  def executable?(processed_source)
@@ -17,7 +17,7 @@ module RuboCop
17
17
  private
18
18
 
19
19
  def add_offense_from_diagnostic(diagnostic, ruby_version)
20
- message = if lsp_mode?
20
+ message = if LSP.enabled?
21
21
  diagnostic.message
22
22
  else
23
23
  "#{diagnostic.message}\n(Using Ruby #{ruby_version} parser; " \
@@ -51,8 +51,13 @@ module RuboCop
51
51
  enum_conversion_call?(node) do |method_node, arguments|
52
52
  next if method_node.call_type? &&
53
53
  !method_node.method?(:__method__) && !method_node.method?(:__callee__)
54
- next if method_name?(method_node, def_node.method_name) &&
55
- arguments_match?(arguments, def_node)
54
+
55
+ valid = if method_name?(method_node, def_node.method_name)
56
+ arguments_match?(arguments, def_node)
57
+ else
58
+ def_node.arguments.empty?
59
+ end
60
+ return if valid
56
61
 
57
62
  add_offense(node)
58
63
  end
@@ -64,7 +64,7 @@ module RuboCop
64
64
  remove_node(corrector, node)
65
65
  elsif !proc_name.empty?
66
66
  autocorrect_block_pass(corrector, node, proc_name)
67
- else
67
+ elsif node.block_type?
68
68
  autocorrect_block(corrector, node)
69
69
  end
70
70
  end
@@ -100,7 +100,12 @@ module RuboCop
100
100
  expressions = *node
101
101
  expressions.pop unless in_void_context?(node)
102
102
  expressions.each do |expr|
103
- check_void_op(expr)
103
+ check_void_op(expr) do
104
+ block_node = node.each_ancestor(:block).first
105
+
106
+ block_node&.method?(:each)
107
+ end
108
+
104
109
  check_expression(expr)
105
110
  end
106
111
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  length = calculator.calculate
37
37
  return if length <= max_length
38
38
 
39
- location = node.casgn_type? ? node.loc.name : node.source_range
39
+ location = location(node)
40
40
 
41
41
  add_offense(location, message: message(length, max_length)) { self.max = length }
42
42
  end
@@ -54,6 +54,17 @@ module RuboCop
54
54
  foldable_types: count_as_one
55
55
  )
56
56
  end
57
+
58
+ def location(node)
59
+ return node.loc.name if node.casgn_type?
60
+
61
+ if LSP.enabled?
62
+ end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
63
+ node.source_range.begin.join(end_range)
64
+ else
65
+ node.source_range
66
+ end
67
+ end
57
68
  end
58
69
  end
59
70
  end
@@ -49,13 +49,13 @@ module RuboCop
49
49
 
50
50
  return unless complexity > max
51
51
 
52
- msg = format(self.class::MSG,
53
- method: method_name,
54
- complexity: complexity,
55
- abc_vector: abc_vector,
56
- max: max)
52
+ msg = format(
53
+ self.class::MSG,
54
+ method: method_name, complexity: complexity, abc_vector: abc_vector, max: max
55
+ )
56
+ location = location(node)
57
57
 
58
- add_offense(node, message: msg) { self.max = complexity.ceil }
58
+ add_offense(location, message: msg) { self.max = complexity.ceil }
59
59
  end
60
60
 
61
61
  def complexity(body)
@@ -69,6 +69,15 @@ module RuboCop
69
69
  end
70
70
  score
71
71
  end
72
+
73
+ def location(node)
74
+ if LSP.enabled?
75
+ end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
76
+ node.source_range.begin.join(end_range)
77
+ else
78
+ node.source_range
79
+ end
80
+ end
72
81
  end
73
82
  end
74
83
  end
@@ -189,7 +189,7 @@ module RuboCop
189
189
  case node.type
190
190
  when :casgn then _scope, _lhs, rhs = *node
191
191
  when :op_asgn then _lhs, _op, rhs = *node
192
- when :send then rhs = node.last_argument
192
+ when :send, :csend then rhs = node.last_argument
193
193
  else _lhs, rhs = *node
194
194
  end
195
195
  rhs
@@ -14,7 +14,7 @@ module RuboCop
14
14
  def_node_matcher :empty_condition?, '(begin)'
15
15
 
16
16
  # @!method setter_method?(node)
17
- def_node_matcher :setter_method?, '[(send ...) setter_method?]'
17
+ def_node_matcher :setter_method?, '[(call ...) setter_method?]'
18
18
 
19
19
  # @!method safe_assignment?(node)
20
20
  def_node_matcher :safe_assignment?, '(begin {equals_asgn? #setter_method?})'
@@ -51,29 +51,25 @@ module RuboCop
51
51
  [Lint::AmbiguousOperator, Style::ArgumentsForwarding]
52
52
  end
53
53
 
54
- # rubocop:disable Metrics/CyclomaticComplexity
55
54
  def on_def(node)
56
55
  return if node.arguments.empty?
57
56
 
58
57
  last_argument = node.last_argument
59
58
  return if expected_block_forwarding_style?(node, last_argument)
60
59
 
61
- invalid_syntax = false
62
- node.each_descendant(:block_pass) do |block_pass_node|
63
- next if block_pass_node.children.first&.sym_type? ||
64
- last_argument.source != block_pass_node.source
60
+ forwarded_args = node.each_descendant(:block_pass).with_object([]) do |block_pass, result|
61
+ return nil if invalidates_syntax?(block_pass)
62
+ next unless block_argument_name_matched?(block_pass, last_argument)
65
63
 
66
- if block_pass_node.each_ancestor(:block, :numblock).any?
67
- invalid_syntax = true
68
- next
69
- end
64
+ result << block_pass
65
+ end
70
66
 
71
- register_offense(block_pass_node, node)
67
+ forwarded_args.each do |forwarded_arg|
68
+ register_offense(forwarded_arg, node)
72
69
  end
73
70
 
74
- register_offense(last_argument, node) unless invalid_syntax
71
+ register_offense(last_argument, node)
75
72
  end
76
- # rubocop:enable Metrics/CyclomaticComplexity
77
73
  alias on_defs on_def
78
74
 
79
75
  private
@@ -88,6 +84,29 @@ module RuboCop
88
84
  end
89
85
  end
90
86
 
87
+ def block_argument_name_matched?(block_pass_node, last_argument)
88
+ return false if block_pass_node.children.first&.sym_type?
89
+
90
+ last_argument.source == block_pass_node.source
91
+ end
92
+
93
+ # Prevents the following syntax error:
94
+ #
95
+ # # foo.rb
96
+ # def foo(&)
97
+ # block_method do
98
+ # bar(&)
99
+ # end
100
+ # end
101
+ #
102
+ # $ ruby -vc foo.rb
103
+ # ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin22]
104
+ # foo.rb: foo.rb:4: anonymous block parameter is also used within block (SyntaxError)
105
+ #
106
+ def invalidates_syntax?(block_pass_node)
107
+ block_pass_node.each_ancestor(:block, :numblock).any?
108
+ end
109
+
91
110
  def use_kwarg_in_method_definition?(node)
92
111
  node.arguments.each_descendant(:kwarg, :kwoptarg).any?
93
112
  end
@@ -57,7 +57,7 @@ module RuboCop
57
57
  file_path = processed_source.file_path
58
58
  return if config.file_to_exclude?(file_path) || config.allowed_camel_case_file?(file_path)
59
59
 
60
- for_bad_filename(file_path) { |range, msg| add_offense(range, message: msg) }
60
+ for_bad_filename(file_path)
61
61
  end
62
62
 
63
63
  private
@@ -71,7 +71,7 @@ module RuboCop
71
71
  msg = other_message(basename) unless bad_filename_allowed?
72
72
  end
73
73
 
74
- yield source_range(processed_source.buffer, 1, 0), msg if msg
74
+ add_global_offense(msg) if msg
75
75
  end
76
76
 
77
77
  def perform_class_and_module_naming_checks(file_path, basename)
@@ -207,8 +207,7 @@ module RuboCop
207
207
  message = create_multiple_word_message_for_file(words)
208
208
  end
209
209
 
210
- range = source_range(processed_source.buffer, 1, 0)
211
- add_offense(range, message: message)
210
+ add_global_offense(message)
212
211
  end
213
212
 
214
213
  def create_single_word_message_for_file(word)
@@ -99,7 +99,7 @@ module RuboCop
99
99
  !(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
100
100
  method_name.match?(/^#{prefix}[^0-9]/)) ||
101
101
  method_name == expected_name(method_name, prefix) ||
102
- method_name.end_with?('=') || # rubocop:todo InternalAffairs/MethodNameEndWith
102
+ method_name.end_with?('=') ||
103
103
  allowed_method?(method_name)
104
104
  end
105
105
 
@@ -109,7 +109,7 @@ module RuboCop
109
109
  else
110
110
  method_name.dup
111
111
  end
112
- new_name << '?' unless method_name.end_with?('?') # rubocop:todo InternalAffairs/MethodNameEndWith
112
+ new_name << '?' unless method_name.end_with?('?')
113
113
  new_name
114
114
  end
115
115
 
@@ -300,7 +300,7 @@ module RuboCop
300
300
  unless given_badge.match?(real_badge)
301
301
  path = PathUtil.smart_path(source_path)
302
302
  warn "#{path}: #{given_badge} has the wrong namespace - " \
303
- "should be #{real_badge.department}"
303
+ "replace it with #{given_badge.with_department(real_badge.department)}"
304
304
  end
305
305
 
306
306
  real_badge.to_s
@@ -41,6 +41,7 @@ module RuboCop
41
41
  def on_send(node)
42
42
  return unless node.command?(:alias_method)
43
43
  return unless style == :prefer_alias && alias_keyword_possible?(node)
44
+ return unless node.arguments.count == 2
44
45
 
45
46
  msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
46
47
  add_offense(node.loc.selector, message: msg) do |corrector|