rubocop 0.86.0 → 0.87.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +46 -4
  4. data/lib/rubocop.rb +8 -1
  5. data/lib/rubocop/cli.rb +0 -2
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +40 -5
  7. data/lib/rubocop/cli/command/show_cops.rb +1 -1
  8. data/lib/rubocop/config_loader.rb +21 -62
  9. data/lib/rubocop/config_obsoletion.rb +0 -1
  10. data/lib/rubocop/cop/autocorrect_logic.rb +13 -23
  11. data/lib/rubocop/cop/base.rb +399 -0
  12. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +10 -20
  13. data/lib/rubocop/cop/commissioner.rb +48 -50
  14. data/lib/rubocop/cop/cop.rb +85 -236
  15. data/lib/rubocop/cop/corrector.rb +38 -115
  16. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  17. data/lib/rubocop/cop/generator.rb +1 -1
  18. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +11 -14
  19. data/lib/rubocop/cop/layout/case_indentation.rb +18 -19
  20. data/lib/rubocop/cop/layout/class_structure.rb +2 -37
  21. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
  23. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
  24. data/lib/rubocop/cop/layout/multiline_block_layout.rb +0 -1
  25. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +19 -25
  26. data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
  27. data/lib/rubocop/cop/legacy/corrector.rb +29 -0
  28. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -4
  29. data/lib/rubocop/cop/lint/interpolation_check.rb +13 -0
  30. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  31. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  32. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -3
  33. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  34. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -23
  35. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +2 -2
  36. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +8 -0
  37. data/lib/rubocop/cop/lint/syntax.rb +11 -26
  38. data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
  39. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  40. data/lib/rubocop/cop/metrics/block_length.rb +22 -0
  41. data/lib/rubocop/cop/metrics/class_length.rb +25 -2
  42. data/lib/rubocop/cop/metrics/method_length.rb +23 -0
  43. data/lib/rubocop/cop/metrics/module_length.rb +25 -2
  44. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +129 -0
  45. data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
  46. data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
  47. data/lib/rubocop/cop/mixin/code_length.rb +4 -0
  48. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  49. data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
  50. data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
  51. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
  52. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -2
  53. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -13
  54. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -2
  55. data/lib/rubocop/cop/mixin/visibility_help.rb +50 -0
  56. data/lib/rubocop/cop/naming/ascii_identifiers.rb +27 -4
  57. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +2 -2
  58. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  59. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  60. data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
  61. data/lib/rubocop/cop/naming/variable_name.rb +1 -1
  62. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  63. data/lib/rubocop/cop/offense.rb +16 -2
  64. data/lib/rubocop/cop/style/accessor_grouping.rb +140 -0
  65. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +145 -0
  66. data/lib/rubocop/cop/style/class_vars.rb +21 -0
  67. data/lib/rubocop/cop/style/date_time.rb +1 -1
  68. data/lib/rubocop/cop/style/dir.rb +2 -2
  69. data/lib/rubocop/cop/style/empty_literal.rb +5 -5
  70. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
  71. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -0
  72. data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
  73. data/lib/rubocop/cop/style/mutable_constant.rb +4 -4
  74. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -5
  75. data/lib/rubocop/cop/style/proc.rb +1 -1
  76. data/lib/rubocop/cop/style/random_with_offset.rb +4 -10
  77. data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
  78. data/lib/rubocop/cop/style/redundant_exception.rb +14 -10
  79. data/lib/rubocop/cop/style/redundant_fetch_block.rb +26 -7
  80. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  81. data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
  82. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
  83. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -2
  84. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
  85. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  86. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  87. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
  88. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  89. data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
  90. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -2
  91. data/lib/rubocop/cop/team.rb +97 -81
  92. data/lib/rubocop/cop/utils/format_string.rb +1 -2
  93. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  94. data/lib/rubocop/name_similarity.rb +1 -3
  95. data/lib/rubocop/options.rb +15 -8
  96. data/lib/rubocop/rake_task.rb +6 -9
  97. data/lib/rubocop/rspec/cop_helper.rb +4 -4
  98. data/lib/rubocop/rspec/expect_offense.rb +22 -17
  99. data/lib/rubocop/rspec/shared_contexts.rb +7 -7
  100. data/lib/rubocop/runner.rb +31 -29
  101. data/lib/rubocop/target_ruby.rb +1 -1
  102. data/lib/rubocop/version.rb +1 -1
  103. metadata +16 -7
  104. data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
@@ -18,7 +18,7 @@ module RuboCop
18
18
  'name its argument `other`.'
19
19
 
20
20
  OP_LIKE_METHODS = %i[eql? equal?].freeze
