rubocop 0.69.0 → 0.70.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +17 -1
  4. data/lib/rubocop.rb +1 -0
  5. data/lib/rubocop/ast/builder.rb +37 -37
  6. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +10 -0
  7. data/lib/rubocop/cached_data.rb +2 -2
  8. data/lib/rubocop/config.rb +9 -1
  9. data/lib/rubocop/config_loader.rb +2 -2
  10. data/lib/rubocop/config_loader_resolver.rb +3 -2
  11. data/lib/rubocop/cop/generator.rb +7 -1
  12. data/lib/rubocop/cop/layout/align_hash.rb +74 -31
  13. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +6 -6
  14. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +75 -4
  15. data/lib/rubocop/cop/layout/indentation_width.rb +1 -7
  16. data/lib/rubocop/cop/lint/ambiguous_operator.rb +5 -5
  17. data/lib/rubocop/cop/lint/handle_exceptions.rb +47 -8
  18. data/lib/rubocop/cop/lint/number_conversion.rb +7 -0
  19. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +3 -0
  20. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  21. data/lib/rubocop/cop/mixin/configurable_numbering.rb +2 -2
  22. data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +19 -0
  23. data/lib/rubocop/cop/rails/refute_methods.rb +13 -13
  24. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -3
  25. data/lib/rubocop/cop/variable_force/scope.rb +3 -3
  26. data/lib/rubocop/formatter/formatter_set.rb +13 -13
  27. data/lib/rubocop/formatter/html_formatter.rb +4 -4
  28. data/lib/rubocop/formatter/json_formatter.rb +16 -16
  29. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -4
  30. data/lib/rubocop/options.rb +89 -83
  31. data/lib/rubocop/version.rb +1 -1
  32. metadata +4 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ceeff27cb7a9a5422da99021b22d3d729445de0cfc8db0fcd451a7b59644564
4
- data.tar.gz: 975afb9f919e4b698091be763cbe0ae668aff0a76e79eea297eaf46113156049
3
+ metadata.gz: f98c70ae4897b3f4c793fa73cb716986f9d63815928c278accf6879a0190e97e
4
+ data.tar.gz: 89111e2312bdf926aab76ca58bfb90a414ff3b5f58ba48257e5d1949763d4776
5
5
  SHA512:
6
- metadata.gz: 502807f9a65b63922679174a7e32e7232d1191ea30b06199811f2c7485cdd47b02548a576f88e6bbadee9ed5e2a525eec570674d6b69fdfe5bfa2843edad465f
7
- data.tar.gz: fdd08613fb4d3292b99f2b9764df4b91981b5c31300c879cfdd80203f2965b8994187dff36f79e0c16c38665f9b76bf93ad57f1b0df834a42ffe9aa057f82070
6
+ metadata.gz: 83462908a6383ab72503c4af338d395a118e435d8f4f73e7cdda54b6d8d1cc05f40a5ebdb6a3197bf9a2734046665c7c2d6616e0bb0847f198d11b410ae4b7f8
7
+ data.tar.gz: 39c1a0fca5a9251e3a60f9ca3958d228d79f5797de21da608f69cb133611c683913673bbdc426a537c9578bc4394607a20617d394d1abc3454878373589a0fdd
data/README.md CHANGED
@@ -53,7 +53,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you
53
53
  might want to use a conservative version lock in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 0.69.0', require: false
