rubocop 1.75.8 → 1.82.1

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -16
  3. data/config/default.yml +142 -33
  4. data/config/obsoletion.yml +10 -3
  5. data/exe/rubocop +1 -8
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  7. data/lib/rubocop/cli.rb +20 -4
  8. data/lib/rubocop/comment_config.rb +62 -17
  9. data/lib/rubocop/config_loader.rb +6 -40
  10. data/lib/rubocop/config_loader_resolver.rb +7 -6
  11. data/lib/rubocop/config_store.rb +5 -0
  12. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  13. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
  14. data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -7
  15. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  16. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  17. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  18. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
  19. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -3
  20. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  21. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  22. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  24. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  25. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  26. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
  27. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  28. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  30. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  31. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  32. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  33. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  34. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  35. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  36. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
  37. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  38. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  39. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  40. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
  41. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  42. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
  43. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  44. data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
  45. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  46. data/lib/rubocop/cop/layout/line_length.rb +43 -10
  47. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  48. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
  49. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  50. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  51. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  52. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  53. data/lib/rubocop/cop/layout/space_around_keyword.rb +7 -2
  54. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  55. data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
  56. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
  57. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  58. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  59. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  60. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  61. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  62. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  63. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  64. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  65. data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
  66. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  67. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  68. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  69. data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
  70. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  71. data/lib/rubocop/cop/lint/literal_as_condition.rb +38 -28
  72. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  73. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  74. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  75. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  76. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  77. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  78. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  79. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  80. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  81. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
  82. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  83. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  84. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  85. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  86. data/lib/rubocop/cop/lint/self_assignment.rb +39 -5
  87. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  88. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  89. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  90. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  91. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  92. data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
  93. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  94. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  95. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  96. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  97. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  98. data/lib/rubocop/cop/lint/void.rb +7 -0
  99. data/lib/rubocop/cop/message_annotator.rb +1 -1
  100. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  101. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  102. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  103. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
  104. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  105. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  106. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  107. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  108. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  109. data/lib/rubocop/cop/mixin/line_length_help.rb +45 -10
  110. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  111. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  112. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  113. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  114. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  115. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  116. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  117. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  118. data/lib/rubocop/cop/naming/method_name.rb +129 -13
  119. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  120. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  121. data/lib/rubocop/cop/security/eval.rb +2 -1
  122. data/lib/rubocop/cop/security/json_load.rb +33 -11
  123. data/lib/rubocop/cop/security/open.rb +1 -0
  124. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  125. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  126. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  127. data/lib/rubocop/cop/style/array_intersect.rb +99 -35
  128. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  129. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  130. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  131. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  132. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  133. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  134. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  135. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  136. data/lib/rubocop/cop/style/conditional_assignment.rb +12 -16
  137. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  138. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  139. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  140. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  141. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  142. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  143. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  144. data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
  145. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  146. data/lib/rubocop/cop/style/float_division.rb +15 -1
  147. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  148. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  149. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  150. data/lib/rubocop/cop/style/if_unless_modifier.rb +16 -9
  151. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  152. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  153. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  154. data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
  155. data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
  156. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  157. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
  158. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +33 -4
  160. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  161. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  162. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  163. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  164. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  165. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  166. data/lib/rubocop/cop/style/parallel_assignment.rb +34 -22
  167. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  168. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  169. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  170. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  171. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  172. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  173. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  174. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  175. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  176. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  177. data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
  178. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  179. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  180. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  181. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  182. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  183. data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
  184. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  185. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  186. data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
  187. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  188. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  189. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  190. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  191. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  192. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  193. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  194. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  195. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  196. data/lib/rubocop/cop/util.rb +2 -3
  197. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  198. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  199. data/lib/rubocop/cop/variable_force.rb +25 -8
  200. data/lib/rubocop/cops_documentation_generator.rb +5 -4
  201. data/lib/rubocop/directive_comment.rb +46 -3
  202. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
  203. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  204. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  205. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  206. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  207. data/lib/rubocop/lsp/diagnostic.rb +14 -18
  208. data/lib/rubocop/lsp/routes.rb +35 -6
  209. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  210. data/lib/rubocop/magic_comment.rb +20 -0
  211. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  212. data/lib/rubocop/rake_task.rb +1 -1
  213. data/lib/rubocop/remote_config.rb +7 -8
  214. data/lib/rubocop/result_cache.rb +51 -38
  215. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  216. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  217. data/lib/rubocop/rspec/support.rb +1 -1
  218. data/lib/rubocop/runner.rb +10 -4
  219. data/lib/rubocop/server/cache.rb +4 -2
  220. data/lib/rubocop/server/client_command/base.rb +10 -0
  221. data/lib/rubocop/server/client_command/exec.rb +2 -1
  222. data/lib/rubocop/server/client_command/start.rb +11 -1
  223. data/lib/rubocop/target_finder.rb +9 -9
  224. data/lib/rubocop/target_ruby.rb +11 -2
  225. data/lib/rubocop/version.rb +1 -1
  226. data/lib/rubocop.rb +13 -1
  227. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  228. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  229. metadata +20 -8
