rubocop 1.57.2 → 1.62.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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +87 -15
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
  8. data/lib/rubocop/cli/command/lsp.rb +2 -2
  9. data/lib/rubocop/cli.rb +6 -1
  10. data/lib/rubocop/config.rb +4 -2
  11. data/lib/rubocop/config_finder.rb +12 -2
  12. data/lib/rubocop/config_loader.rb +0 -1
  13. data/lib/rubocop/config_obsoletion.rb +11 -8
  14. data/lib/rubocop/config_validator.rb +14 -7
  15. data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
  16. data/lib/rubocop/cop/base.rb +17 -2
  17. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  18. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  19. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  20. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  21. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  23. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
  24. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  25. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  26. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +123 -29
  28. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  29. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  32. data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
  33. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  34. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  35. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  37. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
  40. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  41. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  43. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  44. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  45. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  46. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  47. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  48. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  49. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  50. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  51. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  52. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  53. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  54. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  55. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  56. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  57. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  58. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  59. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
  60. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  61. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  62. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  63. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  64. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  65. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  66. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  67. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  68. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  69. data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
  70. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  71. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  72. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  73. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  74. data/lib/rubocop/cop/lint/void.rb +20 -2
  75. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  76. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  77. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  78. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  79. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  80. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  81. data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
  82. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  83. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  84. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  85. data/lib/rubocop/cop/registry.rb +1 -1
  86. data/lib/rubocop/cop/security/open.rb +2 -2
  87. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  88. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  89. data/lib/rubocop/cop/style/arguments_forwarding.rb +152 -21
  90. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  91. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  92. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  93. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  94. data/lib/rubocop/cop/style/class_check.rb +1 -0
  95. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  96. data/lib/rubocop/cop/style/collection_compact.rb +18 -8
  97. data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
  98. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  99. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
  100. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
  101. data/lib/rubocop/cop/style/date_time.rb +5 -4
  102. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  103. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  104. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  105. data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
  106. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  107. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  108. data/lib/rubocop/cop/style/for.rb +2 -0
  109. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  110. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  111. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  112. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  113. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  114. data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
  115. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  116. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  117. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
  118. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  119. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  120. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  121. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  122. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  123. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
  124. data/lib/rubocop/cop/style/next.rb +1 -1
  125. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  126. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  127. data/lib/rubocop/cop/style/object_then.rb +5 -3
  128. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  129. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  130. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  131. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  132. data/lib/rubocop/cop/style/redundant_argument.rb +4 -3
  133. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  134. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +4 -3
  135. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  136. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  137. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  138. data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -7
  139. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
  140. data/lib/rubocop/cop/style/redundant_return.rb +7 -1
  141. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  142. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  143. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  144. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  145. data/lib/rubocop/cop/style/sample.rb +3 -4
  146. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  147. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  148. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  149. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
  150. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  151. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  152. data/lib/rubocop/cop/style/strip.rb +7 -4
  153. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  154. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  155. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  156. data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
  157. data/lib/rubocop/cops_documentation_generator.rb +15 -3
  158. data/lib/rubocop/directive_comment.rb +10 -8
  159. data/lib/rubocop/ext/regexp_node.rb +9 -4
  160. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  161. data/lib/rubocop/formatter/html_formatter.rb +31 -12
  162. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  163. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  164. data/lib/rubocop/formatter.rb +1 -1
  165. data/lib/rubocop/lsp/logger.rb +1 -1
  166. data/lib/rubocop/lsp/routes.rb +2 -2
  167. data/lib/rubocop/lsp/runtime.rb +1 -1
  168. data/lib/rubocop/lsp/server.rb +5 -2
  169. data/lib/rubocop/lsp/severity.rb +1 -1
  170. data/lib/rubocop/lsp.rb +29 -0
  171. data/lib/rubocop/magic_comment.rb +1 -1
  172. data/lib/rubocop/options.rb +11 -8
  173. data/lib/rubocop/path_util.rb +6 -2
  174. data/lib/rubocop/result_cache.rb +0 -1
  175. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  176. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  177. data/lib/rubocop/rspec/shared_contexts.rb +40 -15
  178. data/lib/rubocop/rspec/support.rb +2 -0
  179. data/lib/rubocop/runner.rb +10 -3
  180. data/lib/rubocop/server/cache.rb +1 -2
  181. data/lib/rubocop/server/client_command/exec.rb +0 -1
  182. data/lib/rubocop/server/server_command/exec.rb +0 -1
  183. data/lib/rubocop/target_finder.rb +84 -78
  184. data/lib/rubocop/target_ruby.rb +82 -80
  185. data/lib/rubocop/version.rb +18 -3
  186. data/lib/rubocop.rb +4 -0
  187. metadata +18 -10
  188. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -17,7 +17,10 @@ module RuboCop