56
+ gem 'rubocop', '~> 0.70.0', require: false
57
57
  ```
58
58
 
59
59
  ## Quickstart
@@ -260,6 +260,7 @@ Layout/AlignHash:
260
260
  Align the elements of a hash literal if they span more than
261
261
  one line.
262
262
  Enabled: true
263
+ AllowMultipleStyles: true
263
264
  VersionAdded: '0.49'
264
265
  # Alignment of entries using hash rocket as separator. Valid values are:
265
266
  #
@@ -508,6 +509,13 @@ Layout/EmptyLinesAroundAccessModifier:
508
509
  StyleGuide: '#empty-lines-around-access-modifier'
509
510
  Enabled: true
510
511
  VersionAdded: '0.49'
512
+ EnforcedStyle: around
513
+ SupportedStyles:
514
+ - around
515
+ - only_before
516
+ Reference:
517
+ # A reference to `EnforcedStyle: only_before`.
518
+ - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions
511
519
 
512
520
  Layout/EmptyLinesAroundArguments:
513
521
  Description: "Keeps track of empty lines around method arguments."
@@ -780,6 +788,9 @@ Layout/IndentationConsistency:
780
788
  SupportedStyles:
781
789
  - normal
782
790
  - rails
791
+ Reference:
792
+ # A reference to `EnforcedStyle: rails`.
793
+ - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions
783
794
 
784
795
  Layout/IndentationWidth:
785
796
  Description: 'Use 2 spaces for indentation.'
@@ -1359,7 +1370,9 @@ Lint/HandleExceptions:
1359
1370
  Description: "Don't suppress exception."
1360
1371
  StyleGuide: '#dont-hide-exceptions'
1361
1372
  Enabled: true
1373
+ AllowComments: false
1362
1374
  VersionAdded: '0.9'
1375
+ VersionChanged: '0.70'
1363
1376
 
1364
1377
  Lint/HeredocMethodCallPosition:
1365
1378
  Description: >-
@@ -1462,6 +1475,8 @@ Lint/NumberConversion:
1462
1475
  Description: 'Checks unsafe usage of number conversion methods.'
1463
1476
  Enabled: false
1464
1477
  VersionAdded: '0.53'
1478
+ VersionChanged: '0.70'
1479
+ SafeAutoCorrect: false
1465
1480
 
1466
1481
  Lint/OrderedMagicComments:
1467
1482
  Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
@@ -3752,8 +3767,9 @@ Style/PreferredHashMethods:
3752
3767
  Description: 'Checks use of `has_key?` and `has_value?` Hash methods.'
3753
3768
  StyleGuide: '#hash-key'
3754
3769
  Enabled: true
3770
+ Safe: false
3755
3771
  VersionAdded: '0.41'
3756
- VersionChanged: '0.44'
3772
+ VersionChanged: '0.70'
3757
3773
  EnforcedStyle: short
3758
3774
  SupportedStyles:
3759
3775
  - short
@@ -117,6 +117,7 @@ require_relative 'rubocop/cop/mixin/frozen_string_literal'
117
117
  require_relative 'rubocop/cop/mixin/hash_alignment'
118
118
  require_relative 'rubocop/cop/mixin/ignored_pattern'
119
119
  require_relative 'rubocop/cop/mixin/ignored_methods'
120
+ require_relative 'rubocop/cop/mixin/ignored_method_patterns'
120
121
  require_relative 'rubocop/cop/mixin/integer_node'
121
122
  require_relative 'rubocop/cop/mixin/match_range'
122
123
  require_relative 'rubocop/cop/mixin/method_complexity'
@@ -15,45 +15,45 @@ module RuboCop
15
15
  # root_node = parser.parse(buffer)
16
16
  class Builder < Parser::Builders::Default
17
17
  NODE_MAP = {
18
- and: AndNode,
19
- alias: AliasNode,
20
- args: ArgsNode,
21
- array: ArrayNode,
22
- block: BlockNode,
23
- break: BreakNode,
24
- case: CaseNode,
25
- class: ClassNode,
26
- def: DefNode,
27
- defined?: DefinedNode,
28
- defs: DefNode,
29
- ensure: EnsureNode,
30
- for: ForNode,
31
- hash: HashNode,
32
- if: IfNode,
33
- irange: RangeNode,
34
- erange: RangeNode,
35
- kwsplat: KeywordSplatNode,
36
- module: ModuleNode,
37
- or: OrNode,
38
- pair: PairNode,
39
- regexp: RegexpNode,
40
- resbody: ResbodyNode,
41
- retry: RetryNode,
42
- csend: SendNode,
43
- send: SendNode,
44
- str: StrNode,
45
- dstr: StrNode,
46
- xstr: StrNode,
47
- sclass: SelfClassNode,
48
- super: SuperNode,
49
- zsuper: SuperNode,
50
- sym: SymbolNode,
51
- until: UntilNode,
18
+ and: AndNode,
19
+ alias: AliasNode,
20
+ args: ArgsNode,
21
+ array: ArrayNode,
22
+ block: BlockNode,
23
+ break: BreakNode,
24
+ case: CaseNode,
25
+ class: ClassNode,
26
+ def: DefNode,
27
+ defined?: DefinedNode,
28
+ defs: DefNode,
29
+ ensure: EnsureNode,
30
+ for: ForNode,
31
+ hash: HashNode,
32
+ if: IfNode,
33
+ irange: RangeNode,
34
+ erange: RangeNode,
35
+ kwsplat: KeywordSplatNode,
36
+ module: ModuleNode,
37
+ or: OrNode,
38
+ pair: PairNode,
39
+ regexp: RegexpNode,
40
+ resbody: ResbodyNode,
41
+ retry: RetryNode,
42
+ csend: SendNode,
43
+ send: SendNode,
44
+ str: StrNode,
45
+ dstr: StrNode,
46
+ xstr: StrNode,
47
+ sclass: SelfClassNode,
48
+ super: SuperNode,
49
+ zsuper: SuperNode,
50
+ sym: SymbolNode,
51
+ until: UntilNode,
52
52
  until_post: UntilNode,
53
- when: WhenNode,
54
- while: WhileNode,
53
+ when: WhenNode,
54
+ while: WhileNode,
55
55
  while_post: WhileNode,
56
- yield: YieldNode
56
+ yield: YieldNode
57
57
  }.freeze
58
58
 
59
59
  # Generates {Node} from the given information.
@@ -9,6 +9,7 @@ module RuboCop
9
9
  include MethodIdentifierPredicates
10
10
 
11
11
  ARITHMETIC_OPERATORS = %i[+ - * / % **].freeze
12
+ SPECIAL_MODIFIERS = %w[private protected].freeze
12
13
 
13
14
  # The receiving node of the method dispatch.
14
15
  #
@@ -75,6 +76,15 @@ module RuboCop
75
76
  macro? && non_bare_access_modifier_declaration?
76
77
  end
77
78
 
79
+ # Checks whether the dispatched method is a bare `private` or `protected`
80
+ # access modifier that affects all methods defined after the macro.
81
+ #
82
+ # @return [Boolean] whether the dispatched method is a bare
83
+ # `private` or `protected` access modifier
84
+ def special_modifier?
85
+ bare_access_modifier? && SPECIAL_MODIFIERS.include?(source)
86
+ end
87
+
78
88
  # Checks whether the name of the dispatched method matches the argument
79
89
  # and has an implicit receiver.
80
90
  #
@@ -29,9 +29,9 @@ module RuboCop
29
29
  begin_pos: offense.location.begin_pos,
30
30
  end_pos: offense.location.end_pos
31
31
  },
32
- message: message(offense),
32
+ message: message(offense),
33
33
  cop_name: offense.cop_name,
34
- status: :uncorrected
34
+ status: :uncorrected
35
35
  }
36
36
  end
37
37
 
@@ -543,8 +543,10 @@ module RuboCop
543
543
  styles.each do |style_name, style|
544
544
  supported_key = RuboCop::Cop::Util.to_supported_styles(style_name)
545
545
  valid = ConfigLoader.default_configuration[name][supported_key]
546
+
546
547
  next unless valid
547
548
  next if valid.include?(style)
549
+ next if validate_support_and_has_list(name, style, valid)
548
550
 
549
551
  msg = "invalid #{style_name} '#{style}' for #{name} found in " \
550
552
  "#{smart_loaded_path}\n" \
@@ -554,6 +556,12 @@ module RuboCop
554
556
  end
555
557
  end
556
558
 
559
+ def validate_support_and_has_list(name, formats, valid)
560
+ ConfigLoader.default_configuration[name]['AllowMultipleStyles'] &&
561
+ formats.is_a?(Array) &&
562
+ formats.all? { |format| valid.include?(format) }
563
+ end
564
+
557
565
  def reject_obsolete_cops_and_parameters
558
566
  messages = [
559
567
  obsolete_cops,
@@ -712,7 +720,7 @@ module RuboCop
712
720
  end
713
721
  end
714
722
 
715
- cop_options.fetch('Enabled', true)
723
+ cop_options.fetch('Enabled') { !for_all_cops['DisabledByDefault'] }
716
724
  end
717
725
 
718
726
  def smart_loaded_path
@@ -120,8 +120,8 @@ module RuboCop
120
120
  # If AllCops::EnabledByDefault is true, it changes the Enabled params
121
121
  # so that only cops explicitly disabled in user configuration are
122
122
  # disabled.
123
- def merge_with_default(config, config_file)
124
- resolver.merge_with_default(config, config_file)
123
+ def merge_with_default(config, config_file, unset_nil: true)
124
+ resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
125
125
  end
126
126
 
127
127
  def add_inheritance_from_auto_generated_file
@@ -55,7 +55,7 @@ module RuboCop
55
55
  # only cops from user configuration are enabled. If
56
56
  # AllCops::EnabledByDefault is true, it changes the Enabled params so that
57
57
  # only cops explicitly disabled in user configuration are disabled.
58
- def merge_with_default(config, config_file)
58
+ def merge_with_default(config, config_file, unset_nil:)
59
59
  default_configuration = ConfigLoader.default_configuration
60
60
 
61
61
  disabled_by_default = config.for_all_cops['DisabledByDefault']
@@ -71,7 +71,8 @@ module RuboCop
71
71
  config = handle_disabled_by_default(config, default_configuration)
72
72
  end
73
73
 
74
- opts = { inherit_mode: config['inherit_mode'] || {}, unset_nil: true }
74
+ opts = { inherit_mode: config['inherit_mode'] || {},
75
+ unset_nil: unset_nil }
75
76
  Config.new(merge(default_configuration, config, opts), config_file)
76
77
  end
77
78
 
@@ -7,7 +7,13 @@ module RuboCop
7
7
  # This generator will take a cop name and generate a source file
8
8
  # and spec file when given a valid qualified cop name.
9
9
  class Generator
10
- SOURCE_TEMPLATE = <<~RUBY
10
+ # Note: RDoc 5.1.0 or lower has the following issue.
11
+ # https://github.com/rubocop-hq/rubocop/issues/7043
12
+ #
13
+ # The following `String#strip_indent` can be replaced with
14
+ # squiggly heredoc when RuboCop supports Ruby 2.5 or higher
15
+ # (RDoc 6.0 or higher).
16
+ SOURCE_TEMPLATE = <<-RUBY.strip_indent
11
17
  # frozen_string_literal: true