@@ -83,7 +83,7 @@ module RuboCop
83
83
  execute_runner
84
84
  @options.delete(:only)
85
85
  @config_store = ConfigStore.new
86
- @config_store.options_config = @options[:config] if @options[:config]
86
+ @config_store.apply_options!(@options)
87
87
  # Save the todo configuration of the LineLength cop.
88
88
  File.read(AUTO_GENERATED_FILE).lines.drop_while { |line| line.start_with?('#') }.join
89
89
  end
@@ -99,7 +99,7 @@ module RuboCop
99
99
 
100
100
  def reset_config_and_auto_gen_file
101
101
  @config_store = ConfigStore.new
102
- @config_store.options_config = @options[:config] if @options[:config]
102
+ @config_store.apply_options!(@options)
103
103
  File.open(AUTO_GENERATED_FILE, 'w') {} # create or truncate if exists
104
104
  add_inheritance_from_auto_generated_file(@options[:config])
105
105
  end
data/lib/rubocop/cli.rb CHANGED
@@ -12,7 +12,7 @@ module RuboCop
12
12
  STATUS_INTERRUPTED = Signal.list['INT'] + 128
13
13
  DEFAULT_PARALLEL_OPTIONS = %i[
14
14
  color config debug display_style_guide display_time display_only_fail_level_offenses
15
- display_only_failed editor_mode except extra_details fail_level fix_layout format
15
+ display_only_failed editor_mode except extra_details fail_level fix_layout format formatters
16
16
  ignore_disable_comments lint only only_guide_cops require safe
17
17
  autocorrect safe_autocorrect autocorrect_all
18
18
  ].freeze
@@ -37,6 +37,8 @@ module RuboCop
37
37
  #
38
38
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
39
39
  def run(args = ARGV)
40
+ time_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
41
+
40
42
  @options, paths = Options.new.parse(args)
41
43
  @env = Environment.new(@options, @config_store, paths)
42
44
 
@@ -48,6 +50,7 @@ module RuboCop
48
50
  validate_options_vs_config
49
51
  parallel_by_default!
50
52
  apply_default_formatter
53
+ report_pending_cops
51
54
  execute_runners
52
55
  end
53
56
  end
@@ -63,7 +66,7 @@ module RuboCop
63
66
  STATUS_INTERRUPTED
64
67
  rescue Finished
65
68
  STATUS_SUCCESS
66
- rescue OptionParser::InvalidOption => e
69
+ rescue OptionParser::ParseError => e
67
70
  warn e.message
68
71
  warn 'For usage information, use --help'
69
72
  STATUS_ERROR
@@ -71,6 +74,9 @@ module RuboCop
71
74
  warn e.message
72
75
  warn e.backtrace
73
76
  STATUS_ERROR
77
+ ensure
78
+ elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
79
+ puts "Finished in #{elapsed_time} seconds" if @options[:debug] || @options[:display_time]
74
80
  end