17
17
 
18
18
  PHASE_1_OVERRIDDEN = '(skipped because the default Layout/LineLength:Max is overridden)'
19
19
  PHASE_1_DISABLED = '(skipped because Layout/LineLength is disabled)'
20
- PHASE_1_SKIPPED = '(skipped because a list of cops is passed to the `--only` flag)'
20
+ PHASE_1_SKIPPED_ONLY_COPS =
21
+ '(skipped because a list of cops is passed to the `--only` flag)'
22
+ PHASE_1_SKIPPED_ONLY_EXCLUDE =
23
+ '(skipped because only excludes will be generated due to `--auto-gen-only-exclude` flag)'
21
24
 
22
25
  def run
23
26
  add_formatter
@@ -29,12 +32,14 @@ module RuboCop
29
32
  private
30
33
 
31
34
  def maybe_run_line_length_cop
32
- if !line_length_enabled?(@config_store.for_pwd)
35
+ if only_exclude?
36
+ skip_line_length_cop(PHASE_1_SKIPPED_ONLY_EXCLUDE)
37
+ elsif !line_length_enabled?(@config_store.for_pwd)
33
38
  skip_line_length_cop(PHASE_1_DISABLED)
34
39
  elsif !same_max_line_length?(@config_store.for_pwd, ConfigLoader.default_configuration)
35
40
  skip_line_length_cop(PHASE_1_OVERRIDDEN)
36
41
  elsif options_has_only_flag?
37
- skip_line_length_cop(PHASE_1_SKIPPED)
42
+ skip_line_length_cop(PHASE_1_SKIPPED_ONLY_COPS)
38
43
  else
39
44
  run_line_length_cop
40
45
  end
@@ -65,6 +70,10 @@ module RuboCop
65
70
  @options[:only]
66
71
  end
67
72
 
73
+ def only_exclude?
74
+ @options[:auto_gen_only_exclude]
75
+ end
76
+
68
77
  # Do an initial run with only Layout/LineLength so that cops that
69
78
  # depend on Layout/LineLength:Max get the correct value for that
70
79
  # parameter.
@@ -7,11 +7,11 @@ module RuboCop
7
7
  module Command
8
8
  # Start Language Server Protocol of RuboCop.
9
9
  # @api private
10
- class Lsp < Base
10
+ class LSP < Base
11
11
  self.command_name = :lsp
12
12
 
13
13
  def run
14
- RuboCop::Lsp::Server.new(@config_store).start
14
+ RuboCop::LSP::Server.new(@config_store).start
15
15
  end
16
16
  end
17
17
  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 except extra_details fail_level fix_layout format
15
+ display_only_failed editor_mode except extra_details fail_level fix_layout format
16
16
  ignore_disable_comments lint only only_guide_cops require safe
17
17
  autocorrect safe_autocorrect autocorrect_all
18
18
  ].freeze
@@ -151,6 +151,7 @@ module RuboCop
151
151
 
152
152
  def act_on_options
