rubocop 1.69.2 → 1.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +36 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  7. data/lib/rubocop/comment_config.rb +1 -1
  8. data/lib/rubocop/config.rb +13 -4
  9. data/lib/rubocop/config_loader.rb +4 -0
  10. data/lib/rubocop/config_loader_resolver.rb +14 -3
  11. data/lib/rubocop/config_validator.rb +18 -8
  12. data/lib/rubocop/cop/base.rb +6 -0
  13. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  15. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  16. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  17. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  18. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  19. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +2 -1
  20. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  21. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  22. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  23. data/lib/rubocop/cop/layout/class_structure.rb +7 -7
  24. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  25. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  26. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  27. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
  28. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  29. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  30. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  31. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  32. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  33. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  34. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  35. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  36. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  37. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  38. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  39. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  40. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  41. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  42. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  43. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  44. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  45. data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
  46. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  47. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  48. data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
  49. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  50. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +23 -5
  51. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  52. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  53. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  54. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  55. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +17 -30
  56. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  57. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  58. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  60. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +7 -0
  61. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  62. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  63. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  64. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  65. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  66. data/lib/rubocop/cop/lint/void.rb +3 -2
  67. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  68. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  69. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  70. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  71. data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
  72. data/lib/rubocop/cop/mixin/comments_help.rb +2 -0
  73. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  74. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  75. data/lib/rubocop/cop/mixin/hash_subset.rb +170 -0
  76. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +26 -16
  77. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  78. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  79. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  80. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -2
  81. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  82. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  83. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
  84. data/lib/rubocop/cop/style/and_or.rb +1 -1
  85. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
  86. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  87. data/lib/rubocop/cop/style/block_delimiters.rb +6 -19
  88. data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
  89. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  90. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
  91. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  92. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  93. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  94. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  95. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  96. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  97. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  98. data/lib/rubocop/cop/style/float_division.rb +8 -4
  99. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  100. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
  101. data/lib/rubocop/cop/style/hash_except.rb +9 -148
  102. data/lib/rubocop/cop/style/hash_slice.rb +65 -0
  103. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  104. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  105. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  106. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
  107. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  108. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  109. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  110. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  111. data/lib/rubocop/cop/style/mutable_constant.rb +2 -2
  112. data/lib/rubocop/cop/style/object_then.rb +13 -15
  113. data/lib/rubocop/cop/style/open_struct_use.rb +4 -4
  114. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  115. data/lib/rubocop/cop/style/raise_args.rb +6 -4
  116. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  117. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  118. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  119. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  120. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  121. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  122. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -4
  123. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  124. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  125. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  126. data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
  127. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  128. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  129. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  130. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  131. data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
  132. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  133. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
  134. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  135. data/lib/rubocop/cop/style/super_arguments.rb +63 -15
  136. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  137. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  138. data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
  139. data/lib/rubocop/cop/util.rb +9 -2
  140. data/lib/rubocop/cops_documentation_generator.rb +13 -13
  141. data/lib/rubocop/directive_comment.rb +9 -8
  142. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  143. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  144. data/lib/rubocop/lsp/logger.rb +2 -2
  145. data/lib/rubocop/lsp/routes.rb +7 -23
  146. data/lib/rubocop/lsp/runtime.rb +15 -49
  147. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  148. data/lib/rubocop/options.rb +2 -1
  149. data/lib/rubocop/path_util.rb +11 -8
  150. data/lib/rubocop/result_cache.rb +13 -13
  151. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  152. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  153. data/lib/rubocop/runner.rb +5 -6
  154. data/lib/rubocop/target_finder.rb +1 -0
  155. data/lib/rubocop/target_ruby.rb +15 -0
  156. data/lib/rubocop/version.rb +1 -1
  157. data/lib/rubocop.rb +6 -0
  158. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  159. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  160. metadata +17 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45af4a986637b8c3dacb16d942870c2138501ae834e79c0875b81bbf09644b54