75
81
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
76
82
 
@@ -155,10 +161,10 @@ module RuboCop
155
161
 
156
162
  def act_on_options
157
163
  set_options_to_config_loader
164
+ set_options_to_pending_cops_reporter
158
165
  handle_editor_mode
159
166
 
160
- @config_store.options_config = @options[:config] if @options[:config]
161
- @config_store.force_default_config! if @options[:force_default_config]
167
+ @config_store.apply_options!(@options)
162
168
 
163
169
  handle_exiting_options
164
170
 
@@ -177,6 +183,12 @@ module RuboCop
177
183
  ConfigLoader.enable_pending_cops = @options[:enable_pending_cops]
178
184
  ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion]
179
185
  ConfigLoader.ignore_unrecognized_cops = @options[:ignore_unrecognized_cops]
186
+ ConfigLoader.cache_root = ResultCache.cache_root(@config_store, @options[:cache_root])
187
+ end
188
+
189
+ def set_options_to_pending_cops_reporter
190
+ PendingCopsReporter.disable_pending_cops = @options[:disable_pending_cops]
191
+ PendingCopsReporter.enable_pending_cops = @options[:enable_pending_cops]
180
192
  end
181
193
 
182
194
  def handle_editor_mode
@@ -208,5 +220,9 @@ module RuboCop
208
220
  [[formatter, @options[:output_path]]]
209
221
  end
210
222
  end
223
+
224
+ def report_pending_cops
225
+ PendingCopsReporter.warn_if_needed(@config_store.for_pwd)
226
+ end
211
227
  end
212
228
  end
@@ -34,6 +34,7 @@ module RuboCop
34
34
  def initialize(processed_source)
35
35
  @processed_source = processed_source
36
36
  @no_directives = !processed_source.raw_source.include?('rubocop')
37
+ @stack = []
37
38
  end
38
39
 
39
40
  def cop_enabled_at_line?(cop, line_number)
@@ -93,16 +94,23 @@ module RuboCop
93
94
  end
94
95
  end
95
96
 
96
- def analyze # rubocop:todo Metrics/AbcSize
97
+ def analyze # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
97
98
  return {} if @no_directives
98
99
 
99
100
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
100
101
  inject_disabled_cops_directives(analyses)
101
102
 
102
103
  each_directive do |directive|
103
- directive.cop_names.each do |cop_name|
104
- cop_name = qualified_cop_name(cop_name)
105
- analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
104
+ if directive.push?
105
+ @stack.push(snapshot_analyses(analyses))
106
+ apply_push_args(analyses, directive)
107
+ elsif directive.pop?
108
+ pop_state(analyses, directive.line_number) if @stack.any?
109
+ else
110
+ directive.cop_names.each do |cop_name|
111
+ cop_name = qualified_cop_name(cop_name)
112
+ analyses[cop_name] = analyze_cop(analyses[cop_name], directive)
113
+ end
106
114
  end
107
115
  end
108
116
 
@@ -112,6 +120,51 @@ module RuboCop
112
120
  end
113
121
  end
114
122
 
