rubocop 1.40.0 → 1.43.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +52 -2
  5. data/lib/rubocop/cli.rb +1 -1
  6. data/lib/rubocop/config.rb +34 -11
  7. data/lib/rubocop/config_loader.rb +9 -0
  8. data/lib/rubocop/config_loader_resolver.rb +5 -1
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/badge.rb +9 -4
  11. data/lib/rubocop/cop/base.rb +83 -66
  12. data/lib/rubocop/cop/commissioner.rb +8 -3
  13. data/lib/rubocop/cop/cop.rb +29 -29
  14. data/lib/rubocop/cop/corrector.rb +23 -11
  15. data/lib/rubocop/cop/gemspec/dependency_version.rb +16 -18
  16. data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
  17. data/lib/rubocop/cop/layout/class_structure.rb +32 -11
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +3 -1
  19. data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
  20. data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
  21. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
  22. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
  23. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
  24. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
  25. data/lib/rubocop/cop/layout/indentation_style.rb +7 -2
  26. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
  27. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +11 -5
  28. data/lib/rubocop/cop/layout/line_length.rb +2 -0
  29. data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
  30. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  31. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
  32. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
  33. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
  34. data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
  35. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  36. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +11 -4
  38. data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
  39. data/lib/rubocop/cop/lint/debugger.rb +3 -1
  40. data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
  41. data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
  42. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
  43. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +19 -0
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -1
  45. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  46. data/lib/rubocop/cop/lint/regexp_as_condition.rb +6 -0
  47. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -1
  48. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -19
  49. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  50. data/lib/rubocop/cop/lint/useless_rescue.rb +71 -0
  51. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +5 -3
  52. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  53. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  54. data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
  55. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  56. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -4
  57. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  58. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  59. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
  60. data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
  61. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
  62. data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
  63. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -2
  64. data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
  66. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
  67. data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
  68. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  69. data/lib/rubocop/cop/mixin/require_library.rb +2 -0
  70. data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
  71. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -1
  72. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  73. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
  74. data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
  75. data/lib/rubocop/cop/registry.rb +28 -25
  76. data/lib/rubocop/cop/security/compound_hash.rb +2 -1
  77. data/lib/rubocop/cop/style/alias.rb +9 -1
  78. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  79. data/lib/rubocop/cop/style/concat_array_literals.rb +86 -0
  80. data/lib/rubocop/cop/style/documentation.rb +11 -5
  81. data/lib/rubocop/cop/style/guard_clause.rb +17 -9
  82. data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
  83. data/lib/rubocop/cop/style/hash_syntax.rb +11 -7
  84. data/lib/rubocop/cop/style/identical_conditional_branches.rb +15 -0
  85. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -3
  86. data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
  87. data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
  88. data/lib/rubocop/cop/style/map_to_set.rb +61 -0
  89. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -9
  90. data/lib/rubocop/cop/style/method_def_parentheses.rb +11 -4
  91. data/lib/rubocop/cop/style/min_max_comparison.rb +73 -0
  92. data/lib/rubocop/cop/style/missing_else.rb +13 -1
  93. data/lib/rubocop/cop/style/operator_method_call.rb +15 -1
  94. data/lib/rubocop/cop/style/redundant_constant_base.rb +13 -0
  95. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
  96. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  97. data/lib/rubocop/cop/style/redundant_string_escape.rb +6 -3
  98. data/lib/rubocop/cop/style/require_order.rb +63 -9
  99. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -2
  100. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  101. data/lib/rubocop/cop/style/signal_exception.rb +8 -6
  102. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
  103. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -4
  104. data/lib/rubocop/cop/style/word_array.rb +41 -0
  105. data/lib/rubocop/cop/style/yoda_expression.rb +81 -0
  106. data/lib/rubocop/cop/style/zero_length_predicate.rb +31 -14
  107. data/lib/rubocop/cop/team.rb +29 -29
  108. data/lib/rubocop/cop/util.rb +31 -4
  109. data/lib/rubocop/cop/variable_force.rb +0 -3
  110. data/lib/rubocop/cops_documentation_generator.rb +33 -11
  111. data/lib/rubocop/directive_comment.rb +1 -1
  112. data/lib/rubocop/file_patterns.rb +43 -0
  113. data/lib/rubocop/formatter.rb +2 -0
  114. data/lib/rubocop/options.rb +1 -1
  115. data/lib/rubocop/path_util.rb +38 -22
  116. data/lib/rubocop/result_cache.rb +1 -1
  117. data/lib/rubocop/runner.rb +10 -3
  118. data/lib/rubocop/target_finder.rb +1 -1
  119. data/lib/rubocop/target_ruby.rb +0 -1
  120. data/lib/rubocop/version.rb +1 -1
  121. data/lib/rubocop.rb +7 -1
  122. metadata +16 -10
  123. data/lib/rubocop/optimized_patterns.rb +0 -38