4
- data.tar.gz: 65961fc4cb25730ad9528201e22a82427def59f6ad5f048cd01a0ca89a437c3c
3
+ metadata.gz: 0f4339f6b223b2a7fd5f68764dd3030e5cb83925c0605414459ed0f3d2543510
4
+ data.tar.gz: 525042279be387c345b3efd57ed7ca976e3eda5b15ba9723485b72f3a083816e
5
5
  SHA512:
6
- metadata.gz: aa6eb7a2cbf39d99cbda0faff3dfe690a61e9665847c21669bc9a005f9ac316e9404a8babc8cadf7f033bf82afcf317c8c503ede2306e8b3a8c211abaa878cb9
7
- data.tar.gz: 126f20d27ebf2e0098d0a1039230fea4178d2a196693db8c75326a7f3fdc797b1f030af3d116f2d74f69bb70cc033372ede6836962b2c47632a9ecf4f524dd56
6
+ metadata.gz: 404c792e4624474f907576ef9c73fc3ee09a5736c63becf75197fe40d5e9fdefb7c2cb6bc22326857d3b5065f50badd1a6a4d8f7cecd219fb6ec7280bb95a97a
7
+ data.tar.gz: 6e3071938d0f6d7850a732c41ce55890c6a2ba8bcd352df28203c136453cf249fd21a10c9c3d1ea7762376466a669a287efb56c8b7505877d8b17cacdd5dd059
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-24 Bozhidar Batsov
1
+ Copyright (c) 2012-25 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
52
52
  in your `Gemfile`:
53
53
 
54
54
  ```rb
55
- gem 'rubocop', '~> 1.69', require: false
55
+ gem 'rubocop', '~> 1.71', require: false
56
56
  ```
57
57
 
58
58
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -247,5 +247,5 @@ RuboCop's changelog is available [here](CHANGELOG.md).
247
247
 
248
248
  ## Copyright
249
249
 
250
- Copyright (c) 2012-2024 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
250
+ Copyright (c) 2012-2025 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
251
251
  further details.
data/config/default.yml CHANGED
@@ -1616,6 +1616,12 @@ Lint/AmbiguousRegexpLiteral:
1616
1616
  VersionAdded: '0.17'
1617
1617
  VersionChanged: '0.83'
1618
1618
 
1619
+ Lint/ArrayLiteralInRegexp:
1620
+ Description: 'Checks for an array literal interpolated inside a regexp.'
1621
+ Enabled: pending
1622
+ VersionAdded: '1.71'
1623
+ SafeAutoCorrect: false
1624
+
1619
1625
  Lint/AssignmentInCondition:
1620
1626
  Description: "Don't use assignment in conditions."
1621
1627
  StyleGuide: '#safe-assignment-in-condition'
@@ -1665,6 +1671,11 @@ Lint/ConstantOverwrittenInRescue:
1665
1671
  Enabled: pending
1666
1672
  VersionAdded: '1.31'
1667
1673
 
1674
+ Lint/ConstantReassignment:
1675
+ Description: 'Checks for constant reassignments.'
1676
+ Enabled: pending
1677
+ VersionAdded: '1.70'
1678
+
1668
1679
  Lint/ConstantResolution:
1669
1680
  Description: 'Check that constants are fully qualified with `::`.'
1670
1681
  Enabled: false
@@ -2402,6 +2413,12 @@ Lint/ShadowingOuterLocalVariable:
2402
2413
  Enabled: true
2403
2414
  VersionAdded: '0.9'
2404
2415
 
2416
+ Lint/SharedMutableDefault:
2417
+ Description: 'Checks for mutable literals used as default arguments during Hash initialization.'
2418
+ StyleGuide: '#no-mutable-defaults'
2419
+ Enabled: pending
2420
+ VersionAdded: '1.70'
2421
+
2405
2422
  Lint/StructNewOverride:
2406
2423
  Description: 'Disallow overriding the `Struct` built-in methods via `Struct.new`.'