123
+ def snapshot_analyses(analyses)
124
+ analyses.transform_values { |a| CopAnalysis.new(a.line_ranges.dup, a.start_line_number) }
125
+ end
126
+
127
+ def pop_state(analyses, pop_line)
128
+ analyses.each do |cop_name, analysis|
129
+ next unless analysis.start_line_number
130
+
131
+ analyses[cop_name] = CopAnalysis.new(
132
+ analysis.line_ranges + [analysis.start_line_number...pop_line], nil
133
+ )
134
+ end
135
+
136
+ @stack.pop.each do |cop_name, saved_analysis|
137
+ current = analyses[cop_name]
138
+ new_start = saved_analysis.start_line_number ? pop_line : nil
139
+ analyses[cop_name] = CopAnalysis.new(current.line_ranges, new_start)
140
+ end
141
+ end
142
+
143
+ def apply_push_args(analyses, directive)
144
+ directive.push_args.each do |operation, cop_names|
145
+ cop_names.each do |cop_name|
146
+ apply_cop_operation(analyses, operation, qualified_cop_name(cop_name),
147
+ directive.line_number)
148
+ end
149
+ end
150
+ end
151
+
152
+ def apply_cop_operation(analyses, operation, cop_name, line)
153
+ analysis = analyses[cop_name]
154
+ start_line = analysis.start_line_number
155
+
156
+ case operation
157
+ when '+' # Enable cop
158
+ return unless start_line
159
+
160
+ analyses[cop_name] = CopAnalysis.new(analysis.line_ranges + [start_line..line], nil)
161
+ when '-' # Disable cop
162
+ return if start_line
163
+
164
+ analyses[cop_name] = CopAnalysis.new(analysis.line_ranges, line)
165
+ end
166
+ end
167
+
115
168
  def inject_disabled_cops_directives(analyses)
116
169
  registry.disabled(config).each do |cop|
117
170
  analyses[cop.cop_name] = analyze_cop(
@@ -136,29 +189,21 @@ module RuboCop
136
189
  return analysis unless directive.disabled?
137
190
 
138
191
  line = directive.line_number
139
- start_line = analysis.start_line_number
140
-
141
- CopAnalysis.new(analysis.line_ranges + [(line..line)], start_line)
192
+ CopAnalysis.new(analysis.line_ranges + [(line..line)], analysis.start_line_number)
142
193
  end
143
194
 
144
195
  def analyze_disabled(analysis, directive)
145
196
  line = directive.line_number
146
197
  start_line = analysis.start_line_number
147
-
148
- # Cop already disabled on this line, so we end the current disabled
149
- # range before we start a new range.
150
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], line) if start_line
151
-
152
- CopAnalysis.new(analysis.line_ranges, line)
198
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
199
+ CopAnalysis.new(new_ranges, line)
153
200
  end
154
201
 
155
202
  def analyze_rest(analysis, directive)
156
203
  line = directive.line_number
157
204
  start_line = analysis.start_line_number
158
-
159
- return CopAnalysis.new(analysis.line_ranges + [start_line..line], nil) if start_line
160
-
161
- CopAnalysis.new(analysis.line_ranges, nil)
205
+ new_ranges = start_line ? analysis.line_ranges + [start_line..line] : analysis.line_ranges
206
+ CopAnalysis.new(new_ranges, nil)
162
207
  end
163
208
 
164
209
  def cop_line_ranges(analysis)
@@ -22,16 +22,8 @@ module RuboCop
22
22
  class << self
23
23
  include FileFinder
24
24
 
25
- PENDING_BANNER = <<~BANNER
26
- The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
27
-
28
- Please also note that you can opt-in to new cops by default by adding this to your config:
29
- AllCops:
30
- NewCops: enable
31
- BANNER
32
-
33
25
  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
34
- :ignore_unrecognized_cops
26
+ :ignore_unrecognized_cops, :cache_root
35
27
  attr_writer :default_configuration
36
28
  attr_reader :loaded_plugins, :loaded_features
37
29
 
@@ -46,6 +38,7 @@ module RuboCop
46
38
  @enable_pending_cops = nil
47
39
  @ignore_parent_exclusion = nil
48
40
  @ignore_unrecognized_cops = nil
41
+ @cache_root = nil
49
42
  FileFinder.root_level = nil
50
43
  end
51
44
 
@@ -83,7 +76,9 @@ module RuboCop
83
76
 
84
77
  puts "configuration from #{absolute_path}" if debug?
85
78
 
86
- raise(TypeError, "Malformed configuration in #{absolute_path}") unless hash.is_a?(Hash)
79
+ unless hash.is_a?(Hash)
80
+ raise(ValidationError, "Malformed configuration in #{absolute_path}")
81
+ end
87
82
 
88
83
  hash
89
84
  end
@@ -132,21 +127,7 @@ module RuboCop
132
127
  add_excludes_from_files(config, config_file)
