rubocop 0.75.0 → 0.76.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +53 -54
  4. data/lib/rubocop.rb +10 -9
  5. data/lib/rubocop/ast/builder.rb +1 -0
  6. data/lib/rubocop/ast/node.rb +4 -0
  7. data/lib/rubocop/ast/node/return_node.rb +24 -0
  8. data/lib/rubocop/cli.rb +7 -4
  9. data/lib/rubocop/comment_config.rb +2 -2
  10. data/lib/rubocop/config.rb +7 -0
  11. data/lib/rubocop/config_loader.rb +1 -1
  12. data/lib/rubocop/config_loader_resolver.rb +2 -1
  13. data/lib/rubocop/config_obsoletion.rb +9 -0
  14. data/lib/rubocop/config_validator.rb +24 -15
  15. data/lib/rubocop/cop/commissioner.rb +15 -7
  16. data/lib/rubocop/cop/cop.rb +10 -6
  17. data/lib/rubocop/cop/corrector.rb +8 -7
  18. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  19. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  20. data/lib/rubocop/cop/layout/align_hash.rb +6 -2
  21. data/lib/rubocop/cop/layout/comment_indentation.rb +10 -13
  22. data/lib/rubocop/cop/layout/empty_comment.rb +7 -16
  23. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +22 -7
  24. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +2 -2
  25. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +2 -2
  26. data/lib/rubocop/cop/layout/end_of_line.rb +8 -3
  27. data/lib/rubocop/cop/layout/indent_assignment.rb +2 -1
  28. data/lib/rubocop/cop/layout/indent_first_argument.rb +9 -7
  29. data/lib/rubocop/cop/layout/indent_first_hash_element.rb +1 -1
  30. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  31. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -0
  32. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -7
  33. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -4
  34. data/lib/rubocop/cop/layout/space_inside_parens.rb +6 -6
  35. data/lib/rubocop/cop/layout/trailing_whitespace.rb +18 -2
  36. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -8
  37. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +2 -2
  38. data/lib/rubocop/cop/lint/{unneeded_cop_disable_directive.rb → redundant_cop_disable_directive.rb} +23 -23
  39. data/lib/rubocop/cop/lint/{unneeded_cop_enable_directive.rb → redundant_cop_enable_directive.rb} +6 -8
  40. data/lib/rubocop/cop/lint/{unneeded_require_statement.rb → redundant_require_statement.rb} +1 -1
  41. data/lib/rubocop/cop/lint/{unneeded_splat_expansion.rb → redundant_splat_expansion.rb} +5 -5
  42. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +5 -6
  43. data/lib/rubocop/cop/lint/unused_block_argument.rb +22 -6
  44. data/lib/rubocop/cop/lint/unused_method_argument.rb +23 -5
  45. data/lib/rubocop/cop/lint/void.rb +7 -26
  46. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  47. data/lib/rubocop/cop/metrics/line_length.rb +1 -4
  48. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +23 -6
  49. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  50. data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -2
  51. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -6
  52. data/lib/rubocop/cop/naming/file_name.rb +12 -5
  53. data/lib/rubocop/cop/registry.rb +1 -1
  54. data/lib/rubocop/cop/style/attr.rb +2 -2
  55. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +6 -6
  56. data/lib/rubocop/cop/style/comment_annotation.rb +5 -5
  57. data/lib/rubocop/cop/style/copyright.rb +11 -7
  58. data/lib/rubocop/cop/style/documentation_method.rb +44 -0
  59. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +2 -2
  60. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  61. data/lib/rubocop/cop/style/empty_literal.rb +2 -2
  62. data/lib/rubocop/cop/style/empty_method.rb +5 -5
  63. data/lib/rubocop/cop/style/expand_path_arguments.rb +1 -1
  64. data/lib/rubocop/cop/style/format_string.rb +10 -7
  65. data/lib/rubocop/cop/style/format_string_token.rb +15 -34
  66. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +10 -0
  67. data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
  68. data/lib/rubocop/cop/style/if_unless_modifier.rb +9 -2
  69. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  70. data/lib/rubocop/cop/style/inverse_methods.rb +19 -13
  71. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -10
  72. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +20 -20
  73. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -9
  74. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  75. data/lib/rubocop/cop/style/nested_modifier.rb +4 -2
  76. data/lib/rubocop/cop/style/non_nil_check.rb +21 -9
  77. data/lib/rubocop/cop/style/{unneeded_capital_w.rb → redundant_capital_w.rb} +1 -1
  78. data/lib/rubocop/cop/style/{unneeded_condition.rb → redundant_condition.rb} +3 -3
  79. data/lib/rubocop/cop/style/{unneeded_interpolation.rb → redundant_interpolation.rb} +1 -1
  80. data/lib/rubocop/cop/style/{unneeded_percent_q.rb → redundant_percent_q.rb} +1 -1
  81. data/lib/rubocop/cop/style/redundant_return.rb +37 -21
  82. data/lib/rubocop/cop/style/{unneeded_sort.rb → redundant_sort.rb} +4 -4
  83. data/lib/rubocop/cop/style/safe_navigation.rb +19 -8
  84. data/lib/rubocop/cop/style/semicolon.rb +13 -2
  85. data/lib/rubocop/cop/style/special_global_vars.rb +5 -7
  86. data/lib/rubocop/cop/util.rb +1 -1
  87. data/lib/rubocop/cop/utils/format_string.rb +10 -18
  88. data/lib/rubocop/cop/variable_force.rb +7 -5
  89. data/lib/rubocop/formatter/clang_style_formatter.rb +8 -3
  90. data/lib/rubocop/formatter/emacs_style_formatter.rb +22 -12
  91. data/lib/rubocop/formatter/file_list_formatter.rb +1 -1
  92. data/lib/rubocop/formatter/formatter_set.rb +16 -16
  93. data/lib/rubocop/formatter/pacman_formatter.rb +3 -3
  94. data/lib/rubocop/formatter/simple_text_formatter.rb +7 -3
  95. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  96. data/lib/rubocop/node_pattern.rb +3 -1
  97. data/lib/rubocop/options.rb +16 -22
  98. data/lib/rubocop/result_cache.rb +1 -1
  99. data/lib/rubocop/runner.rb +32 -27
  100. data/lib/rubocop/target_finder.rb +12 -6
  101. data/lib/rubocop/version.rb +1 -1
  102. metadata +12 -11