2407
2424
  Enabled: true
@@ -3136,13 +3153,14 @@ Style/AccessModifierDeclarations:
3136
3153
  Description: 'Checks style of how access modifiers are used.'
3137
3154
  Enabled: true
3138
3155
  VersionAdded: '0.57'
3139
- VersionChanged: '0.81'
3156
+ VersionChanged: '1.70'
3140
3157
  EnforcedStyle: group
3141
3158
  SupportedStyles:
3142
3159
  - inline
3143
3160
  - group
3144
3161
  AllowModifiersOnSymbols: true
3145
3162
  AllowModifiersOnAttrs: true
3163
+ AllowModifiersOnAliasMethod: true
3146
3164
  SafeAutoCorrect: false
3147
3165
 
3148
3166
  Style/AccessorGrouping:
@@ -4051,6 +4069,9 @@ Style/FrozenStringLiteralComment:
4051
4069
  # exist in a file.
4052
4070
  - never
4053
4071
  SafeAutoCorrect: false
4072
+ Exclude:
4073
+ # Prevent the Ruby warning: `'frozen_string_literal' is ignored after any tokens` when using Active Admin.
4074
+ - '**/*.arb'
4054
4075
 
4055
4076
  Style/GlobalStdStream:
4056
4077
  Description: 'Enforces the use of `$stdout/$stderr/$stdin` instead of `STDOUT/STDERR/STDIN`.'
@@ -4129,6 +4150,14 @@ Style/HashLikeCase:
4129
4150
  # to trigger this cop
4130
4151
  MinBranchesCount: 3
4131
4152
 
4153
+ Style/HashSlice:
4154
+ Description: >-
4155
+ Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
4156
+ that can be replaced with `Hash#slice` method.
4157
+ Enabled: pending
4158
+ Safe: false
4159
+ VersionAdded: '1.71'
4160
+
4132
4161
  Style/HashSyntax:
4133
4162
  Description: >-
4134
4163
  Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax
@@ -4316,6 +4345,11 @@ Style/IpAddresses:
4316
4345
  - '**/gems.rb'
4317
4346
  - '**/*.gemspec'
4318
4347
 
4348
+ Style/ItAssignment:
4349
+ Description: 'Checks for assignment to `it` inside a block.'
4350
+ Enabled: pending
4351
+ VersionAdded: '1.70'
4352
+
4319
4353
  Style/KeywordArgumentsMerging:
4320
4354
  Description: >-
4321
4355
  When passing an existing hash as keyword arguments, provide additional arguments
@@ -5059,7 +5093,7 @@ Style/RedundantConstantBase:
5059
5093
  VersionAdded: '1.40'
5060
5094
 
5061
5095
  Style/RedundantCurrentDirectoryInPath:
5062
- Description: 'Checks for uses a redundant current directory in path.'
5096
+ Description: 'Checks for a redundant current directory in a path given to `require_relative`.'
5063
5097
  Enabled: pending
5064
5098
  VersionAdded: '1.53'
5065
5099
 
@@ -71,11 +71,11 @@ module RuboCop
71
71
 
72
72
  warn Rainbow("\n#{pluralize(errors.size, 'error')} occurred:").red
73
73
 
74
- errors.each { |error| warn error }
74
+ errors.each { |error| warn Rainbow(error).red }
75
75
 
76
- warn <<~WARNING
76
+ warn Rainbow(<<~WARNING.strip).yellow
77
77
  Errors are usually caused by RuboCop bugs.
78
- Please, report your problems to RuboCop's issue tracker.
78
+ Please, update to the latest RuboCop version if not already in use, and report a bug if the issue still occurs on this version.
79
79
  #{bug_tracker_uri}
80
80
  Mention the following information in the issue report:
81
81
  #{RuboCop::Version.verbose}
@@ -9,11 +9,31 @@ module RuboCop
9
9
  class ShowCops < Base