133
128
  end
134
129
 
135
- merge_with_default(config, config_file).tap do |merged_config|
136
- unless possible_new_cops?(merged_config)
137
- pending_cops = pending_cops_only_qualified(merged_config.pending_cops)
138
- warn_on_pending_cops(pending_cops) unless pending_cops.empty?
139
- end
140
- end
141
- end
142
-
143
- def pending_cops_only_qualified(pending_cops)
144
- pending_cops.select { |cop| Cop::Registry.qualified_cop?(cop.name) }
145
- end
146
-
147
- def possible_new_cops?(config)
148
- disable_pending_cops || enable_pending_cops ||
149
- config.disabled_new_cops? || config.enabled_new_cops?
130
+ merge_with_default(config, config_file)
150
131
  end
151
132
 
152
133
  def add_excludes_from_files(config, config_file)
@@ -208,21 +189,6 @@ module RuboCop
208
189
  ConfigFinder.project_root
209
190
  end
210
191
 
211
- def warn_on_pending_cops(pending_cops)
212
- warn Rainbow(PENDING_BANNER).yellow
213
-
214
- pending_cops.each { |cop| warn_pending_cop cop }
215
-
216
- warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
217
- end
218
-
219
- def warn_pending_cop(cop)
220
- version = cop.metadata['VersionAdded'] || 'N/A'
221
-
222
- warn Rainbow("#{cop.name}: # new in #{version}").yellow
223
- warn Rainbow(' Enabled: true').yellow
224
- end
225
-
226
192
  # Merges the given configuration with the default one.
227
193
  def merge_with_default(config, config_file, unset_nil: true)
228
194
  resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
@@ -246,7 +246,7 @@ module RuboCop
246
246
  def inherited_file(path, inherit_from, file)
247
247
  if PathUtil.remote_file?(inherit_from)
248
248
  # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`.
249
- RemoteConfig.new(inherit_from, File.dirname(path))
249
+ RemoteConfig.new(inherit_from, ConfigLoader.cache_root)
250
250
  elsif Pathname.new(inherit_from).absolute?
251
251
  # An absolute path to a config, e.g. `inherit_from: /Users/me/rubocop.yml`.
252
252
  # The path may come from `inherit_gem` option, where a gem name is expanded
@@ -256,7 +256,7 @@ module RuboCop
256
256
  elsif file.is_a?(RemoteConfig)
257
257
  # A path relative to a URL, e.g. `inherit_from: configs/default.yml`
258
258
  # in a config included with `inherit_from: http://example.com/rubocop.yml`
259
- file.inherit_from_remote(inherit_from, path)
259
+ file.inherit_from_remote(inherit_from)
260
260
  else
261
261
  # A local relative path, e.g. `inherit_from: default.yml`
262
262
  print 'Inheriting ' if ConfigLoader.debug?
@@ -295,10 +295,11 @@ module RuboCop
295
295
  begin
296
296
  gem = Bundler.load.specs[gem_name].first
297
297
  gem_path = gem.full_gem_path if gem
298
- rescue Bundler::GemfileNotFound
299
- # No Gemfile found. Bundler may be loaded manually
300
- rescue Bundler::GitError
301
- # The Gemfile exists but contains an uninstalled git source
298
+ rescue StandardError
299
+ # The Gemfile has a problem, which could be one of:
300
+ # - No Gemfile found. Bundler may be loaded manually
301
+ # - The Gemfile exists but contains an uninstalled git source
302
+ # - The Gemfile exists but cannot be loaded for some other reason
302
303
  end
303
304
  end
304
305
 
@@ -25,6 +25,11 @@ module RuboCop
25
25
  @validated = true
26
26
  end
27
27
 
28
+ def apply_options!(options)
29
+ self.options_config = options[:config] if options[:config]
30
+ force_default_config! if options[:force_default_config]
31
+ end
32
+
28
33
  def options_config=(options_config)
29
34
  loaded_config = ConfigLoader.load_file(options_config)