@@ -51,7 +51,11 @@ module RuboCop
51
51
  private_constant :LINE_1_ENDING, :LINE_2_BEGINNING,
52
52
  :LEADING_STYLE_OFFENSE, :TRAILING_STYLE_OFFENSE
53
53
 
54
+ # rubocop:disable Metrics/AbcSize
54
55
  def on_dstr(node)
56
+ # Quick check if we possibly have line continuations.
57
+ return unless node.source.include?('\\')
58
+
55
59
  end_of_first_line = node.loc.expression.begin_pos - node.loc.expression.column
56
60
 
57
61
  raw_lines(node).each_cons(2) do |raw_line_one, raw_line_two|
@@ -66,6 +70,7 @@ module RuboCop
66
70
  end
67
71
  end
68
72
  end
73
+ # rubocop:enable Metrics/AbcSize
69
74
 
70
75
  private
71
76
 
@@ -32,10 +32,9 @@ module RuboCop
32
32
  extend AutoCorrector
33
33
 
34
34
  def on_new_investigation
35
- last_line = last_line(processed_source)
35
+ return unless processed_source.raw_source.include?('\\')
36
36
 
37
- @ignored_ranges = string_literal_ranges(processed_source.ast) +
38
- comment_ranges(processed_source.comments)
37
+ last_line = last_line(processed_source)
39
38
 
40
39
  processed_source.raw_source.lines.each_with_index do |line, index|
41
40
  break if index >= last_line
@@ -92,7 +91,8 @@ module RuboCop
92
91
  # which lines start inside a string literal?
93
92
  return [] if ast.nil?
94
93
 
95
- ast.each_node(:str, :dstr).with_object(Set.new) do |str, ranges|
94
+ ranges = Set.new
95
+ ast.each_node(:str, :dstr) do |str|
96
96
  loc = str.location
97
97
 
98
98
  if str.heredoc?
@@ -101,6 +101,7 @@ module RuboCop
101
101
  ranges << loc.expression
102
102
  end
103
103
  end
104
+ ranges
104
105
  end
105
106
 
106
107
  def comment_ranges(comments)
@@ -114,7 +115,12 @@ module RuboCop
114
115
  end
115
116
 
116
117
  def ignore_range?(backtick_range)
117
- @ignored_ranges.any? { |range| range.contains?(backtick_range) }
118
+ ignored_ranges.any? { |range| range.contains?(backtick_range) }
119
+ end
120
+
121
+ def ignored_ranges
122
+ @ignored_ranges ||= string_literal_ranges(processed_source.ast) +
123
+ comment_ranges(processed_source.comments)
118
124
  end
119
125
 
120
126
  def no_space_style?
@@ -86,6 +86,8 @@ module RuboCop
86
86
  alias on_def on_potential_breakable_node
87
87
 
88
88
  def on_new_investigation
89
+ return unless processed_source.raw_source.include?(';')
90
+
89
91
  check_for_breakable_semicolons(processed_source)
90
92
  end