10
10
  self.command_name = :show_cops
11
11
 
12
+ ExactMatcher = Struct.new(:pattern) do
13
+ def match?(name)
14
+ name == pattern
15
+ end
16
+ end
17
+
18
+ WildcardMatcher = Struct.new(:pattern) do
19
+ def match?(name)
20
+ File.fnmatch(pattern, name, File::FNM_PATHNAME)
21
+ end
22
+ end
23
+
12
24
  def initialize(env)
13
25
  super
14
26
 
15
27
  # Load the configs so the require()s are done for custom cops
16
28
  @config = @config_store.for(Dir.pwd)
29
+
30
+ @cop_matchers = @options[:show_cops].map do |pattern|
31
+ if pattern.include?('*')
32
+ WildcardMatcher.new(pattern)
33
+ else
34
+ ExactMatcher.new(pattern)
35
+ end
36
+ end
17
37
  end
18
38
 
19
39
  def run
@@ -24,7 +44,7 @@ module RuboCop
24
44
 
25
45
  def print_available_cops
26
46
  registry = Cop::Registry.global
27
- show_all = @options[:show_cops].empty?
47
+ show_all = @cop_matchers.empty?
28
48
 
29
49
  puts "# Available cops (#{registry.length}) + config for #{Dir.pwd}: " if show_all
30
50
 
@@ -56,7 +76,9 @@ module RuboCop
56
76
 
57
77
  def selected_cops_of_department(cops, department)
58
78
  cops_of_department(cops, department).select do |cop|
59
- @options[:show_cops].include?(cop.cop_name)
79
+ @cop_matchers.any? do |matcher|
80
+ matcher.match?(cop.cop_name)
81
+ end
60
82
  end
61
83
  end
62
84
 
@@ -87,7 +87,7 @@ module RuboCop
87
87
  next unless directive.enabled?
88
88
  next if directive.all_cops?
89
89
 
90
- cops.merge(directive.cop_names)
90
+ cops.merge(directive.raw_cop_names)
91
91
  end
92
92
  cops
93
93
  end
@@ -16,6 +16,7 @@ module RuboCop
16
16
 
17
17
  CopConfig = Struct.new(:name, :metadata)
18
18
 
19
+ EMPTY_CONFIG = {}.freeze
19
20
  DEFAULT_RAILS_VERSION = 5.0
20
21
  attr_reader :loaded_path
21
22
 
@@ -80,10 +81,7 @@ module RuboCop
80
81
 
81
82
  def make_excludes_absolute
82
83
  each_key do |key|
83
- @validator.validate_section_presence(key)
84
- next unless self[key]['Exclude']
85
-
86
- self[key]['Exclude'].map! do |exclude_elem|
84
+ dig(key, 'Exclude')&.map! do |exclude_elem|
87
85
  if exclude_elem.is_a?(String) && !absolute?(exclude_elem)
88
86
  File.expand_path(File.join(base_dir_for_path_parameters, exclude_elem))
89
87
  else
@@ -123,6 +121,13 @@ module RuboCop
123
121
  @for_cop[cop]
124
122
  end
125
123
 
124
+ # @return [Config, Hash] for the given cop / cop name.
125
+ # If the given cop is enabled, returns its configuration hash.
126
+ # Otherwise, returns an empty hash.
127
+ def for_enabled_cop(cop)
128
+ cop_enabled?(cop) ? for_cop(cop) : EMPTY_CONFIG
129
+ end
130
+
126
131
  # @return [Config] for the given cop merged with that of its department (if any)
127
132
  # Note: the 'Enabled' attribute is same as that returned by `for_cop`
128
133
  def for_badge(badge)
@@ -159,6 +164,10 @@ module RuboCop
159
164
  @for_all_cops ||= self['AllCops'] || {}
160
165
  end
161
166
 
167
+ def cop_enabled?(name)
168
+ !!for_cop(name)['Enabled']
169
+ end
170
+
162
171
  def disabled_new_cops?