@@ -6,55 +6,36 @@ module RuboCop
6
6
  # This cop checks for operators, variables, literals, and nonmutating
7
7
  # methods used in void context.
8
8
  #
9
- # @example
10
- #
9
+ # @example CheckForMethodsWithNoSideEffects: false (default)
11
10
  # # bad
12
- #
13
11
  # def some_method
14
12
  # some_num * 10
15
13
  # do_something
16
14
  # end
17
15
  #
18
- # @example
19
- #
20
- # # bad
21
- #
22
16
  # def some_method(some_var)
23
17
  # some_var
24
18
  # do_something
25
19
  # end
26
20
  #
27
- # @example
28
- #
29
- # # bad, when CheckForMethodsWithNoSideEffects is set true
30
- #
21
+ # @example CheckForMethodsWithNoSideEffects: true
22
+ # # bad
31
23
  # def some_method(some_array)
32
24
  # some_array.sort
33
25
  # do_something(some_array)
34
26
  # end
35
27
  #
36
- # @example
37
- #
38
28
  # # good
39
- #
40
29
  # def some_method
41
30
  # do_something
42
31
  # some_num * 10
43
32
  # end
44
33
  #
45
- # @example
46
- #
47
- # # good
48
- #
49
34
  # def some_method(some_var)
50
35
  # do_something
51
36
  # some_var
52
37
  # end
53
38
  #
54
- # @example
55
- #
56
- # # good, when CheckForMethodsWithNoSideEffects is set true
57
- #
58
39
  # def some_method(some_array)
59
40
  # some_array.sort!
60
41
  # do_something(some_array)
@@ -74,10 +55,10 @@ module RuboCop
74
55
  VOID_CONTEXT_TYPES = %i[def for block].freeze
75
56
  NONMUTATING_METHODS = %i[capitalize chomp chop collect compact
76
57
  delete_prefix delete_suffix downcase
77
- encode flatten gsub lstrip map next reject
78
- reverse rotate rstrip scrub select shuffle
79
- slice sort sort_by squeeze strip sub succ
80
- swapcase tr tr_s transform_values
58
+ encode flatten gsub lstrip map merge next
59
+ reject reverse rotate rstrip scrub select
60
+ shuffle slice sort sort_by squeeze strip sub
61
+ succ swapcase tr tr_s transform_values
81
62
  unicode_normalize uniq upcase].freeze
82
63
 
83
64
  def on_block(node)
@@ -11,7 +11,7 @@ module RuboCop
11
11
  include MethodComplexity
12
12
 
13
13
  MSG = 'Assignment Branch Condition size for %<method>s is too high. ' \