30
35
  @options_config = ConfigLoader.merge_with_default(loaded_config, options_config)
@@ -35,8 +35,8 @@ module RuboCop
35
35
  # `false` is the same as `disabled` for backward compatibility.
36
36
  return false if ['disabled', false].include?(cop_config['AutoCorrect'])
37
37
 
38
- # When LSP is enabled, it is considered as editing source code,
39
- # and autocorrection with `AutoCorrect: contextual` will not be performed.
38
+ # When LSP is enabled or the `--editor-mode` option is on, it is considered as editing
39
+ # source code, and autocorrection with `AutoCorrect: contextual` will not be performed.
40
40
  return false if contextual_autocorrect? && LSP.enabled?
41
41
 
42
42
  # :safe_autocorrect is a derived option based on several command-line
@@ -90,11 +90,13 @@ module RuboCop
90
90
  end
91
91
 
92
92
  def line_with_eol_comment_too_long?(range)
93
+ return false unless max_line_length
94
+
93
95
  (range.source_line + eol_comment).length > max_line_length
94
96
  end
95
97
 
96
98
  def surrounding_heredoc?(node)
97
- node.type?(:str, :dstr, :xstr) && node.heredoc?
99
+ node.any_str_type? && node.heredoc?
98
100
  end
99
101
 
100
102
  def heredoc_range(node)
@@ -106,7 +108,7 @@ module RuboCop
106
108
  end
107
109
 
108
110
  def string_continuation?(node)
109
- node.type?(:str, :dstr, :xstr) && node.source.match?(/\\\s*$/)
111
+ node.any_str_type? && node.source.match?(/\\\s*$/)
110
112
  end
111
113
 
112
114
  def multiline_string?(node)
@@ -133,6 +135,8 @@ module RuboCop
133
135
  end
134
136
 
135
137
  def max_line_length
138
+ return unless config.cop_enabled?('Layout/LineLength')
139
+
136
140
  config.for_cop('Layout/LineLength')['Max'] || 120
137
141
  end
138
142
 
@@ -43,9 +43,8 @@ module RuboCop
43
43
  def on_new_investigation
44
44
  return if processed_source.blank?
45
45
 
46
- gem_declarations(processed_source.ast)
47
- .each_cons(2) do |previous, current|
48
- next unless consecutive_lines(previous, current)
46
+ gem_declarations(processed_source.ast).each_cons(2) do |previous, current|
47
+ next unless consecutive_lines?(previous, current)
49
48
  next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
50
49
 
51
50
  register_offense(previous, current)
@@ -29,10 +29,13 @@ module RuboCop
29
29
  def align_end(corrector, processed_source, node, align_to)
30
30
  @processed_source = processed_source
31
31
  whitespace = whitespace_range(node)
32
- return false unless whitespace.source.strip.empty?
33
-
34
32
  column = alignment_column(align_to)
35
- corrector.replace(whitespace, ' ' * column)
33
+
34
+ if whitespace.source.strip.empty?
35
+ corrector.replace(whitespace, ' ' * column)
36
+ else
37
+ corrector.insert_after(whitespace, "\n#{' ' * column}")
38
+ end
36
39
  end
37
40
 
38
41
  private
@@ -54,7 +57,7 @@ module RuboCop
54
57
  def inside_string_ranges(node)
55
58
  return [] unless node.is_a?(Parser::AST::Node)
56
59
 
57
- node.each_node(:str, :dstr, :xstr).filter_map { |n| inside_string_range(n) }
60
+ node.each_node(:any_str).filter_map { |n| inside_string_range(n) }
58
61
  end
59
62
 
60
63
  def inside_string_range(node)
@@ -73,9 +76,7 @@ module RuboCop
73
76
  # nil.
74
77
  # - The source map of `__FILE__` responds to neither :begin nor :end.
75
78
  def delimited_string_literal?(node)
76
- loc = node.location
77
-
78
- loc.respond_to?(:begin) && loc.begin && loc.respond_to?(:end) && loc.end
79
+ node.loc?(:begin) && node.loc?(:end)
79
80
  end