163
172
  for_all_cops['NewCops'] == 'disable'
164
173
  end
@@ -41,6 +41,10 @@ module RuboCop
41
41
  def clear_options
42
42
  @debug = nil
43
43
  @loaded_features = Set.new
44
+ @disable_pending_cops = nil
45
+ @enable_pending_cops = nil
46
+ @ignore_parent_exclusion = nil
47
+ @ignore_unrecognized_cops = nil
44
48
  FileFinder.root_level = nil
45
49
  end
46
50
 
@@ -163,14 +163,21 @@ module RuboCop
163
163
  end
164
164
 
165
165
  def warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
166
+ # If the file being considered is remote, don't bother checking for duplicates
167
+ return if remote_config?(opts[:file])
168
+
166
169
  return unless duplicate_setting?(base_hash, derived_hash, key, opts[:inherited_file])
167
170
 
168
171
  inherit_mode = opts[:inherit_mode]['merge'] || opts[:inherit_mode]['override']
169
172
  return if base_hash[key].is_a?(Array) && inherit_mode&.include?(key)
170
173
 
171
- puts "#{PathUtil.smart_path(opts[:file])}: " \
172
- "#{opts[:cop_name]}:#{key} overrides " \
173
- "the same parameter in #{opts[:inherited_file]}"
174
+ puts duplicate_setting_warning(opts, key)
175
+ end
176
+
177
+ def duplicate_setting_warning(opts, key)
178
+ "#{PathUtil.smart_path(opts[:file])}: " \
179
+ "#{opts[:cop_name]}:#{key} overrides " \
180
+ "the same parameter in #{opts[:inherited_file]}"
174
181
  end
175
182
 
176
183
  def determine_inherit_mode(hash, key)
@@ -242,6 +249,10 @@ module RuboCop
242
249
  uri.start_with?('http://', 'https://')
243
250
  end
244
251
 
252
+ def remote_config?(file)
253
+ file.is_a?(RemoteConfig)
254
+ end
255
+
245
256
  def handle_disabled_by_default(config, new_default_configuration)
246
257
  department_config = config.to_hash.reject { |cop| cop.include?('/') }
247
258
  department_config.each do |dept, dept_params|
@@ -3,6 +3,7 @@
3
3
  module RuboCop
4
4
  # Handles validation of configuration, for example cop names, parameter
5
5
  # names, and Ruby versions.
6
+ # rubocop:disable Metrics/ClassLength
6
7
  class ConfigValidator
7
8
  extend SimpleForwardable
8
9
 
@@ -41,8 +42,9 @@ module RuboCop
41
42
  ConfigLoader.default_configuration.key?(key)
42
43
  end
43
44
 
44
- check_obsoletions
45
+ validate_parameter_shape(valid_cop_names)
45
46
 
47
+ check_obsoletions
46
48
  alert_about_unrecognized_cops(invalid_cop_names)
47
49
  validate_new_cops_parameter
48
50
  validate_parameter_names(valid_cop_names)
@@ -64,12 +66,6 @@ module RuboCop
64
66
  target_ruby.version
65
67
  end
66
68
 
67
- def validate_section_presence(name)
68
- return unless @config.key?(name) && @config[name].nil?
69
-
70
- raise ValidationError, "empty section #{name} found in #{smart_loaded_path}"
71
- end
72
-
73
69
  private
74
70
 
75
71
  attr_reader :target_ruby
@@ -177,9 +173,22 @@ module RuboCop
177
173
  raise ValidationError, message
178
174
  end
179
175
 
176
+ def validate_parameter_shape(valid_cop_names)
177
+ valid_cop_names.each do |name|
178
+ if @config[name].nil?
179
+ raise ValidationError, "empty section #{name.inspect} found in #{smart_loaded_path}"
180
+ elsif !@config[name].is_a?(Hash)
181
+ raise ValidationError, <<~MESSAGE
182
+ The configuration for #{name.inspect} in #{smart_loaded_path} is not a Hash.
183
+
184
+ Found: #{@config[name].inspect}
185
+ MESSAGE
186
+ end
187
+ end
188
+ end
189
+
180
190
  def validate_parameter_names(valid_cop_names)