153
153
  set_options_to_config_loader
154
+ handle_editor_mode
154
155
 
155
156
  @config_store.options_config = @options[:config] if @options[:config]
156
157
  @config_store.force_default_config! if @options[:force_default_config]
@@ -174,6 +175,10 @@ module RuboCop
174
175
  ConfigLoader.ignore_unrecognized_cops = @options[:ignore_unrecognized_cops]
175
176
  end
176
177
 
178
+ def handle_editor_mode
179
+ RuboCop::LSP.enable if @options[:editor_mode]
180
+ end
181
+
177
182
  # rubocop:disable Metrics/CyclomaticComplexity
178
183
  def handle_exiting_options
179
184
  return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
3
  # FIXME: Moving Rails department code to RuboCop Rails will remove
6
4
  # the following rubocop:disable comment.
7
5
  # rubocop:disable Metrics/ClassLength
@@ -246,6 +244,10 @@ module RuboCop
246
244
  end
247
245
  end
248
246
 
247
+ def parser_engine
248
+ @parser_engine ||= for_all_cops.fetch('ParserEngine', :parser_whitequark).to_sym
249
+ end
250
+
249
251
  def target_rails_version
250
252
  @target_rails_version ||=
251
253
  if for_all_cops['TargetRailsVersion']
@@ -17,8 +17,8 @@ module RuboCop
17
17
  attr_writer :project_root
18
18
 
19
19
  def find_config_path(target_dir)
20
- find_project_dotfile(target_dir) || find_user_dotfile || find_user_xdg_config ||
21
- DEFAULT_FILE
20
+ find_project_dotfile(target_dir) || find_project_root_dot_config ||
21
+ find_user_dotfile || find_user_xdg_config || DEFAULT_FILE
22
22
  end
23
23
 
24
24
  # Returns the path RuboCop inferred as the root of the project. No file
@@ -41,6 +41,16 @@ module RuboCop
41
41
  find_file_upwards(DOTFILE, target_dir, project_root)
42
42
  end
43
43
 
44
+ def find_project_root_dot_config
45
+ return unless project_root
46
+
47
+ dotfile = File.join(project_root, '.config', DOTFILE)
48
+ return dotfile if File.exist?(dotfile)
49
+
50
+ xdg_config = File.join(project_root, '.config', 'rubocop', XDG_CONFIG)
51
+ xdg_config if File.exist?(xdg_config)
52
+ end
53
+
44
54
  def find_user_dotfile
45
55
  return unless ENV.key?('HOME')
46
56
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'erb'
4
- require 'pathname'
5
4
  require 'yaml'
6
5
  require_relative 'config_finder'
7
6
 
@@ -15,6 +15,8 @@ module RuboCop
15
15
  'changed_parameters' => ChangedParameter,
16
16
  'changed_enforced_styles' => ChangedEnforcedStyles
17
17
  }.freeze
18
+ LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant
19
+ private_constant :LOAD_RULES_CACHE
18
20
 
19
21
  attr_reader :rules, :warnings
20
22
 
@@ -48,16 +50,17 @@ module RuboCop
48
50
  # Default rules for obsoletions are in config/obsoletion.yml
49
51
  # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
50
52
  def load_rules # rubocop:disable Metrics/AbcSize
51
- rules = self.class.files.each_with_object({}) do |filename, hash|
52
- hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
53
- case first
54
- when Hash
55
- first.merge(second)
56
- when Array
57
- first.concat(second)
53
+ rules = LOAD_RULES_CACHE[self.class.files] ||=
54
+ self.class.files.each_with_object({}) do |filename, hash|
55
+ hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
56
+ case first
57
+ when Hash
58
+ first.merge(second)
59
+ when Array
60
+ first.concat(second)
61
+ end
58
62
  end
59
63
  end
60
- end
61
64
 
62
65
  cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
63
66
  parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
3
  module RuboCop