14
- '[%<complexity>.4g/%<max>.4g]'
14
+ '[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
15
15
 
16
16
  private
17
17
 
@@ -128,10 +128,7 @@ module RuboCop
128
128
  return check_uri_line(line, line_index) if allow_uri?
129
129
 
130
130
  register_offense(
131
- source_range(
132
- processed_source.buffer, line_index,
133
- highlight_start(line)...line_length(line)
134
- ),
131
+ excess_range(nil, line, line_index),
135
132
  line,
136
133
  line_index
137
134
  )
@@ -36,15 +36,17 @@ module RuboCop
36
36
  @node.each_node do |child|
37
37
  if child.assignment?
38
38
  @assignment += 1
39
- elsif BRANCH_NODES.include?(child.type)
39
+ elsif branch?(child)
40
40
  evaluate_branch_nodes(child)
41
- elsif CONDITION_NODES.include?(child.type)
42
- @condition += 1 if node_has_else_branch?(child)
43
- @condition += 1
41
+ elsif condition?(child)
42
+ evaluate_condition_node(child)
44
43
  end
45
44
  end
46
45
 
47
- Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2)
46
+ [
47
+ Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2),
48
+ "<#{@assignment}, #{@branch}, #{@condition}>"
49
+ ]
48
50
  end
49
51
 
50
52
  def evaluate_branch_nodes(node)
@@ -55,11 +57,26 @@ module RuboCop
55
57
  end
56
58
  end
57
59
 
58
- def node_has_else_branch?(node)
60
+ def evaluate_condition_node(node)
61
+ @condition += 1 if else_branch?(node)
62
+ @condition += 1
63
+ end
64
+
65
+ def else_branch?(node)
59
66
  %i[case if].include?(node.type) &&
60
67
  node.else? &&
61
68
  node.loc.else.is?('else')
62
69
  end
70
+
71
+ private
72
+
73
+ def branch?(node)
74
+ BRANCH_NODES.include?(node.type)
75
+ end
76
+
77
+ def condition?(node)
78
+ CONDITION_NODES.include?(node.type)
79
+ end
63
80
  end
64
81
  end
65
82
  end
@@ -32,13 +32,14 @@ module RuboCop
32
32
  return unless node.body
33
33
 
34
34
  max = cop_config['Max']
35
- complexity = complexity(node.body)
35
+ complexity, abc_vector = complexity(node.body)
36
36
 
37
37
  return unless complexity > max
38
38
 
39
39
  msg = format(self.class::MSG,
40
40
  method: method_name,
41
41
  complexity: complexity,
42
+ abc_vector: abc_vector,
42
43
  max: max)
43
44
 
44
45
  add_offense(node, message: msg) do
@@ -41,10 +41,13 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def length_in_modifier_form(node, cond, body_length)
44
- indentation = node.loc.keyword.column * indentation_multiplier
45
- kw_length = node.loc.keyword.size
44
+ keyword = node.loc.keyword
45
+
46
+ indentation = keyword.column * indentation_multiplier
47
+ kw_length = keyword.size
46
48
  cond_length = cond.source_range.size
47
49
  space = 1
50
+
48
51
  indentation + body_length + space + kw_length + space + cond_length
49
52
  end
50
53
 
@@ -18,12 +18,7 @@ module RuboCop
18
18
 
19
19
  def check(node, items, kind, begin_pos, end_pos)
20
20
  after_last_item = range_between(begin_pos, end_pos)
21
-
22
- # If there is any heredoc in items, then match the comma succeeding
23
- # any whitespace (except newlines), otherwise allow for newlines
24
- comma_regex = any_heredoc?(items) ? /\A[^\S\n]*,/ : /\A\s*,/
25
- comma_offset = after_last_item.source =~ comma_regex &&
26
- after_last_item.source.index(',')
21
+ comma_offset = comma_offset(items, after_last_item)
27
22
 
28
23
  if comma_offset && !inside_comment?(after_last_item, comma_offset)
29
24
  check_comma(node, kind, after_last_item.begin_pos + comma_offset)
@@ -32,6 +27,13 @@ module RuboCop
32
27
  end
33
28
  end
34
29
 
30
+ def comma_offset(items, range)
31
+ # If there is any heredoc in items, then match the comma succeeding
32
+ # any whitespace (except newlines), otherwise allow for newlines
33
+ comma_regex = any_heredoc?(items) ? /\A[^\S\n]*,/ : /\A\s*,/
34
+ range.source =~ comma_regex && range.source.index(',')
35
+ end
36
+
35
37
  def check_comma(node, kind, comma_pos)