12
18
 
13
19
  # TODO: when finished, run `rake generate_cops_documentation` to update the docs
@@ -17,7 +17,9 @@ module RuboCop
17
17
  # - always_inspect
18
18
  # - always_ignore
19
19
  # - ignore_implicit (without curly braces)
20
- # - ignore_explicit (with curly braces)
20
+ #
21
+ # Alternatively you can specify multiple allowed styles. That's done by
22
+ # passing a list of styles to EnforcedStyles.
21
23
  #
22
24
  # @example EnforcedHashRocketStyle: key (default)
23
25
  # # bad
@@ -198,48 +200,65 @@ module RuboCop
198
200
  return if ignored_node?(node)
199
201
  return if node.pairs.empty? || node.single_line?
200
202
 
201
- return unless alignment_for_hash_rockets.checkable_layout?(node) &&
202
- alignment_for_colons.checkable_layout?(node)
203
+ return unless alignment_for_hash_rockets
204
+ .any? { |a| a.checkable_layout?(node) } &&
205
+ alignment_for_colons
206
+ .any? { |a| a.checkable_layout?(node) }
203
207
 
204
208
  check_pairs(node)
205
209
  end
206
210
 
207
211
  def autocorrect(node)
208
- # We can't use the instance variable inside the lambda. That would
209
- # just give each lambda the same reference and they would all get the
210
- # last value of each. A local variable fixes the problem.
211
- key_delta = column_deltas[:key] || 0
212
+ delta = column_deltas[alignment_for(node).first.class][node]
213
+ return if delta.nil?
212
214
 