80
81
 
81
82
  def block_comment_within?(expr)
@@ -6,7 +6,7 @@ module RuboCop
6
6
  class ForToEachCorrector
7
7
  extend NodePattern::Macros
8
8
 
9
- CORRECTION = '%<collection>s.each do |%<argument>s|'
9
+ CORRECTION = '%<collection>s%<dot>seach do |%<argument>s|'
10
10
 
11
11
  def initialize(for_node)
12
12
  @for_node = for_node
@@ -25,7 +25,12 @@ module RuboCop
25
25
  attr_reader :for_node, :variable_node, :collection_node
26
26
 
27
27
  def correction
28
- format(CORRECTION, collection: collection_source, argument: variable_node.source)
28
+ format(
29
+ CORRECTION,
30
+ collection: collection_source,
31
+ dot: collection_node.csend_type? ? '&.' : '.',
32
+ argument: variable_node.source
33
+ )
29
34
  end
30
35
 
31
36
  def collection_source
@@ -10,8 +10,11 @@ module RuboCop
10
10
  COMMA_REGEXP = /(?<=\))\s*,/.freeze
11
11
 
12
12
  def correct(corrector, node)
13
- corrector.remove(node.loc.begin)
14
- corrector.remove(node.loc.end)
13
+ buffer = node.source_range.source_buffer
14
+ corrector.remove(range_with_surrounding_space(range: node.loc.begin, buffer: buffer,
15
+ side: :right, whitespace: true))
16
+ corrector.remove(range_with_surrounding_space(range: node.loc.end, buffer: buffer,
17
+ side: :left))
15
18
  handle_orphaned_comma(corrector, node)
16
19
 
17
20
  return unless ternary_condition?(node) && next_char_is_question_mark?(node)
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # Use consistent style for Gemspec attributes assignment.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # # This example uses two styles for assignment of metadata attribute.
12
+ # Gem::Specification.new do |spec|
13
+ # spec.metadata = { 'key' => 'value' }
14
+ # spec.metadata['another-key'] = 'another-value'
15
+ # end
16
+ #
17
+ # # good
18
+ # Gem::Specification.new do |spec|
19
+ # spec.metadata['key'] = 'value'
20
+ # spec.metadata['another-key'] = 'another-value'
21
+ # end
22
+ #
23
+ # # good
24
+ # Gem::Specification.new do |spec|
25
+ # spec.metadata = { 'key' => 'value', 'another-key' => 'another-value' }
26
+ # end
27
+ #
28
+ # # bad
29
+ # # This example uses two styles for assignment of authors attribute.
30
+ # Gem::Specification.new do |spec|
31
+ # spec.authors = %w[author-0 author-1]
32
+ # spec.authors[2] = 'author-2'
33
+ # end
34
+ #
35
+ # # good
36
+ # Gem::Specification.new do |spec|
37
+ # spec.authors = %w[author-0 author-1 author-2]
38
+ # end
39
+ #
40
+ # # good
41
+ # Gem::Specification.new do |spec|
42
+ # spec.authors[0] = 'author-0'
43
+ # spec.authors[1] = 'author-1'
44
+ # spec.authors[2] = 'author-2'
45
+ # end
46
+ #
47
+ # # good
48
+ # # This example uses consistent assignment per attribute,
49
+ # # even though two different styles are used overall.
50
+ # Gem::Specification.new do |spec|
51
+ # spec.metadata = { 'key' => 'value' }
52
+ # spec.authors[0] = 'author-0'
53
+ # spec.authors[1] = 'author-1'
54
+ # spec.authors[2] = 'author-2'
55
+ # end
56
+ #
57
+ class AttributeAssignment < Base
58
+ include GemspecHelp
59
+
60
+ MSG = 'Use consistent style for Gemspec attributes assignment.'
61
+
62
+ def on_new_investigation
63
+ return if processed_source.blank?
64
+
65
+ assignments = source_assignments(processed_source.ast)
66
+ indexed_assignments = source_indexed_assignments(processed_source.ast)
67
+
68
+ assignments.keys.intersection(indexed_assignments.keys).each do |attribute|
69
+ indexed_assignments[attribute].each do |node|
70
+ add_offense(node)
71
+ end
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def source_assignments(ast)
78
+ assignment_method_declarations(ast)
79
+ .select(&:assignment_method?)
80
+ .group_by(&:method_name)
81
+ .transform_keys { |method_name| method_name.to_s.delete_suffix('=').to_sym }
82
+ end
83
+
84
+ def source_indexed_assignments(ast)
85
+ indexed_assignment_method_declarations(ast)
86
+ .group_by { |node| node.children.first.method_name }
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -54,22 +54,6 @@ module RuboCop
54
54
  MSG = '`%<assignment>s` method calls already given on line ' \
