rubocop 0.36.0 → 0.37.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -2
  3. data/README.md +10 -1
  4. data/assets/output.html.erb +55 -1
  5. data/config/default.yml +9 -3
  6. data/config/disabled.yml +21 -0
  7. data/config/enabled.yml +11 -10
  8. data/lib/rubocop.rb +9 -2
  9. data/lib/rubocop/ast_node.rb +67 -19
  10. data/lib/rubocop/ast_node/builder.rb +1 -0
  11. data/lib/rubocop/ast_node/sexp.rb +1 -0
  12. data/lib/rubocop/ast_node/traversal.rb +171 -0
  13. data/lib/rubocop/cached_data.rb +4 -1
  14. data/lib/rubocop/cli.rb +1 -1
  15. data/lib/rubocop/config.rb +36 -20
  16. data/lib/rubocop/config_loader.rb +6 -5
  17. data/lib/rubocop/cop/commissioner.rb +27 -18
  18. data/lib/rubocop/cop/cop.rb +7 -6
  19. data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
  20. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  21. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  22. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  23. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  24. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
  25. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
  26. data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
  27. data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
  28. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
  29. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  30. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
  31. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
  32. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  33. data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
  34. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
  35. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  37. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
  38. data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
  39. data/lib/rubocop/cop/performance/casecmp.rb +56 -17
  40. data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
  41. data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
  42. data/lib/rubocop/cop/performance/times_map.rb +3 -4
  43. data/lib/rubocop/cop/severity.rb +1 -1
  44. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  45. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/and_or.rb +1 -1
  47. data/lib/rubocop/cop/style/block_comments.rb +2 -0
  48. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
  49. data/lib/rubocop/cop/style/copyright.rb +2 -2
  50. data/lib/rubocop/cop/style/documentation.rb +19 -29
  51. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  52. data/lib/rubocop/cop/style/else_alignment.rb +2 -2
  53. data/lib/rubocop/cop/style/encoding.rb +1 -1
  54. data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
  55. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
  56. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  57. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
  58. data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
  59. data/lib/rubocop/cop/style/indentation_width.rb +3 -7
  60. data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
  61. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  62. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
  63. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
  64. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
  65. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
  66. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
  67. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
  68. data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
  69. data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
  70. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
  71. data/lib/rubocop/cop/style/next.rb +32 -11
  72. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  73. data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
  74. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
  75. data/lib/rubocop/cop/style/send.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
  77. data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
  78. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  79. data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
  80. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  81. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  82. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
  83. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
  84. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  85. data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
  86. data/lib/rubocop/cop/team.rb +30 -5
  87. data/lib/rubocop/cop/util.rb +16 -1
  88. data/lib/rubocop/cop/variable_force.rb +3 -12
  89. data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
  90. data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
  91. data/lib/rubocop/cop/variable_force/reference.rb +3 -3
  92. data/lib/rubocop/cop/variable_force/scope.rb +8 -7
  93. data/lib/rubocop/cop/variable_force/variable.rb +3 -3
  94. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  95. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  96. data/lib/rubocop/node_pattern.rb +1 -1
  97. data/lib/rubocop/options.rb +10 -10
  98. data/lib/rubocop/path_util.rb +5 -0
  99. data/lib/rubocop/processed_source.rb +8 -2
  100. data/lib/rubocop/result_cache.rb +1 -1
  101. data/lib/rubocop/runner.rb +1 -1
  102. data/lib/rubocop/token.rb +2 -2
  103. data/lib/rubocop/version.rb +1 -1
  104. data/relnotes/v0.30.1.md +1 -0
  105. data/relnotes/v0.33.0.md +1 -1
  106. data/relnotes/v0.36.0.md +2 -1
  107. data/relnotes/v0.37.0.md +200 -0
  108. data/rubocop.gemspec +2 -1
  109. metadata +28 -7
  110. data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
  111. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  class Node
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  # This module provides a shorthand method to create a {Node} like `AST::Sexp`.
@@ -0,0 +1,171 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ class Node
6
+ # Provides methods for traversing an AST.
7
+ # Does not transform an AST; for that, use Parser::AST::Processor.
8
+ # Override methods to perform custom processing. Remember to call `super`
9
+ # if you want to recursively process descendant nodes.
10
+ module Traversal
11
+ def walk(node)
12
+ return if node.nil?
13
+ send(:"on_#{node.type}", node)
14
+ nil
15
+ end
16
+
17
+ NO_CHILD_NODES = [:true, :false, :nil, :int, :float, :complex,
18
+ :rational, :str, :sym, :regopt, :self, :lvar,
19
+ :ivar, :cvar, :gvar, :nth_ref, :back_ref, :cbase,
20
+ :arg, :restarg, :blockarg, :shadowarg,
21
+ :kwrestarg, :zsuper, :lambda, :redo, :retry].freeze
22
+ ONE_CHILD_NODE = [:splat, :kwsplat, :block_pass, :not, :break, :next,
23
+ :return, :preexe, :postexe, :match_current_line,
24
+ :defined?, :arg_expr].freeze
25
+ MANY_CHILD_NODES = [:dstr, :dsym, :xstr, :regexp, :array, :hash, :pair,
26
+ :irange, :erange, :mlhs, :masgn, :or_asgn, :and_asgn,
27
+ :undef, :alias, :args, :super, :yield, :or, :and,
28
+ :while_post, :until_post, :iflipflop, :eflipflop,
29
+ :match_with_lvasgn, :begin, :kwbegin].freeze
30
+ SECOND_CHILD_ONLY = [:lvasgn, :ivasgn, :cvasgn, :gvasgn, :optarg, :kwarg,
31
+ :kwoptarg].freeze
32
+
33
+ NO_CHILD_NODES.each do |type|
34
+ module_eval("def on_#{type}(node); end")
35
+ end
36
+
37
+ ONE_CHILD_NODE.each do |type|
38
+ module_eval(<<-END)
39
+ def on_#{type}(node)
40
+ if (child = node.children[0])
41
+ send(:"on_\#{child.type}", child)
42
+ end
43
+ end
44
+ END
45
+ end
46
+
47
+ MANY_CHILD_NODES.each do |type|
48
+ module_eval(<<-END)
49
+ def on_#{type}(node)
50
+ node.children.each { |child| send(:"on_\#{child.type}", child) }
51
+ nil
52
+ end
53
+ END
54
+ end
55
+
56
+ SECOND_CHILD_ONLY.each do |type|
57
+ # Guard clause is for nodes nested within mlhs
58
+ module_eval(<<-END)
59
+ def on_#{type}(node)
60
+ if (child = node.children[1])
61
+ send(:"on_\#{child.type}", child)
62
+ end
63
+ end
64
+ END
65
+ end
66
+
67
+ def on_const(node)
68
+ return unless (child = node.children[0])
69
+ send(:"on_#{child.type}", child)
70
+ end
71
+
72
+ def on_casgn(node)
73
+ children = node.children
74
+ if (child = children[0]) # always const???
75
+ send(:"on_#{child.type}", child)
76
+ end
77
+ return unless (child = children[2])
78
+ send(:"on_#{child.type}", child)
79
+ end
80
+
81
+ def on_class(node)
82
+ children = node.children
83
+ child = children[0] # always const???
84
+ send(:"on_#{child.type}", child)
85
+ if (child = children[1])
86
+ send(:"on_#{child.type}", child)
87
+ end
88
+ return unless (child = children[2])
89
+ send(:"on_#{child.type}", child)
90
+ end
91
+
92
+ def on_def(node)
93
+ children = node.children
94
+ on_args(children[1])
95
+ return unless (child = children[2])
96
+ send(:"on_#{child.type}", child)
97
+ end
98
+
99
+ def on_send(node)
100
+ node.children.each_with_index do |child, i|
101
+ next if i == 1
102
+ send(:"on_#{child.type}", child) if child
103
+ end
104
+ nil
105
+ end
106
+
107
+ alias on_csend on_send
108
+
109
+ def on_op_asgn(node)
110
+ children = node.children
111
+ child = children[0]
112
+ send(:"on_#{child.type}", child)
113
+ child = children[2]
114
+ send(:"on_#{child.type}", child)
115
+ end
116
+
117
+ def on_defs(node)
118
+ children = node.children
119
+ child = children[0]
120
+ send(:"on_#{child.type}", child)
121
+ on_args(children[2])
122
+ return unless (child = children[3])
123
+ send(:"on_#{child.type}", child)
124
+ end
125
+
126
+ def on_if(node)
127
+ children = node.children
128
+ child = children[0]
129
+ send(:"on_#{child.type}", child)
130
+ if (child = children[1])
131
+ send(:"on_#{child.type}", child)
132
+ end
133
+ return unless (child = children[2])
134
+ send(:"on_#{child.type}", child)
135
+ end
136
+
137
+ def on_while(node)
138
+ children = node.children
139
+ child = children[0]
140
+ send(:"on_#{child.type}", child)
141
+ return unless (child = children[1])
142
+ send(:"on_#{child.type}", child)
143
+ end
144
+
145
+ alias on_until on_while
146
+ alias on_when on_while
147
+ alias on_module on_while
148
+ alias on_sclass on_while
149
+
150
+ def on_block(node)
151
+ children = node.children
152
+ on_send(children[0])
153
+ on_args(children[1])
154
+ return unless (child = children[2])
155
+ send(:"on_#{child.type}", child)
156
+ end
157
+
158
+ def on_case(node)
159
+ node.children.each do |child|
160
+ send(:"on_#{child.type}", child) if child
161
+ end
162
+ nil
163
+ end
164
+
165
+ alias on_rescue on_case
166
+ alias on_resbody on_case
167
+ alias on_ensure on_case
168
+ alias on_for on_case
169
+ end
170
+ end
171
+ end
@@ -31,7 +31,10 @@ module RuboCop
31
31
  end