6
4
  # Handles validation of configuration, for example cop names, parameter
7
5
  # names, and Ruby versions.
@@ -20,6 +18,7 @@ module RuboCop
20
18
  # @api private
21
19
  CONFIG_CHECK_KEYS = %w[Enabled Safe SafeAutoCorrect AutoCorrect].to_set.freeze
22
20
  CONFIG_CHECK_DEPARTMENTS = %w[pending override_department].freeze
21
+ CONFIG_CHECK_AUTOCORRECTS = %w[always contextual disabled].freeze
23
22
  private_constant :CONFIG_CHECK_KEYS, :CONFIG_CHECK_DEPARTMENTS
24
23
 
25
24
  def_delegators :@config, :smart_loaded_path, :for_all_cops
@@ -250,23 +249,31 @@ module RuboCop
250
249
  end
251
250
  end
252
251
 
252
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
253
253
  def check_cop_config_value(hash, parent = nil)
254
254
  hash.each do |key, value|
255
255
  check_cop_config_value(value, key) if value.is_a?(Hash)
256
256
 
257
257
  next unless CONFIG_CHECK_KEYS.include?(key) && value.is_a?(String)
258
258
 
259
- next if key == 'Enabled' && CONFIG_CHECK_DEPARTMENTS.include?(value)
259
+ if key == 'Enabled' && !CONFIG_CHECK_DEPARTMENTS.include?(value)
260
+ supposed_values = 'a boolean'
261
+ elsif key == 'AutoCorrect' && !CONFIG_CHECK_AUTOCORRECTS.include?(value)
262
+ supposed_values = '`always`, `contextual`, `disabled`, or a boolean'
263
+ else
264
+ next
265
+ end
260
266
 
261
- raise ValidationError, msg_not_boolean(parent, key, value)
267
+ raise ValidationError, param_error_message(parent, key, value, supposed_values)
262
268
  end
263
269
  end
270
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
264
271
 
265
272
  # FIXME: Handling colors in exception messages like this is ugly.
266
- def msg_not_boolean(parent, key, value)
273
+ def param_error_message(parent, key, value, supposed_values)
267
274
  "#{Rainbow('').reset}" \
268
- "Property #{Rainbow(key).yellow} of cop #{Rainbow(parent).yellow} " \
269
- "is supposed to be a boolean and #{Rainbow(value).yellow} is not."
275
+ "Property #{Rainbow(key).yellow} of #{Rainbow(parent).yellow} cop " \
276
+ "is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
270
277
  end
271
278
  end
272
279
  end
@@ -32,7 +32,12 @@ module RuboCop
32
32
  # allow turning off autocorrect on a cop by cop basis
33
33
  return true unless cop_config
34
34
 
35
- return false if cop_config['AutoCorrect'] == false
35
+ # `false` is the same as `disabled` for backward compatibility.
36
+ return false if ['disabled', false].include?(cop_config['AutoCorrect'])
37
+
38
+ # When LSP is enabled, it is considered as editing source code,
39
+ # and autocorrection with `AutoCorrect: contextual` will not be performed.
40
+ return false if contextual_autocorrect? && LSP.enabled?
36
41
 
37
42
  # :safe_autocorrect is a derived option based on several command-line
38
43
  # arguments - see RuboCop::Options#add_autocorrection_options
@@ -232,6 +232,10 @@ module RuboCop
232
232
  @config.target_ruby_version
233
233
  end
234
234
 
235
+ def parser_engine
236
+ @config.parser_engine
237
+ end
238
+
235
239
  def target_rails_version
236
240
  @config.target_rails_version
237
241
  end
@@ -254,7 +258,7 @@ module RuboCop
254
258
 
255
259
  # There should be very limited reasons for a Cop to do it's own parsing
256
260
  def parse(source, path = nil)
257
- ProcessedSource.new(source, target_ruby_version, path)
261
+ ProcessedSource.new(source, target_ruby_version, path, parser_engine: parser_engine)
258
262
  end