181
191
  valid_cop_names.each do |name|
182
- validate_section_presence(name)
183
192
  each_invalid_parameter(name) do |param, supported_params|
184
193
  warn Rainbow(<<~MESSAGE).yellow
185
194
  Warning: #{name} does not support #{param} parameter.
@@ -277,4 +286,5 @@ module RuboCop
277
286
  "is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
278
287
  end
279
288
  end
289
+ # rubocop:enable Metrics/ClassLength
280
290
  end
@@ -261,6 +261,12 @@ module RuboCop
261
261
  @config.target_ruby_version
262
262
  end
263
263
 
264
+ # Returns a gems locked versions (i.e. from Gemfile.lock or gems.locked)
265
+ # @returns [Gem::Version | nil] The locked gem version, or nil if the gem is not present.
266
+ def target_gem_version(gem_name)
267
+ @config.gem_versions_in_target && @config.gem_versions_in_target[gem_name]
268
+ end
269
+
264
270
  def parser_engine
265
271
  @config.parser_engine
266
272
  end
@@ -161,7 +161,7 @@ module RuboCop
161
161
  end
162
162
 
163
163
  def gem_options(node)
164
- return [] unless node.last_argument&.type == :hash
164
+ return [] unless node.last_argument&.hash_type?
165
165
 
166
166
  node.last_argument.keys.map(&:value)
167
167
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Use `config.cop_enabled?('Department/CopName')` instead of
7
+ # traversing the config hash.
8
+ #
9
+ # @example
10
+ # # `for_cop(...)['Enabled']
11
+ #
12
+ # # bad
13
+ # config.for_cop('Department/CopName')['Enabled']
14
+ #
15
+ # # good
16
+ # config.cop_enabled?('Department/CopName')
17
+ #
18
+ # @example
19
+ # # when keeping a cop's config in a local and then checking the `Enabled` key
20
+ #
21
+ # # bad
22
+ # cop_config = config.for_cop('Department/CopName')
23
+ # cop_config['Enabled'] && cop_config['Foo']
24
+ #
25
+ # # good
26
+ # config.for_enabled_cop('Department/CopName')['Foo']
27
+ #
28
+ class CopEnabled < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
32
+ MSG_HASH = 'Consider replacing uses of `%<hash_name>s` with `config.for_enabled_cop`.'
33
+
34
+ RESTRICT_ON_SEND = [:[]].freeze
35
+
36
+ # @!method for_cop_enabled?(node)
37
+ def_node_matcher :for_cop_enabled?, <<~PATTERN
38
+ (send
39
+ (send
40
+ ${(send nil? :config) (ivar :@config)} :for_cop
41
+ $(str _)) :[]
42
+ (str "Enabled"))
43
+ PATTERN
44
+
45
+ # @!method config_enabled_lookup?(node)
46
+ def_node_matcher :config_enabled_lookup?, <<~PATTERN
47
+ (send
48
+ {(lvar $_) (ivar $_) (send nil? $_)} :[]
49
+ (str "Enabled"))
50
+ PATTERN
51
+
52
+ def on_send(node)
53
+ if (config_var, cop_name = for_cop_enabled?(node))
54
+ handle_for_cop(node, config_var, cop_name)
55
+ elsif (config_var = config_enabled_lookup?(node))
56
+ return unless config_var.end_with?('_config')
57
+
58
+ handle_hash(node, config_var)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def handle_for_cop(node, config_var, cop_name)
65
+ source = node.source
66
+ quote = cop_name.loc.begin.source
67
+ cop_name = cop_name.value
68
+
69
+ replacement = "#{config_var.source}.cop_enabled?(#{quote}#{cop_name}#{quote})"
70
+ message = format(MSG, source: source, replacement: replacement)
71
+
72
+ add_offense(node, message: message) do |corrector|
73
+ corrector.replace(node, replacement)
74
+ end
75
+ end
76
+
77
+ def handle_hash(node, config_var)
78
+ message = format(MSG_HASH, hash_name: config_var)
79
+
80
+ add_offense(node, message: message)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -22,7 +22,7 @@ module RuboCop
22
22
 