91
93
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Ensures that each item in a multi-line array
7
7
  # starts on a separate line.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # [
@@ -14,12 +14,55 @@ module RuboCop
14
14
  # c
15
15
  # ]
16
16
  #
17
+ # # bad
18
+ # [ a, b, foo(
19
+ # bar
20
+ # )]
21
+ #
17
22
  # # good
18
23
  # [
19
24
  # a,
20
25
  # b,
21
26
  # c
22
27
  # ]
28
+ #
29
+ # # good
30
+ # [
31
+ # a,
32
+ # b,
33
+ # foo(
34
+ # bar
35
+ # )
36
+ # ]
37
+ #
38
+ # @example AllowMultilineFinalElement: true
39
+ #
40
+ # # bad
41
+ # [
42
+ # a, b,
43
+ # c
44
+ # ]
45
+ #
46
+ # # good
47
+ # [ a, b, foo(
48
+ # bar
49
+ # )]
50
+ #
51
+ # # good
52
+ # [
53
+ # a,
54
+ # b,
55
+ # c
56
+ # ]
57
+ #
58
+ # # good
59
+ # [
60
+ # a,
61
+ # b,
62
+ # foo(
63
+ # bar
64
+ # )
65
+ # ]
23
66
  class MultilineArrayLineBreaks < Base
24
67
  include MultilineElementLineBreaks
25
68
  extend AutoCorrector
@@ -27,7 +70,13 @@ module RuboCop
27
70
  MSG = 'Each item in a multi-line array must start on a separate line.'
28
71
 
29
72
  def on_array(node)
30
- check_line_breaks(node, node.children)
73
+ check_line_breaks(node, node.children, ignore_last: ignore_last_element?)
74
+ end
75
+
76
+ private
77
+
78
+ def ignore_last_element?
79
+ !!cop_config['AllowMultilineFinalElement']
31
80
  end
32
81
  end
33
82
  end
@@ -91,7 +91,7 @@ module RuboCop
91
91
  if node.source.lines.first.end_with?("|\n")
92
92
  PIPE_SIZE
93
93
  else
94
- 1 + (PIPE_SIZE * 2)
94
+ (PIPE_SIZE * 2) + 1
95
95
  end
96
96
  end
97
97
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Ensures that each key in a multi-line hash
7
7
  # starts on a separate line.
8
8
  #
9
- # @example
9
+ # @example AllowMultilineFinalElement: false (default)
10
10
  #
11
11
  # # bad
12
12
  # {
@@ -14,12 +14,54 @@ module RuboCop
14
14
  # c: 3
15
15
  # }
16
16
  #
17
+ # # bad
18
+ # { a: 1, b: {
19
+ # c: 3,
20
+ # }}
21
+ #
17
22
  # # good
18
23
  # {
19
24
  # a: 1,
20
25
  # b: 2,
21
26
  # c: 3
22
27
  # }
28
+ #
29
+ # # good
30
+ # {
31
+ # a: 1,
32
+ # b: {
33
+ # c: 3,
34
+ # }
35
+ # }
36
+ #
37
+ # @example AllowMultilineFinalElement: true
38
+ #
39
+ # # bad
40
+ # {
41
+ # a: 1, b: 2,
42
+ # c: 3
43
+ # }
44
+ #
45
+ # # good
46
+ # { a: 1, b: {
47
+ # c: 3,
48
+ # }}
49
+ #
50
+ # # good
51
+ # {
52
+ # a: 1,
53
+ # b: 2,
54
+ # c: 3
55
+ # }
56
+ #
57
+ #
58
+ # # good
59
+ # {
60
+ # a: 1,
61
+ # b: {
62
+ # c: 3,
63
+ # }
64
+ # }
23
65
  class MultilineHashKeyLineBreaks < Base
24
66
  include MultilineElementLineBreaks
25
67
  extend AutoCorrector
@@ -31,8 +73,9 @@ module RuboCop
31
73
  # braces like {foo: 1}. That is, not a kwargs hashes.