36
38
  return if should_have_comma?(style, node)
37
39
 
@@ -50,14 +50,11 @@ module RuboCop
50
50
  def for_bad_filename(file_path)
51
51
  basename = File.basename(file_path)
52
52
  msg = if filename_good?(basename)
53
- return unless expect_matching_definition?
54
- return if find_class_or_module(processed_source.ast,
55
- to_namespace(file_path))
53
+ return if matching_definition?(file_path)
56
54
 
57
55
  no_definition_message(basename, file_path)
58
56
  else
59
- return if ignore_executable_scripts? &&
60
- processed_source.start_with?('#!')
57
+ return if bad_filename_allowed?
61
58
 
62
59
  other_message(basename)
63
60
  end
@@ -65,6 +62,16 @@ module RuboCop
65
62
  yield source_range(processed_source.buffer, 1, 0), msg
66
63
  end
67
64
 
65
+ def matching_definition?(file_path)
66
+ return true unless expect_matching_definition?
67
+
68
+ find_class_or_module(processed_source.ast, to_namespace(file_path))
69
+ end
70
+
71
+ def bad_filename_allowed?
72
+ ignore_executable_scripts? && processed_source.start_with?('#!')
73
+ end
74
+
68
75
  def no_definition_message(basename, file_path)
69
76
  format(MSG_NO_DEFINITION,
70
77
  basename: basename,
@@ -122,7 +122,7 @@ module RuboCop
122
122
  def unqualified_cop_names
123
123
  @unqualified_cop_names ||=
124
124
  Set.new(@cops_by_cop_name.keys.map { |qn| File.basename(qn) }) <<
125
- 'UnneededCopDisableDirective'
125
+ 'RedundantCopDisableDirective'
126
126
  end
127
127
 
128
128
  # @return [Hash{String => Array<Class>}]
@@ -31,7 +31,7 @@ module RuboCop
31
31
  node_expr = node.source_range
32
32
  attr_expr = attr_name.source_range
33
33
 
34
- if setter && (setter.true_type? || setter.false_type?)
34
+ if setter&.boolean_type?
35
35
  remove = range_between(attr_expr.end_pos, node_expr.end_pos)
36
36
  end
37
37
 
@@ -50,7 +50,7 @@ module RuboCop
50
50
  def replacement_method(node)
51
51
  setter = node.last_argument
52
52
 
53
- if setter && (setter.true_type? || setter.false_type?)
53
+ if setter&.boolean_type?
54
54
  setter.true_type? ? 'attr_accessor' : 'attr_reader'
55
55
  else
56
56
  'attr_reader'
@@ -147,16 +147,16 @@ module RuboCop
147
147
  end
148
148
 
149
149
  def remove_braces_with_whitespace(corrector, node, space)
150
+ loc = node.loc
151
+
150
152
  if node.multiline?
151
153
  remove_braces_with_range(corrector,
152
- left_whole_line_range(node.loc.begin),
153
- right_whole_line_range(node.loc.end))
154
+ left_whole_line_range(loc.begin),
155
+ right_whole_line_range(loc.end))
154
156
  else
155
- right_brace_and_space = right_brace_and_space(node.loc.end, space)
156
- left_brace_and_space = left_brace_and_space(node.loc.begin, space)
157
157
  remove_braces_with_range(corrector,
158
- left_brace_and_space,
159
- right_brace_and_space)
158
+ left_brace_and_space(loc.begin, space),
159
+ right_brace_and_space(loc.end, space))
160
160
  end
161
161
  end
162
162
 
@@ -49,10 +49,10 @@ module RuboCop
49
49
  next unless annotation?(comment) &&
50
50
  !correct_annotation?(first_word, colon, space, note)
51
51
 
52
- length = concat_length(first_word, colon, space)
53
52
  add_offense(
54
53
  comment,
55
- location: annotation_range(comment, margin, length),
54
+ location: annotation_range(comment, margin,
55
+ first_word, colon, space),
56
56
  message: format(note ? MSG : MISSING_NOTE, keyword: first_word)
57
57
  )
58
58
  end
@@ -62,8 +62,7 @@ module RuboCop
62
62
  margin, first_word, colon, space, note = split_comment(comment)
63
63
  return if note.nil?
64
64
 
65
- length = concat_length(first_word, colon, space)
66
- range = annotation_range(comment, margin, length)
65
+ range = annotation_range(comment, margin, first_word, colon, space)
67
66
 
68
67
  ->(corrector) { corrector.replace(range, "#{first_word.upcase}: ") }