23
23
  def on_send(node)
24
24
  return unless (parent = node.parent)
25
- return unless parent.send_type? && parent.method?(:expression)
25
+ return unless parent.call_type? && parent.method?(:expression)
26
26
  return unless parent.receiver.receiver
27
27
 
28
28
  offense = node.loc.selector.join(parent.source_range.end)
@@ -31,6 +31,7 @@ module RuboCop
31
31
  corrector.replace(offense, 'source_range')
32
32
  end
33
33
  end
34
+ alias on_csend on_send
34
35
  end
35
36
  end
36
37
  end
@@ -27,8 +27,8 @@ module RuboCop
27
27
  # @!method arguments_first_or_last?(node)
28
28
  def_node_matcher :arguments_first_or_last?, <<~PATTERN
29
29
  {
30
- (send (send !nil? :arguments) ${:first :last})
31
- (send (send !nil? :arguments) :[] (int ${0 -1}))
30
+ (call (call !nil? :arguments) ${:first :last})
31
+ (call (call !nil? :arguments) :[] (int ${0 -1}))
32
32
  }
33
33
  PATTERN
34
34
 
@@ -47,6 +47,7 @@ module RuboCop
47
47
  end
48
48
  end
49
49
  end
50
+ alias on_csend on_send
50
51
  end
51
52
  end
52
53
  end
@@ -21,16 +21,17 @@ module RuboCop
21
21
 
22
22
  # @!method node_type_check(node)
23
23
  def_node_matcher :node_type_check, <<~PATTERN
24
- (send (send $_ :type) :== (sym $_))
24
+ (send (call _ :type) :== (sym $_))
25
25
  PATTERN
26
26
 
27
27
  def on_send(node)
28
- node_type_check(node) do |receiver, node_type|
28
+ node_type_check(node) do |node_type|
29
29
  return unless Parser::Meta::NODE_TYPES.include?(node_type)
30
30
 
31
31
  message = format(MSG, type: node_type)
32
32
  add_offense(node, message: message) do |corrector|
33
- range = node.source_range.with(begin_pos: receiver.source_range.end_pos + 1)
33
+ range = node.receiver.loc.selector.join(node.source_range.end)
34
+
34
35
  corrector.replace(range, "#{node_type}_type?")
35
36
  end