259
263
 
260
264
  # @api private
@@ -305,6 +309,17 @@ module RuboCop
305
309
  @current_original = original
306
310
  end
307
311
 
312
+ # @api private
313
+ def always_autocorrect?
314
+ # `true` is the same as `'always'` for backward compatibility.
315
+ ['always', true].include?(cop_config.fetch('AutoCorrect', 'always'))
316
+ end
317
+
318
+ # @api private
319
+ def contextual_autocorrect?
320
+ cop_config.fetch('AutoCorrect', 'always') == 'contextual'
321
+ end
322
+
308
323
  def inspect # :nodoc:
309
324
  "#<#{self.class.name}:#{object_id} @config=#{@config} @options=#{@options}>"
310
325
  end
@@ -389,7 +404,7 @@ module RuboCop
389
404
  def use_corrector(range, corrector)
390
405
  if autocorrect?
391
406
  attempt_correction(range, corrector)
392
- elsif corrector && cop_config.fetch('AutoCorrect', true)
407
+ elsif corrector && (always_autocorrect? || (contextual_autocorrect? && !LSP.enabled?))
393
408
  :uncorrected
394
409
  else
395
410
  :unsupported
@@ -161,9 +161,9 @@ module RuboCop
161
161
  end
162
162
 
163
163
  def gem_options(node)
164
- return [] unless node.arguments.last&.type == :hash
164
+ return [] unless node.last_argument&.type == :hash
165
165
 
166
- node.arguments.last.keys.map(&:value)
166
+ node.last_argument.keys.map(&:value)
167
167
  end
168
168
  end
169
169
  end
@@ -34,18 +34,14 @@ module RuboCop
34
34
  end
35
35
 
36
36
  def offending_range
37
+ begin_range = block_node.source_range.begin
38
+
37
39
  if block_node.arguments?
38
- replacement_range(argument_node.source_range.end_pos)
40
+ begin_range.join(argument_node.source_range.end)
39
41
  else
40
- replacement_range(block_node.loc.begin.end_pos)
42
+ begin_range.join(block_node.loc.begin.end)
41
43
  end
42
44
  end
43
-
44
- def replacement_range(end_pos)
45
- Parser::Source::Range.new(block_node.source_range.source_buffer,
46
- block_node.source_range.begin_pos,
47
- end_pos)
48
- end
49
45
  end
50
46
  end
51
47
  end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  end
16
16
 
17
17
  def call(corrector)
18
+ offending_range = for_node.source_range.begin.join(end_range)
19
+
18
20
  corrector.replace(offending_range, correction)
19
21
  end
20
22
 
@@ -40,11 +42,11 @@ module RuboCop
40
42
  collection_node.range_type? || collection_node.or_type? || collection_node.and_type?
41
43
  end
42
44
 
43
- def end_position
45
+ def end_range
44
46
  if for_node.do?
45
- keyword_begin.end_pos
47
+ keyword_begin.end
46
48
  else
47
- collection_end.end_pos
49
+ collection_end.end
48
50
  end
49
51
  end
50
52
 
@@ -59,16 +61,6 @@ module RuboCop
59
61
  collection_node.source_range
60
62
  end
61
63
  end
62
-
63
- def offending_range
64
- replacement_range(end_position)
65
- end
66
-
67
- def replacement_range(end_pos)
68
- Parser::Source::Range.new(for_node.source_range.source_buffer,
69
- for_node.source_range.begin_pos,
70
- end_pos)
71
- end
72
64
  end
73
65
  end
74
66
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # The parameter name given is transformed into a method name (eg. `Max`
9
9
  # becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
10
10
  def exclude_limit(parameter_name, method_name: transform(parameter_name))
11
- define_method("#{method_name}=") do |value|
11
+ define_method(:"#{method_name}=") do |value|
12
12
  cfg = config_to_allow_offenses