69
68
  end
@@ -79,8 +78,9 @@ module RuboCop
79
78
  !comment_line?(comment.loc.expression.source_line)
80
79
  end
81
80
 
82
- def annotation_range(comment, margin, length)
81
+ def annotation_range(comment, margin, first_word, colon, space)
83
82
  start = comment.loc.expression.begin_pos + margin.length
83
+ length = concat_length(first_word, colon, space)
84
84
  range_between(start, start + length)
85
85
  end
86
86
 
@@ -33,13 +33,7 @@ module RuboCop
33
33
  end
34
34
 
35
35
  def autocorrect(token)
36
- raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
37
-
38
- regex = Regexp.new(notice)
39
- unless autocorrect_notice =~ regex
40
- raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must " \
41
- "match Notice /#{notice}/"
42
- end
36
+ verify_autocorrect_notice!
43
37
 
44
38
  lambda do |corrector|
45
39
  range = token.nil? ? range_between(0, 0) : token.pos
@@ -57,6 +51,16 @@ module RuboCop
57
51
  cop_config['AutocorrectNotice']
58
52
  end
59
53
 
54
+ def verify_autocorrect_notice!
55
+ raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
56
+
57
+ regex = Regexp.new(notice)
58
+ return if autocorrect_notice =~ regex
59
+
60
+ raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must " \
61
+ "match Notice /#{notice}/"
62
+ end
63
+
60
64
  def insert_notice_before(processed_source)
61
65
  token_index = 0
62
66
  token_index += 1 if shebang_token?(processed_source, token_index)
@@ -47,6 +47,50 @@ module RuboCop
47
47
  # def foo.bar
48
48
  # puts baz
49
49
  # end
50
+ #
51
+ # @example RequireForNonPublicMethods: false (default)
52
+ # # good
53
+ # class Foo
54
+ # protected
55
+ # def do_something
56
+ # end
57
+ # end
58
+ #
59
+ # class Foo
60
+ # private
61
+ # def do_something
62
+ # end
63
+ # end
64
+ #
65
+ # @example RequireForNonPublicMethods: true
66
+ # # bad
67
+ # class Foo
68
+ # protected
69
+ # def do_something
70
+ # end
71
+ # end
72
+ #
73
+ # class Foo
74
+ # private
75
+ # def do_something
76
+ # end
77
+ # end
78
+ #
79
+ # # good
80
+ # class Foo
81
+ # protected
82
+ # # Documentation
83
+ # def do_something
84
+ # end
85
+ # end
86
+ #
87
+ # class Foo
88
+ # private
89
+ # # Documentation
90
+ # def do_something
91
+ # end
92
+ # end
93
+ #
50
94
  class DocumentationMethod < Cop
51
95
  include DocumentationComment
52
96
  include DefNode
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Lint/UnneededCopDisableDirective
3
+ # rubocop:disable Lint/RedundantCopDisableDirective
4
4
  # rubocop:disable Style/DoubleCopDisableDirective
5
5
 
6
6
  module RuboCop
@@ -26,7 +26,7 @@ module RuboCop
26
26
  #
27
27
  class DoubleCopDisableDirective < Cop
28
28
  # rubocop:enable Style/For, Style/DoubleCopDisableDirective
29
- # rubocop:enable Lint/UnneededCopDisableDirective, Metrics/AbcSize
29
+ # rubocop:enable Lint/RedundantCopDisableDirective, Metrics/AbcSize
30
30
  MSG = 'More than one disable comment on one line.'
31
31
 
32
32
  def investigate(processed_source)
@@ -84,8 +84,8 @@ module RuboCop
84
84
 
85
85
  next unless conditions.size > 1
86
86
 
87
- range = range_between(conditions.first.loc.expression.begin_pos,
88
- conditions.last.loc.expression.end_pos)
87
+ range = range_between(conditions.first.source_range.begin_pos,
88
+ conditions.last.source_range.end_pos)
89
89
 
90
90
  corrector.replace(range, conditions.map(&:source).join(' || '))
91
91
  end
@@ -84,8 +84,8 @@ module RuboCop
84
84
  # to rewrite the arguments to wrap them in parenthesis.
85
85
  args = node.parent.arguments
86
86
 
87
- range_between(args[0].loc.expression.begin_pos - 1,
88
- args[-1].loc.expression.end_pos)
87
+ range_between(args[0].source_range.begin_pos - 1,
88
+ args[-1].source_range.end_pos)
89
89
  else
90
90
  node.source_range
91
91
  end