213
- if !node.value
214
- correct_no_value(key_delta, node.source_range)
215
- else
216
- correct_key_value(key_delta, node.key.source_range,
217
- node.value.source_range,
218
- node.loc.operator)
219
- end
215
+ correct_node(node, delta)
220
216
  end
221
217
 
222
- private
223
-
218
+ attr_accessor :offences_by
224
219
  attr_accessor :column_deltas
225
220
 
221
+ private
222
+
226
223
  def double_splat?(node)
227
224
  node.children.last.is_a?(Symbol)
228
225
  end
229
226
 
230
227
  def check_pairs(node)
231
228
  first_pair = node.pairs.first
232
- self.column_deltas = alignment_for(first_pair)
233
- .deltas_for_first_pair(first_pair, node)
234
- add_offense(first_pair) unless good_alignment?
229
+ self.offences_by = {}
230
+ self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
231
+
232
+ alignment_for(first_pair).each do |alignment|
233
+ delta = alignment.deltas_for_first_pair(first_pair, node)
234
+ check_delta delta, node: first_pair, alignment: alignment
235
+ end
235
236
 
236
237
  node.children.each do |current|
237
- self.column_deltas = alignment_for(current)
238
- .deltas(first_pair, current)
239
- add_offense(current) unless good_alignment?
238
+ alignment_for(current).each do |alignment|
239
+ delta = alignment.deltas(first_pair, current)
240
+ check_delta delta, node: current, alignment: alignment
241
+ end
242
+ end
243
+
244
+ add_offences
245
+ end
246
+
247
+ def add_offences
248
+ _format, offences = offences_by.min_by { |_, v| v.length }
249
+ (offences || []).each do |offence|
250
+ add_offense offence
240
251
  end