32
74
  # Style/MultilineMethodArgumentLineBreaks handles those.
33
75
  return unless starts_with_curly_brace?(node)
76
+ return unless node.loc.begin
34
77
 
35
- check_line_breaks(node, node.children) if node.loc.begin
78
+ check_line_breaks(node, node.children, ignore_last: ignore_last_element?)
36
79
  end
37
80
 
38
81
  private
@@ -40,6 +83,10 @@ module RuboCop
40
83
  def starts_with_curly_brace?(node)
41
84
  node.loc.begin
42
85
  end
86
+
87
+ def ignore_last_element?
88
+ !!cop_config['AllowMultilineFinalElement']
89
+ end
43
90
  end
44
91
  end
45
92
  end
@@ -9,13 +9,18 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodArgumentLineBreak`.
11
11
  #
12
- # @example
12
+ # @example AllowMultilineFinalElement: false (default)
13
13
  #
14
14
  # # bad
15
15
  # foo(a, b,
16
16
  # c
17
17
  # )
18
18
  #
19
+ # # bad
20
+ # foo(a, b, {
21
+ # foo: "bar",
22
+ # })
23
+ #
19
24
  # # good
20
25
  # foo(
21
26
  # a,
@@ -25,6 +30,46 @@ module RuboCop
25
30
  #
26
31
  # # good
27
32
  # foo(a, b, c)
33
+ #
34
+ # # good
35
+ # foo(
36
+ # a,
37
+ # b,
38
+ # {
39
+ # foo: "bar",
40
+ # }
41
+ # )
42
+ #
43
+ # @example AllowMultilineFinalElement: true
44
+ #
45
+ # # bad
46
+ # foo(a, b,
47
+ # c
48
+ # )
49
+ #
50
+ # # good
51
+ # foo(a, b, {
52
+ # foo: "bar",
53
+ # })
54
+ #
55
+ # # good
56
+ # foo(
57
+ # a,
58
+ # b,
59
+ # c
60
+ # )
61
+ #
62
+ # # good
63
+ # foo(a, b, c)
64
+ #
65
+ # # good
66
+ # foo(
67
+ # a,
68
+ # b,
69
+ # {
70
+ # foo: "bar",
71
+ # }
72
+ # )
28
73
  class MultilineMethodArgumentLineBreaks < Base
29
74
  include MultilineElementLineBreaks
30
75
  extend AutoCorrector
@@ -45,7 +90,13 @@ module RuboCop
45
90
  last_arg = args.last
46
91
  args = args[0...-1] + last_arg.children if last_arg&.hash_type? && !last_arg&.braces?
47
92
 
48
- check_line_breaks(node, args)
93
+ check_line_breaks(node, args, ignore_last: ignore_last_element?)
94
+ end
95
+
96
+ private
97
+
98
+ def ignore_last_element?
99
+ !!cop_config['AllowMultilineFinalElement']
49
100
  end
50
101
  end
51
102
  end
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # NOTE: This cop does not move the first argument, if you want that to
10
10
  # be on a separate line, see `Layout/FirstMethodParameterLineBreak`.
11
11
  #
12
- # @example
12
+ # @example AllowMultilineFinalElement: false (default)
13
13
  #
14
14
  # # bad
15
15
  # def foo(a, b,
@@ -17,6 +17,47 @@ module RuboCop
17
17
  # )
18
18
  # end
19
19
  #
20
+ # # bad
21
+ # def foo(a, b = {
22
+ # foo: "bar",
23
+ # })
24
+ # end
25
+ #
26
+ # # good
27
+ # def foo(
28
+ # a,
29
+ # b,
30
+ # c
31
+ # )
32
+ # end
33
+ #
34
+ # # good
35
+ # def foo(
36
+ # a,
37
+ # b = {
38
+ # foo: "bar",
39
+ # }
40
+ # )
41
+ # end
42
+ #
43
+ # # good
44
+ # def foo(a, b, c)
45
+ # end
46
+ #
47
+ # @example AllowMultilineFinalElement: true
48
+ #
49
+ # # bad
50
+ # def foo(a, b,
51
+ # c
52
+ # )
53
+ # end
54
+ #
55
+ # # good
56
+ # def foo(a, b = {
57
+ # foo: "bar",
58
+ # })
59
+ # end
60
+ #
20
61
  # # good
21
62
  # def foo(
22
63
  # a,
@@ -26,6 +67,15 @@ module RuboCop
26
67
  # end
27
68
  #
28
69
  # # good
70
+ # def foo(
71
+ # a,
72
+ # b = {
73
+ # foo: "bar",
74
+ # }
75
+ # )
76
+ # end
77
+ #
78
+ # # good
29
79
  # def foo(a, b, c)
30
80
  # end
31
81
  class MultilineMethodParameterLineBreaks < Base
@@ -37,7 +87,13 @@ module RuboCop
37
87
  def on_def(node)
38
88
  return if node.arguments.empty?
39
89
 
40
- check_line_breaks(node, node.arguments)
90
+ check_line_breaks(node, node.arguments, ignore_last: ignore_last_element?)
91
+ end
92
+
93
+ private
94
+
95
+ def ignore_last_element?
96
+ !!cop_config['AllowMultilineFinalElement']
41
97
  end
42
98
  end
43
99
  end
@@ -84,11 +84,11 @@ module RuboCop
84
84
  return true if other_cop_takes_precedence?(node)
85
85
 
86
86
  !cop_config['InspectBlocks'] && (node.block_type? ||
87
- node.each_descendant(:block).any?(&:multiline?))
87
+ any_descendant?(node, :block, &:multiline?))
88
88
  end
89
89
 
90
90
  def other_cop_takes_precedence?(node)
91
- single_line_block_chain_enabled? && node.each_descendant(:block).any? do |block_node|
91
+ single_line_block_chain_enabled? && any_descendant?(node, :block) do |block_node|
92
92
  block_node.parent.send_type? && block_node.parent.loc.dot && !block_node.multiline?
93
93
  end
94
94
  end
@@ -256,7 +256,7 @@ module RuboCop
256
256
  # regular dotted method calls bind more tightly than operators
257
257
  # so we need to climb up the AST past them
258
258
  node.each_ancestor do |ancestor|
259
- return true if ancestor.and_type? || ancestor.or_type?
259
+ return true if ancestor.and_type? || ancestor.or_type? || ancestor.range_type?
260
260
  return false unless ancestor.send_type?
261
261
  return true if ancestor.operator_method?
262
262
  end
@@ -79,7 +79,7 @@ module RuboCop
79
79
  def ends_in_end?(processed_source)
80
80
  buffer = processed_source.buffer
81
81
 
82
- return true if buffer.source.strip.start_with?('__END__')
82
+ return true if buffer.source.match?(/\s*__END__/)
83
83
  return false if processed_source.tokens.empty?
84
84
 
85
85
  extra = buffer.source[processed_source.tokens.last.end_pos..]
@@ -47,7 +47,6 @@ module RuboCop
47
47
  MSG = 'Trailing whitespace detected.'
48
48
 
49
49
  def on_new_investigation
50
- @heredocs = extract_heredocs(processed_source.ast)
51
50
  processed_source.lines.each_with_index do |line, index|
52
51
  next unless line.end_with?(' ', "\t")
53
52
 
@@ -102,17 +101,25 @@ module RuboCop
102
101
  end
103
102
 
104
103
  def find_heredoc(line_number)
105
- @heredocs.each { |node, r| return node if r.include?(line_number) }
104
+ heredocs.each { |node, r| return node if r.include?(line_number) }
106
105
  nil
107
106
  end
108
107
 
108
+ def heredocs
109
+ @heredocs ||= extract_heredocs(processed_source.ast)
110
+ end
111
+
109
112
  def extract_heredocs(ast)
110
113
  return [] unless ast
111
114
 
112
- ast.each_node(:str, :dstr, :xstr).select(&:heredoc?).map do |node|
115
+ heredocs = []
116
+ ast.each_node(:str, :dstr, :xstr) do |node|
117
+ next unless node.heredoc?
118
+
113
119
  body = node.location.heredoc_body
114
- [node, body.first_line...body.last_line]
120
+ heredocs << [node, body.first_line...body.last_line]
115
121
  end
122
+ heredocs
116
123
  end
117
124
 
118
125
  def offense_range(lineno, line)
@@ -16,6 +16,10 @@ module RuboCop
16
16
  # using the same name a namespace and a class. To avoid too many unnecessary
17
17
  # offenses, Enable this cop with `Only: [The, Constant, Names, Causing, Issues]`
18
18
  #
19
+ # NOTE: `Style/RedundantConstantBase` cop is disabled if this cop is enabled to prevent
20
+ # conflicting rules. Because it respects user configurations that want to enable
21
+ # this cop which is disabled by default.
22
+ #
19
23
  # @example
20
24
  # # By default checks every constant
21
25
  #
@@ -96,8 +96,10 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def debugger_method?(send_node)
99
+ method_name = send_node.method_name
100
+
99
101
  debugger_methods.any? do |method|
100
- next unless method[:method_name] == send_node.method_name
102
+ next unless method[:method_name] == method_name
101
103
 
102
104
  if method[:receiver].nil?
103
105
  send_node.receiver.nil?
@@ -84,8 +84,6 @@ module RuboCop
84
84
  # end
85
85
  #
86
86
  class DuplicateBranch < Base
87
- include RescueNode
88
-
89
87
  MSG = 'Duplicate branch body detected.'
90
88
 
91
89
  def on_branching_statement(node)
@@ -57,19 +57,20 @@ module RuboCop
57
57
  def initialize(config = nil, options = nil)
58
58
  super
59
59
  @definitions = {}
60
+ @scopes = Hash.new { |hash, key| hash[key] = [] }
60
61
  end
61
62
 
62
63
  def on_def(node)
63
64
  # if a method definition is inside an if, it is very likely
64
65
  # that a different definition is used depending on platform, etc.
65
- return if node.ancestors.any?(&:if_type?)
66
+ return if node.each_ancestor.any?(&:if_type?)
66
67
  return if possible_dsl?(node)
67
68
 
68
69
  found_instance_method(node, node.method_name)
69
70
  end
70
71
 
71
72
  def on_defs(node)
72
- return if node.ancestors.any?(&:if_type?)
73
+ return if node.each_ancestor.any?(&:if_type?)
73
74
  return if possible_dsl?(node)
74
75
 
75
76
  if node.receiver.const_type?
@@ -157,16 +158,18 @@ module RuboCop
157
158
 
158
159
  def found_method(node, method_name)
159
160
  key = method_key(node, method_name)
161
+ scope = node.each_ancestor(:rescue, :ensure).first&.type
160
162
 
161
163
  if @definitions.key?(key)
162
- loc = if DEF_TYPES.include?(node.type)
163
- node.loc.keyword.join(node.loc.name)
164
- else
165
- node.loc.expression
166
- end
164
+ if scope && !@scopes[scope].include?(key)
165
+ @definitions[key] = node
166
+ @scopes[scope] << key
167
+ return
168
+ end
169
+
167
170
  message = message_for_dup(node, method_name, key)
168
171
 
169
- add_offense(loc, message: message)
172
+ add_offense(location(node), message: message)
170
173
  else
171
174
  @definitions[key] = node
172
175
  end
@@ -180,6 +183,14 @@ module RuboCop
180
183
  end
181
184
  end
182
185
 
186
+ def location(node)
187
+ if DEF_TYPES.include?(node.type)
188
+ node.loc.keyword.join(node.loc.name)
189
+ else
190
+ node.loc.expression
191
+ end
192
+ end
193
+
183
194
  def on_attr(node, attr_name, args)
184
195
  case attr_name
185
196
  when :attr
@@ -44,7 +44,6 @@ module RuboCop
44
44
  class NonAtomicFileOperation < Base
45
45
  extend AutoCorrector
46
46
  include Alignment
47
- include RangeHelp
48
47
 
49
48
  MSG_REMOVE_FILE_EXIST_CHECK = 'Remove unnecessary existence check ' \
50
49
  '`%<receiver>s.%<method_name>s`.'
@@ -101,10 +100,11 @@ module RuboCop
101
100
  def register_offense(node, exist_node)
102
101
  add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
103
102
 
104
- range = range_between(node.parent.loc.keyword.begin_pos,
105
- exist_node.loc.expression.end_pos)
103
+ parent = node.parent
104
+ range = parent.loc.keyword.begin.join(parent.condition.source_range.end)
105
+
106
106
  add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
107
- autocorrect(corrector, node, range) unless node.parent.elsif?
107
+ autocorrect(corrector, node, range) unless parent.elsif?
108
108
  end
109
109
  end
110
110
 
@@ -120,7 +120,12 @@ module RuboCop
120
120
  def autocorrect(corrector, node, range)
121
121
  corrector.remove(range)
122
122
  autocorrect_replace_method(corrector, node)
123
- corrector.remove(node.parent.loc.end) if node.parent.multiline?
123
+
124
+ if node.parent.modifier_form?
125
+ corrector.remove(node.source_range.end.join(node.parent.loc.keyword.begin))
126
+ else
127
+ corrector.remove(node.parent.loc.end)
128
+ end
124
129
  end
125
130
 
126
131
  def autocorrect_replace_method(corrector, node)
@@ -68,6 +68,12 @@ module RuboCop
68
68
  @valid_ref = regexp_conditions.map { |condition| check_regexp(condition) }.compact.max
69
69
  end
70
70
 
71
+ def on_in_pattern(node)
72
+ regexp_patterns = patterns(node).select(&:regexp_type?)
73
+
74
+ @valid_ref = regexp_patterns.map { |pattern| check_regexp(pattern) }.compact.max
75
+ end
76
+
71
77
  def on_nth_ref(node)
72
78
  backref, = *node
73
79
  return if @valid_ref.nil? || backref <= @valid_ref
@@ -84,6 +90,19 @@ module RuboCop
84
90
 
85
91
  private
86
92
 
93
+ def patterns(pattern_node)
94
+ pattern = pattern_node.node_parts[0]
95
+
96
+ case pattern.type
97
+ when :array_pattern, :match_alt
98
+ pattern.children
99
+ when :match_as
100
+ patterns(pattern)
101
+ else
102
+ [pattern]
103
+ end
104
+ end
105
+
87
106
  def check_regexp(node)
88
107
  return if node.interpolation?
89
108
 
@@ -128,6 +128,7 @@ module RuboCop
128
128
  end
129
129
  end
130
130
 
131
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
131
132
  def each_already_disabled(cop, line_ranges)
132
133
  line_ranges.each_cons(2) do |previous_range, range|
133
134
  next if ignore_offense?(range)
@@ -152,9 +153,10 @@ module RuboCop
152
153
  cop
153
154
  end
154
155
 
155
- yield comment, redundant
156
+ yield comment, redundant if redundant
156
157
  end
157
158
  end
159
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
158
160
 
159
161
  def find_redundant_cop(cop, range)
160
162
  cop_offenses = offenses_to_check.select { |offense| offense.cop_name == cop }
@@ -42,7 +42,7 @@ module RuboCop
42
42
  MSG = 'Unnecessary enabling of %<cop>s.'
43
43
 
44
44
  def on_new_investigation
45
- return if processed_source.blank?
45
+ return if processed_source.blank? || !processed_source.raw_source.include?('enable')
46
46
 
47
47
  offenses = processed_source.comment_config.extra_enabled_comments
48
48
  offenses.each { |comment, cop_names| register_offense(comment, cop_names) }