21
- BLACKLISTED = %i[+@ -@ [] []= << === `].freeze
21
+ EXCLUDED = %i[+@ -@ [] []= << === `].freeze
22
22
 
23
23
  def_node_matcher :op_method_candidate?, <<~PATTERN
24
24
  (def [#op_method? $_] (args $(arg [!:other !:_other])) _)
@@ -33,7 +33,7 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def op_method?(name)
36
- return false if BLACKLISTED.include?(name)
36
+ return false if EXCLUDED.include?(name)
37
37
 
38
38
  !/\A\w/.match?(name) || OP_LIKE_METHODS.include?(name)
39
39
  end
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # # good
30
30
  # def fooBar; end
31
- class MethodName < Cop
31
+ class MethodName < Base
32
32
  include ConfigurableNaming
33
33
  include IgnoredPattern
34
34
  include RangeHelp
@@ -49,7 +49,7 @@ module RuboCop
49
49
  def on_def(node)
50
50
  return unless node.arguments?
51
51
 
52
- check(node, node.arguments.reject(&:forward_args_type?))
52
+ check(node, node.arguments)
53
53
  end
54
54
  alias on_defs on_def
55
55
  end
@@ -28,6 +28,8 @@ module RuboCop
28
28
  # def value?
29
29
  # end
30
30
  class PredicateName < Cop
31
+ include AllowedMethods
32
+
31
33
  def_node_matcher :dynamic_method_define, <<~PATTERN
32
34
  (send nil? #method_definition_macros
33
35
  (sym $_)
@@ -70,7 +72,7 @@ module RuboCop
70
72
  !method_name.match?(/^#{prefix}[^0-9]/) ||
71
73
  method_name == expected_name(method_name, prefix) ||
72
74
  method_name.end_with?('=') ||
73
- allowed_methods.include?(method_name)
75
+ allowed_method?(method_name)
74
76
  end
75
77
 
76
78
  def expected_name(method_name, prefix)
@@ -95,10 +97,6 @@ module RuboCop
95
97
  cop_config['NamePrefix']
96
98
  end
97
99
 
98
- def allowed_methods
99
- cop_config['AllowedMethods']
100
- end
101
-
102
100
  def method_definition_macros(macro_name)
103
101
  cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
104
102
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
  #
20
20
  # # good
21
21
  # fooBar = 1
22
- class VariableName < Cop
22
+ class VariableName < Base
23
23
  include ConfigurableNaming
24
24
 
25
25
  MSG = 'Use %<style>s for variable names.'
@@ -37,7 +37,7 @@ module RuboCop
37
37
  # variableone = 1
38
38
  #
39
39
  # variable_one = 1
40
- class VariableNumber < Cop
40
+ class VariableNumber < Base
41
41
  include ConfigurableNumbering
42
42
 
43
43
  MSG = 'Use %<style>s for variable numbers.'
@@ -54,14 +54,28 @@ module RuboCop
54
54
  # @api private
55
55
  attr_reader :status
56
56
 
57
+ # @api public
58
+ #
59
+ # @!attribute [r] corrector
60
+ #
61
+ # @return [Corrector | nil]
62
+ # the autocorrection for this offense, or `nil` when not available
63
+ attr_reader :corrector
64
+
65
+ PseudoSourceRange = Struct.new(:line, :column, :source_line, :begin_pos,
66
+ :end_pos)
67
+
68
+ NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 1).freeze
69
+
57
70
  # @api private
58
- def initialize(severity, location, message, cop_name,
59
- status = :uncorrected)
71
+ def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
72
+ status = :uncorrected, corrector = nil)
60
73
  @severity = RuboCop::Cop::Severity.new(severity)
61
74
  @location = location
62
75
  @message = message.freeze
63
76
  @cop_name = cop_name.freeze
64
77
  @status = status
78
+ @corrector = corrector
65
79
  freeze
66
80
  end
67
81
 
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for grouping of accessors in `class` and `module` bodies.
7
+ # By default it enforces accessors to be placed in grouped declarations,
8
+ # but it can be configured to enforce separating them in multiple declarations.
9
+ #
10
+ # @example EnforcedStyle: grouped (default)
11
+ # # bad
12
+ # class Foo
13
+ # attr_reader :bar
14
+ # attr_reader :baz
15
+ # end
16
+ #
17
+ # # good
18
+ # class Foo
19
+ # attr_reader :bar, :baz
20
+ # end
21
+ #
22
+ # @example EnforcedStyle: separated
23
+ # # bad
24
+ # class Foo
25
+ # attr_reader :bar, :baz
26
+ # end
27
+ #
28
+ # # good
29
+ # class Foo
30
+ # attr_reader :bar
31
+ # attr_reader :baz
32
+ # end
33
+ #
34
+ class AccessorGrouping < Cop
35
+ include ConfigurableEnforcedStyle
36
+ include VisibilityHelp
37
+
38
+ GROUPED_MSG = 'Group together all `%<accessor>s` attributes.'
39
+ SEPARATED_MSG = 'Use one attribute per `%<accessor>s`.'
40
+
41
+ ACCESSOR_METHODS = %i[attr_reader attr_writer attr_accessor attr].freeze
42
+
43
+ def on_class(node)
44
+ class_send_elements(node).each do |macro|
45
+ next unless accessor?(macro)
46
+
47
+ check(macro)
48
+ end
49
+ end
50
+ alias on_sclass on_class
51
+ alias on_module on_class
52
+
53
+ def autocorrect(node)
54
+ lambda do |corrector|
55
+ corrector.replace(node, correction(node))
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def class_send_elements(class_node)
62
+ class_def = class_node.body
63
+
64
+ if !class_def || class_def.def_type?
65
+ []
66
+ elsif class_def.send_type?
67
+ [class_def]
68
+ else
69
+ class_def.each_child_node(:send).to_a
70
+ end
71
+ end
72
+
73
+ def accessor?(send_node)
74
+ send_node.macro? && ACCESSOR_METHODS.include?(send_node.method_name)
75
+ end
76
+
77
+ def check(send_node)
78
+ if grouped_style? && sibling_accessors(send_node).size > 1
79
+ add_offense(send_node)
80
+ elsif separated_style? && send_node.arguments.size > 1
81
+ add_offense(send_node)
82
+ end
83
+ end
84
+
85
+ def grouped_style?
86
+ style == :grouped
87
+ end
88
+
89
+ def separated_style?
90
+ style == :separated
91
+ end
92
+
93
+ def sibling_accessors(send_node)
94
+ send_node.parent.each_child_node(:send).select do |sibling|
95
+ accessor?(sibling) &&
96
+ sibling.method?(send_node.method_name) &&
97
+ node_visibility(sibling) == node_visibility(send_node)
98
+ end
99
+ end
100
+
101
+ def message(send_node)
102
+ msg = grouped_style? ? GROUPED_MSG : SEPARATED_MSG
103
+ format(msg, accessor: send_node.method_name)
104
+ end
105
+
106
+ def correction(node)
107
+ if grouped_style?
108
+ accessors = sibling_accessors(node)
109
+ if node == accessors.first
110
+ group_accessors(node, accessors)
111
+ else
112
+ ''
113
+ end
114
+ else
115
+ separate_accessors(node)
116
+ end
117
+ end
118
+
119
+ def group_accessors(node, accessors)
120
+ accessor_names = accessors.flat_map do |accessor|
121
+ accessor.arguments.map(&:source)
122
+ end
123
+
124
+ "#{node.method_name} #{accessor_names.join(', ')}"
125
+ end
126
+
127
+ def separate_accessors(node)
128
+ node.arguments.map do |arg|
129
+ if arg == node.arguments.first
130
+ "#{node.method_name} #{arg.source}"
131
+ else
132
+ indent = ' ' * node.loc.column
133
+ "#{indent}#{node.method_name} #{arg.source}"
134
+ end
135
+ end.join("\n")
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Style
8
+ # This cop checks for places where `attr_reader` and `attr_writer`
9
+ # for the same method can be combined into single `attr_accessor`.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # class Foo
14
+ # attr_reader :bar
15
+ # attr_writer :bar
16
+ # end
17
+ #
18
+ # # good
19
+ # class Foo
20
+ # attr_accessor :bar
21
+ # end
22
+ #
23
+ class BisectedAttrAccessor < Cop
24
+ include VisibilityHelp
25
+
26
+ MSG = 'Combine both accessors into `attr_accessor %<name>s`.'
27
+
28
+ def on_class(class_node)
29
+ VISIBILITY_SCOPES.each do |visibility|
30
+ reader_names, writer_names = accessor_names(class_node, visibility)
31
+
32
+ accessor_macroses(class_node, visibility).each do |macro|
33
+ check(macro, reader_names, writer_names)
34
+ end
35
+ end
36
+ end
37
+ alias on_sclass on_class
38
+ alias on_module on_class
39
+
40
+ def autocorrect(node)
41
+ macro = node.parent
42
+
43
+ lambda do |corrector|
44
+ corrector.replace(macro, replacement(macro, node))
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def accessor_names(class_node, visibility)
51
+ reader_names = Set.new
52
+ writer_names = Set.new
53
+
54
+ accessor_macroses(class_node, visibility).each do |macro|
55
+ names = macro.arguments.map(&:source)
56
+
57
+ names.each do |name|
58
+ if attr_reader?(macro)
59
+ reader_names.add(name)
60
+ else
61
+ writer_names.add(name)
62
+ end
63
+ end
64
+ end
65
+
66
+ [reader_names, writer_names]
67
+ end
68
+
69
+ def accessor_macroses(class_node, visibility)
70
+ class_def = class_node.body
71
+ return [] if !class_def || class_def.def_type?
72
+
73
+ send_nodes =
74
+ if class_def.send_type?
75
+ [class_def]
76
+ else
77
+ class_def.each_child_node(:send)
78
+ end
79
+
80
+ send_nodes.select { |node| attr_within_visibility_scope?(node, visibility) }
81
+ end
82
+
83
+ def attr_within_visibility_scope?(node, visibility)
84
+ node.macro? &&
85
+ (attr_reader?(node) || attr_writer?(node)) &&
86
+ node_visibility(node) == visibility
87
+ end
88
+
89
+ def attr_reader?(send_node)
90
+ send_node.method?(:attr_reader) || send_node.method?(:attr)
91
+ end
92
+
93
+ def attr_writer?(send_node)
94
+ send_node.method?(:attr_writer)
95
+ end
96
+
97
+ def check(macro, reader_names, writer_names)
98
+ macro.arguments.each do |arg_node|
99
+ name = arg_node.source
100
+
101
+ if (attr_reader?(macro) && writer_names.include?(name)) ||
102
+ (attr_writer?(macro) && reader_names.include?(name))
103
+ add_offense(arg_node, message: format(MSG, name: name))
104
+ end
105
+ end
106
+ end
107
+
108
+ def replacement(macro, node)
109
+ class_node = macro.each_ancestor(:class, :sclass, :module).first
110
+ reader_names, writer_names = accessor_names(class_node, node_visibility(macro))
111
+
112
+ rest_args = rest_args(macro.arguments, reader_names, writer_names)
113
+
114
+ if attr_reader?(macro)
115
+ attr_reader_replacement(macro, node, rest_args)
116
+ elsif rest_args.empty?
117
+ ''
118
+ else
119
+ "#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
120
+ end
121
+ end
122
+
123
+ def rest_args(args, reader_names, writer_names)
124
+ args.reject do |arg|
125
+ name = arg.source
126
+ reader_names.include?(name) && writer_names.include?(name)
127
+ end
128
+ end
129
+
130
+ def attr_reader_replacement(macro, node, rest_args)
131
+ if rest_args.empty?
132
+ "attr_accessor #{node.source}"
133
+ else
134
+ "attr_accessor #{node.source}\n"\
135
+ "#{indent(macro)}#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
136
+ end
137
+ end
138
+
139
+ def indent(node)
140
+ ' ' * node.loc.column
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -19,6 +19,15 @@ module RuboCop
19
19
  # @@test = 10
20
20
  # end
21
21
  #
22
+ # class A
23
+ # def self.test(name, value)
24
+ # class_variable_set("@@#{name}", value)
25
+ # end
26
+ # end
27
+ #
28
+ # class A; end
29
+ # A.class_variable_set(:@@test, 10)
30
+ #
22
31
  # # good
23
32
  # class A
24
33
  # @test = 10
@@ -30,6 +39,12 @@ module RuboCop
30
39
  # end
31
40
  # end
32
41
  #
42
+ # class A
43
+ # def self.test(name)
44
+ # class_variable_get("@@#{name}") # you can access without offense
45
+ # end
46
+ # end
47
+ #
33
48
  class ClassVars < Cop
34
49
  MSG = 'Replace class var %<class_var>s with a class ' \
35
50
  'instance var.'
@@ -38,6 +53,12 @@ module RuboCop
38
53
  add_offense(node, location: :name)
39
54
  end
40
55
 
56
+ def on_send(node)
57
+ return unless node.method?(:class_variable_set)
58
+
59
+ add_offense(node.first_argument)
60
+ end
61
+
41
62
  def message(node)
42
63
  class_var, = *node
43
64
  format(MSG, class_var: class_var)
@@ -50,7 +50,7 @@ module RuboCop
50
50
  PATTERN
51
51
 
52
52
  def_node_matcher :historic_date?, <<~PATTERN
53
- (send _ _ _ (const (const nil? :Date) _))
53
+ (send _ _ _ (const (const {nil? (cbase)} :Date) _))
54
54
  PATTERN
55
55
 
56
56
  def_node_matcher :to_datetime?, <<~PATTERN