241
252
  end
242
253
 
254
+ def check_delta(delta, node:, alignment:)
255
+ offences_by[alignment.class] ||= []
256
+ return if good_alignment? delta
257
+
258
+ column_deltas[alignment.class][node] = delta
259
+ offences_by[alignment.class].push(node)
260
+ end
261
+
243
262
  def ignore_hash_argument?(node)
244
263
  case cop_config['EnforcedLastArgumentHashStyle']
245
264
  when 'always_inspect' then false
@@ -267,16 +286,31 @@ module RuboCop
267
286
  new_alignment('EnforcedColonStyle')
268
287
  end
269
288
 
289
+ def correct_node(node, delta)
290
+ # We can't use the instance variable inside the lambda. That would
291
+ # just give each lambda the same reference and they would all get the
292
+ # last value of each. A local variable fixes the problem.
293
+
294
+ if !node.value
295
+ correct_no_value(delta[:key] || 0, node.source_range)
296
+ else
297
+ correct_key_value(delta, node.key.source_range,
298
+ node.value.source_range,
299
+ node.loc.operator)
300
+ end
301
+ end
302
+
270
303
  def correct_no_value(key_delta, key)
271
304
  ->(corrector) { adjust(corrector, key_delta, key) }
272
305
  end
273
306
 
274
- def correct_key_value(key_delta, key, value, separator)
307
+ def correct_key_value(delta, key, value, separator)
275
308
  # We can't use the instance variable inside the lambda. That would
276
309
  # just give each lambda the same reference and they would all get the
277
310
  # last value of each. Some local variables fix the problem.
278
- separator_delta = column_deltas[:separator] || 0
279
- value_delta = column_deltas[:value] || 0
311
+ separator_delta = delta[:separator] || 0
312
+ value_delta = delta[:value] || 0
313
+ key_delta = delta[:key] || 0
280
314
 
281
315
  key_column = key.column
282
316
  key_delta = -key_column if key_delta < -key_column
@@ -289,11 +323,20 @@ module RuboCop
289
323
  end
290
324
 
291
325
  def new_alignment(key)
292
- case cop_config[key]
293
- when 'key' then KeyAlignment.new
294
- when 'table' then TableAlignment.new
295
- when 'separator' then SeparatorAlignment.new
296
- else raise "Unknown #{key}: #{cop_config[key]}"
326
+ formats = cop_config[key]
327
+ formats = [formats] if formats.is_a? String
328
+
329
+ formats.uniq.map do |format|
330
+ case format
331
+ when 'key'
332
+ KeyAlignment.new
333
+ when 'table'
334
+ TableAlignment.new
335
+ when 'separator'
336
+ SeparatorAlignment.new
337
+ else
338
+ raise "Unknown #{key}: #{formats}"
339
+ end
297
340
  end
298
341
  end
299
342
 
@@ -306,7 +349,7 @@ module RuboCop
306
349
  end
307
350
  end
308
351
 
309
- def good_alignment?
352
+ def good_alignment?(column_deltas)
310
353
  column_deltas.values.all?(&:zero?)
311
354
  end
312
355
  end