32
32
 
33
33
  {
34
- severity: offense.severity,
34
+ # Calling #to_s here ensures that the serialization works when using
35
+ # other json serializers such as Oj. Some of these gems do not call
36
+ # #to_s implicitly.
37
+ severity: offense.severity.to_s,
35
38
  location: {
36
39
  begin_pos: offense.location.begin_pos,
37
40
  end_pos: offense.location.end_pos
@@ -78,7 +78,7 @@ module RuboCop
78
78
  puts RuboCop::Version.version(false) if @options[:version]
79
79
  puts RuboCop::Version.version(true) if @options[:verbose_version]
80
80
  print_available_cops if @options[:show_cops]
81
- fail Finished
81
+ raise Finished
82
82
  end
83
83
 
84
84
  def apply_default_formatter
@@ -17,6 +17,27 @@ module RuboCop
17
17
  COMMON_PARAMS = %w(Exclude Include Severity
18
18
  AutoCorrect StyleGuide Details).freeze
19
19
  KNOWN_RUBIES = [1.9, 2.0, 2.1, 2.2, 2.3].freeze
20
+ OBSOLETE_COPS = {
21
+ 'Style/TrailingComma' =>
22
+ 'The `Style/TrailingComma` cop no longer exists. Please use ' \
23
+ '`Style/TrailingCommaInLiteral` and/or ' \
24
+ '`Style/TrailingCommaInArguments` instead.',
25
+ 'Rails/DefaultScope' =>
26
+ 'The `Rails/DefaultScope` cop no longer exists.',
27
+ 'Style/SingleSpaceBeforeFirstArg' =>
28
+ 'The `Style/SingleSpaceBeforeFirstArg` cop has been renamed to ' \
29
+ '`Style/SpaceBeforeFirstArg. ',
30
+ 'Lint/SpaceBeforeFirstArg' =>
31
+ 'The `Lint/SpaceBeforeFirstArg` cop has been removed, since it was a ' \
32
+ 'duplicate of `Style/SpaceBeforeFirstArg`. Please use ' \
33
+ '`Style/SpaceBeforeFirstArg` instead.',
34
+ 'Style/SpaceAfterControlKeyword' =>
35
+ 'The `Style/SpaceAfterControlKeyword` cop has been removed. Please ' \
36
+ 'use `Style/SpaceAroundKeyword` instead.',
37
+ 'Style/SpaceBeforeModifierKeyword' =>
38
+ 'The `Style/SpaceBeforeModifierKeyword` cop has been removed. Please ' \
39
+ 'use `Style/SpaceAroundKeyword` instead.'
40
+ }.freeze
20
41
 
21
42
  attr_reader :loaded_path
22
43
 
@@ -34,7 +55,7 @@ module RuboCop
34
55
  next unless self[key]['Exclude']
35
56
 
36
57
  self[key]['Exclude'].map! do |exclude_elem|
37
- if exclude_elem.is_a?(String) && !exclude_elem.start_with?('/')
58
+ if exclude_elem.is_a?(String) && !absolute?(exclude_elem)
38
59
  File.expand_path(File.join(base_dir_for_path_parameters,
39
60
  exclude_elem))
40
61
  else
@@ -51,7 +72,7 @@ module RuboCop
51
72
  self['AllCops'] ||= {}
52
73
  excludes = self['AllCops']['Exclude'] ||= []
53
74
  highest_config['AllCops']['Exclude'].each do |path|
54
- unless path.is_a?(Regexp) || path.start_with?('/')
75
+ unless path.is_a?(Regexp) || absolute?(path)
55
76
  path = File.join(File.dirname(highest_config.loaded_path), path)
56
77
  end
57
78
  excludes << path unless excludes.include?(path)
@@ -76,11 +97,7 @@ module RuboCop
76
97
  end
77
98
 
78
99
  def cop_enabled?(cop)
79
- department = if cop.respond_to?(:cop_type)
80
- cop.cop_type.to_s.capitalize
81
- else
82
- cop.split('/')[-2]
83
- end
100
+ department = cop.cop_type.to_s.capitalize!
84
101
 
85
102
  if (dept_config = self[department])
86
103
  return false if dept_config['Enabled'] == false
@@ -182,9 +199,9 @@ module RuboCop
182
199
  def warn_about_unrecognized_cops(invalid_cop_names)
183
200
  invalid_cop_names.each do |name|
184
201
  if name == 'Syntax'
185
- fail ValidationError,
186
- "configuration for Syntax cop found in #{loaded_path}\n" \
187
- 'This cop cannot be configured.'
202
+ raise ValidationError,
203
+ "configuration for Syntax cop found in #{loaded_path}\n" \
204
+ 'This cop cannot be configured.'
188
205
  end
189
206
 
190
207
  # There could be a custom cop with this name. If so, don't warn
@@ -197,7 +214,7 @@ module RuboCop
197
214
 
198
215
  def validate_section_presence(name)
199
216
  return unless key?(name) && self[name].nil?
200
- fail ValidationError, "empty section #{name} found in #{loaded_path}"
217
+ raise ValidationError, "empty section #{name} found in #{loaded_path}"
201
218
  end
202
219
 
203
220
  def validate_parameter_names(valid_cop_names)
@@ -222,7 +239,7 @@ module RuboCop
222
239
  msg = "invalid EnforcedStyle '#{style}' for #{name} found in " \
223
240
  "#{loaded_path}\n" \
224
241
  "Valid choices are: #{valid.join(', ')}"
225
- fail ValidationError, msg
242
+ raise ValidationError, msg
226
243
  end
227
244
  end
228
245
 
@@ -239,19 +256,18 @@ module RuboCop
239
256
 
240
257
  def check_obsolete_parameter(cop, parameter, alternative = nil)
241
258
  if key?(cop) && self[cop].key?(parameter)
242
- fail ValidationError, "obsolete parameter #{parameter} (for #{cop}) " \
259
+ raise ValidationError, "obsolete parameter #{parameter} (for #{cop}) " \
243
260
  "found in #{loaded_path}" \
244
261
  "#{"\n" if alternative}#{alternative}"
245
262
  end
246
263
  end
247
264
 
248
265
  def reject_obsolete_cops
249
- if key?('Style/TrailingComma')
250
- fail ValidationError, 'The `Style/TrailingComma` cop no longer ' \
251
- 'exists. Please use ' \
252
- '`Style/TrailingCommaInLiteral` and/or ' \
253
- "`Style/TrailingCommaInArguments` instead.\n" \
254
- "(configuration found in #{loaded_path})"
266
+ OBSOLETE_COPS.each do |cop_name, message|
267
+ next unless key?(cop_name) || key?(cop_name.split('/').last)
268
+ message += "\n(obsolete configuration found in #{loaded_path}, please" \
269
+ ' update it)'
270
+ raise ValidationError, message
255
271
  end
256
272
  end
257
273
 
@@ -260,7 +276,7 @@ module RuboCop
260
276
  return unless target
261
277
 
262
278
  unless KNOWN_RUBIES.include?(target)
263
- fail ValidationError, "Unknown Ruby version #{target.inspect} found " \
279
+ raise ValidationError, "Unknown Ruby version #{target.inspect} found " \
264
280
  'in `TargetRubyVersion` parameter (in ' \
265
281
  "#{loaded_path}).\nKnown versions: " \
266
282
  "#{KNOWN_RUBIES.join(', ')}"
@@ -150,7 +150,7 @@ module RuboCop
150
150
  puts "configuration from #{absolute_path}" if debug?
151
151
 
152
152
  unless hash.is_a?(Hash)
153
- fail(TypeError, "Malformed configuration in #{absolute_path}")
153
+ raise(TypeError, "Malformed configuration in #{absolute_path}")
154
154
  end
155
155
 
156
156
  hash
@@ -179,8 +179,8 @@ module RuboCop
179
179
  def resolve_inheritance_from_gems(hash, gems)
180
180
  (gems || {}).each_pair do |gem_name, config_path|
181
181
  if gem_name == 'rubocop'
182
- fail ArgumentError,
183
- "can't inherit configuration from the rubocop gem"
182
+ raise ArgumentError,
183
+ "can't inherit configuration from the rubocop gem"
184
184
  end
185
185
 
186
186
  hash['inherit_from'] = Array(hash['inherit_from'])
@@ -214,8 +214,9 @@ module RuboCop
214
214
  end
215
215
 
216
216
  def old_auto_config_file_warning
217
- fail RuboCop::Error, 'rubocop-todo.yml is obsolete; it must be called' \
218
- " #{AUTO_GENERATED_FILE} instead"
217
+ raise RuboCop::Error,
218
+ 'rubocop-todo.yml is obsolete; it must be called' \
219
+ " #{AUTO_GENERATED_FILE} instead"
219
220
  end
220
221
  end
221
222
  end
@@ -5,42 +5,43 @@ module RuboCop
5
5
  module Cop
6
6
  # Commissioner class is responsible for processing the AST and delegating
7
7
  # work to the specified cops.
8
- class Commissioner < Parser::AST::Processor
8
+ class Commissioner
9
+ include RuboCop::Node::Traversal
10
+
9
11
  attr_reader :errors
10
12
 
11
13
  def self.callback_methods
12
- Parser::Meta::NODE_TYPES.map { |type| "on_#{type}" }
14
+ Parser::Meta::NODE_TYPES.map { |type| :"on_#{type}" }
13
15
  end
14
16
 
15
- # Methods that are not defined in Parser::AST::Processor
16
- # won't have a `super` to call. So we should not attempt
17
- # to invoke `super` when defining them.
18
- def self.call_super(callback)
19
- if Parser::AST::Processor.method_defined?(callback)
20
- 'super'
21
- else
22
- ''
23
- end
24
- end
25
-
26
- def initialize(cops, forces, options = {})
17
+ def initialize(cops, forces = [], options = {})
27
18
  @cops = cops
28
19
  @forces = forces
29
20
  @options = options
21
+ @callbacks = {}
22
+
30
23
  reset_errors
31
24
  end
32
25
 
26
+ # In the dynamically generated methods below, a call to `super` is used
27
+ # to continue iterating over the children of a node.
28
+ # However, if we know that a certain node type (like `int`) never has
29
+ # child nodes, there is no reason to pay the cost of calling `super`.
30
+ no_child_callbacks = Node::Traversal::NO_CHILD_NODES.map do |type|
31
+ :"on_#{type}"
32
+ end
33
+
33
34
  callback_methods.each do |callback|
35
+ next unless RuboCop::Node::Traversal.method_defined?(callback)
34
36
  class_eval <<-EOS, __FILE__, __LINE__
35
37
  def #{callback}(node)
36
- @cops.each do |cop|
37
- next unless cop.respond_to?(:#{callback})
38
+ @callbacks[:#{callback}].each do |cop|
38
39
  with_cop_error_handling(cop) do
39
40
  cop.send(:#{callback}, node)
40
41
  end
41
42
  end
42
43
 
43
- #{call_super(callback)}
44
+ #{!no_child_callbacks.include?(callback) && 'super'}
44
45
  end
45
46
  EOS
46
47
  end
@@ -48,10 +49,11 @@ module RuboCop
48
49
  def investigate(processed_source)
49
50
  reset_errors
50
51
  remove_irrelevant_cops(processed_source.buffer.name)
52
+ setup_callbacks
51
53
  prepare(processed_source)
52
54
  invoke_custom_processing(@cops, processed_source)
53
55
  invoke_custom_processing(@forces, processed_source)
54
- process(processed_source.ast) if processed_source.ast
56
+ walk(processed_source.ast) if processed_source.ast
55
57
  @cops.flat_map(&:offenses)
56
58
  end
57
59
 
@@ -65,6 +67,13 @@ module RuboCop
65
67
  @cops.reject! { |cop| cop.excluded_file?(filename) }
66
68
  end
67
69
 
70
+ def setup_callbacks
71
+ @callbacks.clear
72
+ self.class.callback_methods.each do |method|
73
+ @callbacks[method] = @cops.select { |cop| cop.respond_to?(method) }
74
+ end
75
+ end
76
+
68
77
  # TODO: Bad design.
69
78
  def prepare(processed_source)
70
79
  @cops.each { |cop| cop.processed_source = processed_source }
@@ -32,8 +32,9 @@ module RuboCop
32
32
  case found_ns.size
33
33
  when 0 then name # No namespace found. Deal with it later in caller.
34
34
  when 1 then cop_name_with_namespace(name, origin, basename, found_ns[0])
35
- else fail AmbiguousCopName, "Ambiguous cop name `#{basename}` used in" \
36
- "#{origin} needs namespace qualifier."
35
+ else raise AmbiguousCopName,
36
+ "Ambiguous cop name `#{basename}` used in" \
37
+ "#{origin} needs namespace qualifier."
37
38
  end
38
39
  end
39
40
 
@@ -95,11 +96,11 @@ module RuboCop
95
96
  end
96
97
 
97
98
  def self.cop_name
98
- @cop_name ||= name.to_s.split('::').last(2).join('/')
99
+ @cop_name ||= name.split('::').last(2).join('/')
99
100
  end
100
101
 
101
102
  def self.cop_type
102
- name.to_s.split('::')[-2].downcase.to_sym
103
+ @cop_type ||= name.split('::')[-2].downcase.to_sym
103
104
  end
104
105
 
105
106
  def self.lint?
@@ -128,7 +129,7 @@ module RuboCop
128
129
  end
129
130
 
130
131
  def cop_config
131
- @config.for_cop(self)
132
+ @cop_config ||= @config.for_cop(self)
132
133
  end
133
134
 
134
135
  def debug?
@@ -201,7 +202,7 @@ module RuboCop
201
202
  end
202
203
 
203
204
  def cop_name
204
- self.class.cop_name
205
+ @cop_name ||= self.class.cop_name
205
206
  end
206
207
 
207
208
  alias name cop_name