13
13
  cfg[:exclude_limit] ||= {}
14
14
  current_max = cfg[:exclude_limit][parameter_name]
@@ -43,7 +43,7 @@ module RuboCop
43
43
  def on_block(block_node)
44
44
  return unless gem_specification(block_node)
45
45
 
46
- block_parameter = block_node.arguments.first.source
46
+ block_parameter = block_node.first_argument.source
47
47
 
48
48
  assignment = block_node.descendants.detect do |node|
49
49
  use_deprecated_attributes?(node, block_parameter)
@@ -65,7 +65,7 @@ module RuboCop
65
65
  lhs, _op, _rhs = *node
66
66
  [lhs, attribute]
67
67
  else
68
- [node, "#{attribute}=".to_sym]
68
+ [node, :"#{attribute}="]
69
69
  end
70
70
  end
71
71
 
@@ -76,7 +76,9 @@ module RuboCop
76
76
  PATTERN
77
77
 
78
78
  def on_new_investigation
79
- add_global_offense(MISSING_MSG) unless required_ruby_version?(processed_source.ast)
79
+ return if processed_source.ast && required_ruby_version?(processed_source.ast)
80
+
81
+ add_global_offense(MISSING_MSG)
80
82
  end
81
83
 
82
84
  def on_send(node)
@@ -110,6 +112,8 @@ module RuboCop
110
112
  end
111
113
  end
112
114
 
115
+ return unless required_ruby_version
116
+
113
117
  required_ruby_version.str_content.scan(/\d/).first(2).join('.')
114
118
  end
115
119
 
@@ -63,10 +63,10 @@ module RuboCop
63
63
  expect_correction: EXPECT_CORRECTION_DESCRIPTION_MAPPING
64
64
  }.freeze
65
65
 
