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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -2
- data/README.md +10 -1
- data/assets/output.html.erb +55 -1
- data/config/default.yml +9 -3
- data/config/disabled.yml +21 -0
- data/config/enabled.yml +11 -10
- data/lib/rubocop.rb +9 -2
- data/lib/rubocop/ast_node.rb +67 -19
- data/lib/rubocop/ast_node/builder.rb +1 -0
- data/lib/rubocop/ast_node/sexp.rb +1 -0
- data/lib/rubocop/ast_node/traversal.rb +171 -0
- data/lib/rubocop/cached_data.rb +4 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +36 -20
- data/lib/rubocop/config_loader.rb +6 -5
- data/lib/rubocop/cop/commissioner.rb +27 -18
- data/lib/rubocop/cop/cop.rb +7 -6
- data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
- data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
- data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
- data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
- data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
- data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
- data/lib/rubocop/cop/performance/casecmp.rb +56 -17
- data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
- data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
- data/lib/rubocop/cop/performance/times_map.rb +3 -4
- data/lib/rubocop/cop/severity.rb +1 -1
- data/lib/rubocop/cop/style/align_hash.rb +1 -1
- data/lib/rubocop/cop/style/align_parameters.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
- data/lib/rubocop/cop/style/copyright.rb +2 -2
- data/lib/rubocop/cop/style/documentation.rb +19 -29
- data/lib/rubocop/cop/style/each_with_object.rb +1 -1
- data/lib/rubocop/cop/style/else_alignment.rb +2 -2
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
- data/lib/rubocop/cop/style/guard_clause.rb +2 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
- data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +3 -7
- data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
- data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
- data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
- data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
- data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
- data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
- data/lib/rubocop/cop/style/next.rb +32 -11
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
- data/lib/rubocop/cop/style/send.rb +1 -1
- data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
- data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
- data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
- data/lib/rubocop/cop/team.rb +30 -5
- data/lib/rubocop/cop/util.rb +16 -1
- data/lib/rubocop/cop/variable_force.rb +3 -12
- data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
- data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
- data/lib/rubocop/cop/variable_force/reference.rb +3 -3
- data/lib/rubocop/cop/variable_force/scope.rb +8 -7
- data/lib/rubocop/cop/variable_force/variable.rb +3 -3
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/node_pattern.rb +1 -1
- data/lib/rubocop/options.rb +10 -10
- data/lib/rubocop/path_util.rb +5 -0
- data/lib/rubocop/processed_source.rb +8 -2
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/token.rb +2 -2
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.30.1.md +1 -0
- data/relnotes/v0.33.0.md +1 -1
- data/relnotes/v0.36.0.md +2 -1
- data/relnotes/v0.37.0.md +200 -0
- data/rubocop.gemspec +2 -1
- metadata +28 -7
- data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
- data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -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
|
data/lib/rubocop/cached_data.rb
CHANGED
@@ -31,7 +31,10 @@ module RuboCop
|
|
31
31
|
end
|
32
32
|
|
33
33
|
{
|
34
|
-
|
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
|
data/lib/rubocop/cli.rb
CHANGED
@@ -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
|
-
|
81
|
+
raise Finished
|
82
82
|
end
|
83
83
|
|
84
84
|
def apply_default_formatter
|
data/lib/rubocop/config.rb
CHANGED
@@ -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) && !
|
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) ||
|
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 =
|
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
|
-
|
186
|
-
|
187
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
183
|
-
|
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
|
-
|
218
|
-
|
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
|
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
|
-
|
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
|
-
@
|
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
|
-
#{
|
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
|
-
|
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 }
|
data/lib/rubocop/cop/cop.rb
CHANGED
@@ -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
|
36
|
-
|
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.
|
99
|
+
@cop_name ||= name.split('::').last(2).join('/')
|
99
100
|
end
|
100
101
|
|
101
102
|
def self.cop_type
|
102
|
-
name.
|
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
|