55
55
  '%<line_of_first_occurrence>d of the gemspec.'
56
56
 
57
- # @!method assignment_method_declarations(node)
58
- def_node_search :assignment_method_declarations, <<~PATTERN
59
- (send
60
- (lvar #match_block_variable_name?) _ ...)
61
- PATTERN
62
-
63
- # @!method indexed_assignment_method_declarations(node)
64
- def_node_search :indexed_assignment_method_declarations, <<~PATTERN
65
- (send
66
- (send (lvar #match_block_variable_name?) _)
67
- :[]=
68
- literal?
69
- _
70
- )
71
- PATTERN
72
-
73
57
  def on_new_investigation
74
58
  return if processed_source.blank?
75
59
 
@@ -96,12 +80,6 @@ module RuboCop
96
80
  end
97
81
  end
98
82
 
99
- def match_block_variable_name?(receiver_name)
100
- gem_specification(processed_source.ast) do |block_variable_name|
101
- return block_variable_name == receiver_name
102
- end
103
- end
104
-
105
83
  def duplicated_assignment_method_nodes
106
84
  assignment_method_declarations(processed_source.ast)
107
85
  .select(&:assignment_method?)
@@ -69,9 +69,8 @@ module RuboCop
69
69
  def on_new_investigation
70
70
  return if processed_source.blank?
71
71
 
72
- dependency_declarations(processed_source.ast)
73
- .each_cons(2) do |previous, current|
74
- next unless consecutive_lines(previous, current)
72
+ dependency_declarations(processed_source.ast).each_cons(2) do |previous, current|
73
+ next unless consecutive_lines?(previous, current)
75
74
  next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
76
75
  next unless get_dependency_name(previous) == get_dependency_name(current)
77
76
 
@@ -74,6 +74,14 @@ module RuboCop
74
74
  }
75
75
  PATTERN
76
76
 
77
+ # @!method metadata_assignment(node)
78
+ def_node_search :metadata_assignment, <<~PATTERN
79
+ `{
80
+ (send _ :metadata= _)
81
+ (send (send _ :metadata) :[]= (str _) _)
82
+ }
83
+ PATTERN
84
+
77
85
  # @!method rubygems_mfa_required(node)
78
86
  def_node_search :rubygems_mfa_required, <<~PATTERN
79
87
  (pair (str "rubygems_mfa_required") $_)
@@ -131,9 +139,15 @@ module RuboCop
131
139
  end
132
140
 
133
141
  def insert_mfa_required(corrector, node, block_var)
134
- corrector.insert_before(node.loc.end, <<~RUBY)
142
+ require_mfa_directive = <<~RUBY.strip
135
143
  #{block_var}.metadata['rubygems_mfa_required'] = 'true'
136
144
  RUBY
145
+
146
+ if (last_assignment = metadata_assignment(processed_source.ast).to_a.last)
147
+ corrector.insert_after(last_assignment, "\n#{require_mfa_directive}")
148
+ else
149
+ corrector.insert_before(node.loc.end, "#{require_mfa_directive}\n")
150
+ end
137
151
  end
138
152
 
139
153
  def change_value(corrector, value)