66
- # @!method offense_example?(node)
67
- def_node_matcher :offense_example?, <<~PATTERN
66
+ # @!method offense_example(node)
67
+ def_node_matcher :offense_example, <<~PATTERN
68
68
  (block
69
- (send _ {:it :specify} $_description)
69
+ (send _ {:it :specify} $...)
70
70
  _args
71
71
  `(send nil? %RESTRICT_ON_SEND ...)
72
72
  )
@@ -74,7 +74,7 @@ module RuboCop
74
74
 
75
75
  def on_send(node)
76
76
  parent = node.each_ancestor(:block).first
77
- return unless parent && (current_description = offense_example?(parent))
77
+ return unless parent && (current_description = offense_example(parent)&.first)
78
78
 
79
79
  method_name = node.method_name
80
80
  message = format(MSG, method_name: method_name)
@@ -30,6 +30,7 @@ module RuboCop
30
30
  extend AutoCorrector
31
31
 
32
32
  MSG = 'Use `%<method_name>s` instead of `%<method_suffix>s`.'
33
+ RESTRICT_ON_SEND = %i[end_with?].freeze
33
34
  SUGGEST_METHOD_FOR_SUFFIX = {
34
35
  '=' => 'assignment_method?',
35
36
  '!' => 'bang_method?',
@@ -51,14 +52,15 @@ module RuboCop
51
52
 
52
53
  def on_send(node)
53
54
  method_name_end_with?(node) do |method_name_node, end_with_arg|
55
+ next unless method_name_node.receiver
56
+
57
+ preferred_method = SUGGEST_METHOD_FOR_SUFFIX[end_with_arg.value]
54
58
  range = range(method_name_node, node)
55
- message = format(
56
- MSG,
57
- method_name: SUGGEST_METHOD_FOR_SUFFIX[end_with_arg.value],
58
- method_suffix: range.source
59
- )
59
+ message = format(MSG, method_name: preferred_method, method_suffix: range.source)
60
60
 
61
- add_offense(range, message: message)
61
+ add_offense(range, message: message) do |corrector|
62
+ corrector.replace(range, preferred_method)
63
+ end
62
64
  end
63
65
  end
64
66
  alias on_csend on_send
@@ -12,38 +12,37 @@ module RuboCop
12
12
  # # good
13
13
  # node.method?(:do_something)
14
14
  #
15
+ # # bad
16
+ # node.method_name != :do_something
17
+ #
18
+ # # good
19
+ # !node.method?(:do_something)
20
+ #
15
21
  class MethodNameEqual < Base
16
- include RangeHelp
17
22
  extend AutoCorrector
18
23
 
19
- MSG = 'Use `method?(%<method_name>s)` instead of `method_name == %<method_name>s`.'
20
- RESTRICT_ON_SEND = %i[==].freeze
24
+ MSG = 'Use `%<prefer>s` instead.'
25
+ RESTRICT_ON_SEND = %i[== !=].freeze
21
26
 
22
- # @!method method_name?(node)
23
- def_node_matcher :method_name?, <<~PATTERN
27
+ # @!method method_name(node)
28
+ def_node_matcher :method_name, <<~PATTERN
24
29
  (send
25
- $(send
26
- (...) :method_name) :==
27
- $...)
30
+ (send
31
+ (...) :method_name) {:== :!=}
32
+ $_)
28
33
  PATTERN
29
34
 
30
35
  def on_send(node)
31
- method_name?(node) do |method_name_node, method_name_arg|
32
- message = format(MSG, method_name: method_name_arg.first.source)
36
+ method_name(node) do |method_name_arg|
37
+ bang = node.method?(:!=) ? '!' : ''
38
+ prefer = "#{bang}#{node.receiver.receiver.source}.method?(#{method_name_arg.source})"
39
+ message = format(MSG, prefer: prefer)
33
40
 
34
- range = range(method_name_node, node)
35
-
36
- add_offense(range, message: message) do |corrector|
37
- corrector.replace(range, "method?(#{method_name_arg.first.source})")
41
+ add_offense(node, message: message) do |corrector|
42
+ corrector.replace(node, prefer)
38
43
  end
39
44
  end
40
45
  end
41
-
42
- private
43
-
44
- def range(method_name_node, node)
45
- range_between(method_name_node.loc.selector.begin_pos, node.source_range.end_pos)
46
- end
47
46
  end
48
47
  end
49
48
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for the use of `node.arguments.first` or `node.arguments.last` and
7
+ # suggests the use of `node.first_argument` or `node.last_argument` instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.arguments.first
12
+ # node.arguments[0]
13
+ # node.arguments.last
14
+ # node.arguments[-1]
15
+ #
16
+ # # good
17
+ # node.first_argument
18
+ # node.last_argument
19
+ #
20
+ class NodeFirstOrLastArgument < Base
21
+ extend AutoCorrector
22
+ include RangeHelp
23
+
24
+ MSG = 'Use `#%<correct>s` instead of `#%<incorrect>s`.'
25
+ RESTRICT_ON_SEND = %i[arguments].freeze
26
+
27
+ # @!method arguments_first_or_last?(node)
28
+ def_node_matcher :arguments_first_or_last?, <<~PATTERN
29
+ {
30
+ (send (send !nil? :arguments) ${:first :last})
31
+ (send (send !nil? :arguments) :[] (int ${0 -1}))
32
+ }
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ arguments_first_or_last?(node.parent) do |end_or_index|
37
+ range = range_between(node.loc.selector.begin_pos, node.parent.source_range.end_pos)
38
+ correct = case end_or_index
39
+ when :first, 0 then 'first_argument'
40
+ when :last, -1 then 'last_argument'
41
+ else raise "Unknown end_or_index: #{end_or_index}"
42
+ end
43
+ message = format(MSG, correct: correct, incorrect: range.source)
44
+
45
+ add_offense(range, message: message) do |corrector|
46
+ corrector.replace(range, correct)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end