36
37
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for cops that define `on_send` without define `on_csend`.
7
+ #
8
+ # Although in some cases it can be predetermined that safe navigation
9
+ # will never be used with the code checked by a specific cop, in general
10
+ # it is good practice to handle safe navigation methods if handling any
11
+ # `send` node.
12
+ #
13
+ # NOTE: It is expected to disable this cop for cops that check for method calls
14
+ # on receivers that cannot be nil (`self`, a literal, a constant), and
15
+ # method calls that will never have a receiver (ruby keywords like `raise`,
16
+ # macros like `attr_reader`, DSL methods, etc.), and other checks that wouldn't
17
+ # make sense to support safe navigation.
18
+ #
19
+ # @example
20
+ # # bad
21
+ # class MyCop < RuboCop::Cop:Base
22
+ # def on_send(node)
23
+ # # ...
24
+ # end
25
+ # end
26
+ #
27
+ # # good - explicit method definition
28
+ # class MyCop < RuboCop::Cop:Base
29
+ # def on_send(node)
30
+ # # ...
31
+ # end
32
+ #
33
+ # def on_csend(node)
34
+ # # ...
35
+ # end
36
+ # end
37
+ #
38
+ # # good - alias
39
+ # class MyCop < RuboCop::Cop:Base
40
+ # def on_send(node)
41
+ # # ...
42
+ # end
43
+ # alias on_csend on_send
44
+ # end
45
+ #
46
+ # # good - alias_method
47
+ # class MyCop < RuboCop::Cop:Base
48
+ # def on_send(node)
49
+ # # ...
50
+ # end
51
+ # alias_method :on_csend, :on_send
52
+ # end
53
+ class OnSendWithoutOnCSend < Base
54
+ RESTRICT_ON_SEND = %i[alias_method].freeze
55
+ MSG = 'Cop defines `on_send` but not `on_csend`.'
56
+
57
+ def on_new_investigation
58
+ @on_send_definition = nil
59
+ @on_csend_definition = nil
60
+ end
61
+
62
+ def on_investigation_end
63
+ return unless @on_send_definition && !@on_csend_definition
64
+
65
+ add_offense(@on_send_definition)
66
+ end
67
+
68
+ def on_def(node)
69
+ @on_send_definition = node if node.method?(:on_send)
70
+ @on_csend_definition = node if node.method?(:on_csend)
71
+ end
72
+
73
+ def on_alias(node)
74
+ @on_send_definition = node if node.new_identifier.value == :on_send
75
+ @on_csend_definition = node if node.new_identifier.value == :on_csend
76
+ end
77
+
78
+ def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
79
+ new_identifier = node.first_argument
80
+ return unless new_identifier.basic_literal?
81
+
82
+ new_identifier = new_identifier.value
83
+
84
+ @on_send_definition = node if new_identifier == :on_send
85
+ @on_csend_definition = node if new_identifier == :on_csend
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # @!method redundant_source_range(node)
48
48
  def_node_matcher :redundant_source_range, <<~PATTERN
49
49
  {
50
- (send $(send _ :source_range) :source)
50
+ (call $(call _ :source_range) :source)
51
51
  (send nil? :add_offense $(send _ :source_range) ...)
52
52
  (send _ {
53
53
  :replace :insert_before :insert_before_multi :insert_after :insert_after_multi
@@ -67,6 +67,7 @@ module RuboCop
67
67
  corrector.remove(source_range.loc.dot.join(selector))
68
68
  end
69
69
  end
70
+ alias on_csend on_send
70
71
  end
71
72
  end
72
73
  end
@@ -34,8 +34,8 @@ module RuboCop
34
34
  # @!method single_line_comparison(node)
35
35
  def_node_matcher :single_line_comparison, <<~PATTERN
36
36
  {
37
- (send (send $_receiver {:line :first_line}) {:== :!=} (send _receiver :last_line))
38
- (send (send $_receiver :last_line) {:== :!=} (send _receiver {:line :first_line}))
37
+ (send (call $_receiver {:line :first_line}) {:== :!=} (call _receiver :last_line))
38
+ (send (call $_receiver :last_line) {:== :!=} (call _receiver {:line :first_line}))
39
39
  }
40
40
  PATTERN
41
41
 
@@ -43,7 +43,8 @@ module RuboCop
43
43
  return unless (receiver = single_line_comparison(node))
44
44
 
45
45
  bang = node.method?(:!=) ? '!' : ''
46
- preferred = "#{bang}#{extract_receiver(receiver)}.single_line?"
46
+ dot = receiver.parent.loc.dot.source
47
+ preferred = "#{bang}#{extract_receiver(receiver)}#{dot}single_line?"
47
48
 
48
49
  add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
49
50
  corrector.replace(node, preferred)
@@ -53,7 +54,7 @@ module RuboCop
53
54
  private
54
55
 
55
56
  def extract_receiver(node)
56
- node = node.receiver if node.send_type? && %i[loc source_range].include?(node.method_name)
57
+ node = node.receiver if node.call_type? && %i[loc source_range].include?(node.method_name)
57
58
  node.source
58
59
  end
59
60
  end