rubocop 0.12.0 → 0.13.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.
- data/CHANGELOG.md +40 -0
- data/README.md +49 -8
- data/config/default.yml +40 -0
- data/config/enabled.yml +37 -9
- data/lib/rubocop.rb +24 -10
- data/lib/rubocop/cli.rb +41 -106
- data/lib/rubocop/config.rb +3 -2
- data/lib/rubocop/cop/commissioner.rb +15 -5
- data/lib/rubocop/cop/cop.rb +47 -32
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
- data/lib/rubocop/cop/lint/block_alignment.rb +30 -9
- data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
- data/lib/rubocop/cop/lint/end_alignment.rb +4 -4
- data/lib/rubocop/cop/lint/end_in_method.rb +1 -1
- data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
- data/lib/rubocop/cop/lint/eval.rb +1 -3
- data/lib/rubocop/cop/lint/handle_exceptions.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_condition.rb +6 -4
- data/lib/rubocop/cop/lint/loop.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -8
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +57 -60
- data/lib/rubocop/cop/lint/useless_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +85 -0
- data/lib/rubocop/cop/lint/void.rb +6 -8
- data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
- data/lib/rubocop/cop/rails/read_attribute.rb +1 -1
- data/lib/rubocop/cop/rails/validation.rb +1 -1
- data/lib/rubocop/cop/style/access_control.rb +4 -6
- data/lib/rubocop/cop/style/alias.rb +1 -3
- data/lib/rubocop/cop/style/align_array.rb +47 -0
- data/lib/rubocop/cop/style/align_hash.rb +145 -0
- data/lib/rubocop/cop/style/align_parameters.rb +9 -3
- data/lib/rubocop/cop/style/and_or.rb +3 -4
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -3
- data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -1
- data/lib/rubocop/cop/style/attr.rb +1 -4
- data/lib/rubocop/cop/style/begin_block.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_nesting.rb +2 -2
- data/lib/rubocop/cop/style/blocks.rb +14 -2
- data/lib/rubocop/cop/style/case_equality.rb +1 -3
- data/lib/rubocop/cop/style/case_indentation.rb +1 -1
- data/lib/rubocop/cop/style/character_literal.rb +1 -2
- data/lib/rubocop/cop/style/class_and_module_camel_case.rb +1 -1
- data/lib/rubocop/cop/style/class_methods.rb +1 -3
- data/lib/rubocop/cop/style/{avoid_class_vars.rb → class_vars.rb} +6 -2
- data/lib/rubocop/cop/style/collection_methods.rb +7 -9
- data/lib/rubocop/cop/style/colon_method_call.rb +1 -2
- data/lib/rubocop/cop/style/comment_annotation.rb +6 -6
- data/lib/rubocop/cop/style/constant_name.rb +1 -3
- data/lib/rubocop/cop/style/def_parentheses.rb +4 -12
- data/lib/rubocop/cop/style/documentation.rb +2 -2
- data/lib/rubocop/cop/style/dot_position.rb +2 -4
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +21 -6
- data/lib/rubocop/cop/style/empty_lines.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +3 -12
- data/lib/rubocop/cop/style/encoding.rb +6 -6
- data/lib/rubocop/cop/style/end_block.rb +1 -1
- data/lib/rubocop/cop/style/end_of_line.rb +5 -5
- data/lib/rubocop/cop/style/even_odd.rb +2 -2
- data/lib/rubocop/cop/style/favor_join.rb +1 -3
- data/lib/rubocop/cop/style/favor_modifier.rb +7 -3
- data/lib/rubocop/cop/style/favor_sprintf.rb +1 -1
- data/lib/rubocop/cop/style/favor_unless_over_negated_if.rb +1 -1
- data/lib/rubocop/cop/style/final_newline.rb +23 -0
- data/lib/rubocop/cop/style/{avoid_for.rb → for.rb} +2 -2
- data/lib/rubocop/cop/style/{avoid_global_vars.rb → global_vars.rb} +19 -6
- data/lib/rubocop/cop/style/hash_methods.rb +3 -5
- data/lib/rubocop/cop/style/hash_syntax.rb +4 -4
- data/lib/rubocop/cop/style/if_then_else.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +4 -4
- data/lib/rubocop/cop/style/lambda.rb +2 -2
- data/lib/rubocop/cop/style/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/style/line_length.rb +7 -8
- data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +1 -1
- data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -4
- data/lib/rubocop/cop/style/method_length.rb +4 -4
- data/lib/rubocop/cop/style/module_function.rb +1 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +44 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +1 -3
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +26 -6
- data/lib/rubocop/cop/style/op_method.rb +2 -2
- data/lib/rubocop/cop/style/parameter_lists.rb +4 -4
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
- data/lib/rubocop/cop/style/perl_backrefs.rb +26 -0
- data/lib/rubocop/cop/style/proc.rb +1 -3
- data/lib/rubocop/cop/style/reduce_arguments.rb +7 -5
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_return.rb +9 -2
- data/lib/rubocop/cop/style/redundant_self.rb +9 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +7 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +10 -10
- data/lib/rubocop/cop/style/signal_exception.rb +2 -4
- data/lib/rubocop/cop/style/single_line_methods.rb +2 -4
- data/lib/rubocop/cop/style/space_after_comma_etc.rb +1 -1
- data/lib/rubocop/cop/style/space_after_control_keyword.rb +1 -1
- data/lib/rubocop/cop/style/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +34 -0
- data/lib/rubocop/cop/style/{avoid_perlisms.rb → special_global_vars.rb} +17 -8
- data/lib/rubocop/cop/style/string_literals.rb +1 -2
- data/lib/rubocop/cop/style/surrounding_space.rb +9 -8
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_name.rb +9 -2
- data/lib/rubocop/cop/style/tab.rb +5 -5
- data/lib/rubocop/cop/style/ternary_operator.rb +2 -6
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +32 -0
- data/lib/rubocop/cop/style/trailing_whitespace.rb +5 -6
- data/lib/rubocop/cop/style/trivial_accessors.rb +5 -5
- data/lib/rubocop/cop/style/unless_else.rb +1 -1
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -3
- data/lib/rubocop/cop/style/when_then.rb +1 -4
- data/lib/rubocop/cop/style/while_until_do.rb +7 -5
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/team.rb +100 -0
- data/lib/rubocop/cop/variable_inspector.rb +323 -235
- data/lib/rubocop/cop/variable_inspector/assignment.rb +103 -0
- data/lib/rubocop/cop/variable_inspector/locatable.rb +162 -0
- data/lib/rubocop/cop/variable_inspector/reference.rb +31 -0
- data/lib/rubocop/cop/variable_inspector/scope.rb +70 -0
- data/lib/rubocop/cop/variable_inspector/variable.rb +87 -0
- data/lib/rubocop/cop/variable_inspector/variable_table.rb +129 -0
- data/lib/rubocop/formatter/json_formatter.rb +8 -8
- data/lib/rubocop/formatter/progress_formatter.rb +4 -4
- data/lib/rubocop/processed_source.rb +22 -1
- data/lib/rubocop/version.rb +1 -1
- data/rubocop.gemspec +1 -1
- data/spec/rubocop/cli_spec.rb +32 -30
- data/spec/rubocop/config_spec.rb +4 -6
- data/spec/rubocop/cop/commissioner_spec.rb +4 -5
- data/spec/rubocop/cop/cop_spec.rb +8 -26
- data/spec/rubocop/cop/lint/assignment_in_condition_spec.rb +5 -9
- data/spec/rubocop/cop/lint/block_alignment_spec.rb +105 -57
- data/spec/rubocop/cop/lint/empty_ensure_spec.rb +1 -1
- data/spec/rubocop/cop/lint/end_alignment_spec.rb +1 -1
- data/spec/rubocop/cop/lint/end_in_method_spec.rb +1 -1
- data/spec/rubocop/cop/lint/ensure_return_spec.rb +1 -1
- data/spec/rubocop/cop/lint/eval_spec.rb +3 -3
- data/spec/rubocop/cop/lint/handle_exceptions_spec.rb +2 -2
- data/spec/rubocop/cop/lint/literal_in_condition_spec.rb +1 -1
- data/spec/rubocop/cop/lint/loop_spec.rb +1 -1
- data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +1 -1
- data/spec/rubocop/cop/lint/rescue_exception_spec.rb +5 -5
- data/spec/rubocop/cop/lint/unreachable_code_spec.rb +1 -1
- data/spec/rubocop/cop/lint/useless_assignment_spec.rb +1545 -108
- data/spec/rubocop/cop/lint/useless_comparison_spec.rb +1 -1
- data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +101 -0
- data/spec/rubocop/cop/lint/void_spec.rb +1 -1
- data/spec/rubocop/cop/offence_spec.rb +4 -4
- data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +1 -1
- data/spec/rubocop/cop/rails/read_attribute_spec.rb +1 -1
- data/spec/rubocop/cop/rails/validation_spec.rb +1 -1
- data/spec/rubocop/cop/style/access_control_spec.rb +20 -20
- data/spec/rubocop/cop/style/alias_spec.rb +3 -3
- data/spec/rubocop/cop/style/align_array_spec.rb +62 -0
- data/spec/rubocop/cop/style/align_hash_spec.rb +267 -0
- data/spec/rubocop/cop/style/align_parameters_spec.rb +2 -2
- data/spec/rubocop/cop/style/and_or_spec.rb +1 -1
- data/spec/rubocop/cop/style/ascii_comments_spec.rb +2 -2
- data/spec/rubocop/cop/style/ascii_identifiers_spec.rb +2 -2
- data/spec/rubocop/cop/style/attr_spec.rb +1 -1
- data/spec/rubocop/cop/style/begin_block_spec.rb +1 -1
- data/spec/rubocop/cop/style/block_comments_spec.rb +1 -1
- data/spec/rubocop/cop/style/block_nesting_spec.rb +3 -3
- data/spec/rubocop/cop/style/blocks_spec.rb +25 -1
- data/spec/rubocop/cop/style/case_equality_spec.rb +1 -1
- data/spec/rubocop/cop/style/case_indentation_spec.rb +5 -5
- data/spec/rubocop/cop/style/character_literal_spec.rb +1 -1
- data/spec/rubocop/cop/style/class_and_module_camel_case_spec.rb +1 -1
- data/spec/rubocop/cop/style/class_methods_spec.rb +1 -1
- data/spec/rubocop/cop/style/class_vars_spec.rb +25 -0
- data/spec/rubocop/cop/style/collection_methods_spec.rb +5 -6
- data/spec/rubocop/cop/style/colon_method_call_spec.rb +0 -3
- data/spec/rubocop/cop/style/comment_annotation_spec.rb +20 -18
- data/spec/rubocop/cop/style/constant_name_spec.rb +1 -1
- data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +1 -1
- data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +1 -1
- data/spec/rubocop/cop/style/documentation_spec.rb +1 -1
- data/spec/rubocop/cop/style/dot_position_spec.rb +5 -5
- data/spec/rubocop/cop/style/empty_line_between_defs_spec.rb +35 -4
- data/spec/rubocop/cop/style/empty_lines_spec.rb +1 -1
- data/spec/rubocop/cop/style/empty_literal_spec.rb +7 -7
- data/spec/rubocop/cop/style/encoding_spec.rb +11 -5
- data/spec/rubocop/cop/style/end_block_spec.rb +1 -1
- data/spec/rubocop/cop/style/end_of_line_spec.rb +4 -3
- data/spec/rubocop/cop/style/even_odd_spec.rb +1 -1
- data/spec/rubocop/cop/style/favor_join_spec.rb +2 -2
- data/spec/rubocop/cop/style/favor_modifier_spec.rb +13 -10
- data/spec/rubocop/cop/style/favor_sprintf_spec.rb +4 -4
- data/spec/rubocop/cop/style/favor_unless_over_negated_if_spec.rb +1 -1
- data/spec/rubocop/cop/style/favor_until_over_negated_while_spec.rb +4 -4
- data/spec/rubocop/cop/style/final_newline_spec.rb +25 -0
- data/spec/rubocop/cop/style/{avoid_for_spec.rb → for_spec.rb} +8 -12
- data/spec/rubocop/cop/style/{avoid_global_vars_spec.rb → global_vars_spec.rb} +13 -3
- data/spec/rubocop/cop/style/hash_methods_spec.rb +1 -1
- data/spec/rubocop/cop/style/hash_syntax_spec.rb +20 -9
- data/spec/rubocop/cop/style/if_with_semicolon_spec.rb +3 -3
- data/spec/rubocop/cop/style/indentation_width_spec.rb +19 -19
- data/spec/rubocop/cop/style/lambda_spec.rb +6 -6
- data/spec/rubocop/cop/style/leading_comment_space_spec.rb +1 -1
- data/spec/rubocop/cop/style/line_length_spec.rb +3 -3
- data/spec/rubocop/cop/style/method_and_variable_snake_case_spec.rb +8 -9
- data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +1 -1
- data/spec/rubocop/cop/style/method_length_spec.rb +18 -17
- data/spec/rubocop/cop/style/module_function_spec.rb +1 -1
- data/spec/rubocop/cop/style/multiline_block_chain_spec.rb +84 -0
- data/spec/rubocop/cop/style/multiline_if_then_spec.rb +2 -2
- data/spec/rubocop/cop/style/nil_comparison_spec.rb +1 -1
- data/spec/rubocop/cop/style/not_spec.rb +1 -1
- data/spec/rubocop/cop/style/numeric_literals_spec.rb +15 -25
- data/spec/rubocop/cop/style/one_line_conditional_spec.rb +2 -2
- data/spec/rubocop/cop/style/op_method_spec.rb +3 -3
- data/spec/rubocop/cop/style/parameter_lists_spec.rb +5 -5
- data/spec/rubocop/cop/style/parentheses_around_condition_spec.rb +4 -8
- data/spec/rubocop/cop/style/perl_backrefs_spec.rb +23 -0
- data/spec/rubocop/cop/style/proc_spec.rb +1 -1
- data/spec/rubocop/cop/style/reduce_arguments_spec.rb +18 -11
- data/spec/rubocop/cop/style/redundant_begin_spec.rb +1 -1
- data/spec/rubocop/cop/style/redundant_return_spec.rb +16 -1
- data/spec/rubocop/cop/style/redundant_self_spec.rb +6 -1
- data/spec/rubocop/cop/style/regexp_literal_spec.rb +19 -23
- data/spec/rubocop/cop/style/rescue_modifier_spec.rb +3 -3
- data/spec/rubocop/cop/style/semicolon_spec.rb +3 -3
- data/spec/rubocop/cop/style/signal_exception_spec.rb +1 -1
- data/spec/rubocop/cop/style/single_line_methods_spec.rb +22 -18
- data/spec/rubocop/cop/style/space_after_colon_spec.rb +4 -4
- data/spec/rubocop/cop/style/space_after_comma_spec.rb +4 -4
- data/spec/rubocop/cop/style/space_after_control_keyword_spec.rb +1 -1
- data/spec/rubocop/cop/style/space_after_method_name_spec.rb +1 -1
- data/spec/rubocop/cop/style/space_after_semicolon_spec.rb +3 -3
- data/spec/rubocop/cop/style/space_around_braces_spec.rb +13 -12
- data/spec/rubocop/cop/style/space_around_equals_in_default_parameter_spec.rb +3 -3
- data/spec/rubocop/cop/style/space_around_operators_spec.rb +25 -25
- data/spec/rubocop/cop/style/space_before_modifier_keyword_spec.rb +53 -0
- data/spec/rubocop/cop/style/space_inside_brackets_spec.rb +9 -9
- data/spec/rubocop/cop/style/space_inside_hash_literal_braces_spec.rb +47 -61
- data/spec/rubocop/cop/style/space_inside_parens_spec.rb +4 -4
- data/spec/rubocop/cop/style/special_global_vars_spec.rb +52 -0
- data/spec/rubocop/cop/style/string_literals_spec.rb +5 -5
- data/spec/rubocop/cop/style/symbol_array_spec.rb +1 -1
- data/spec/rubocop/cop/style/symbol_name_spec.rb +27 -18
- data/spec/rubocop/cop/style/tab_spec.rb +1 -1
- data/spec/rubocop/cop/style/ternary_operator_spec.rb +2 -2
- data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +24 -0
- data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +7 -7
- data/spec/rubocop/cop/style/trivial_accessors_spec.rb +6 -14
- data/spec/rubocop/cop/style/unless_else_spec.rb +3 -3
- data/spec/rubocop/cop/style/variable_interpolation_spec.rb +5 -5
- data/spec/rubocop/cop/style/when_then_spec.rb +15 -15
- data/spec/rubocop/cop/style/while_until_do_spec.rb +3 -3
- data/spec/rubocop/cop/style/word_array_spec.rb +1 -1
- data/spec/rubocop/cop/team_spec.rb +158 -0
- data/spec/rubocop/cop/variable_inspector/assignment_spec.rb +217 -0
- data/spec/rubocop/cop/variable_inspector/locatable_spec.rb +740 -0
- data/spec/rubocop/cop/variable_inspector/scope_spec.rb +191 -0
- data/spec/rubocop/cop/variable_inspector/variable_spec.rb +79 -0
- data/spec/rubocop/cop/variable_inspector/variable_table_spec.rb +275 -0
- data/spec/rubocop/cop/variable_inspector_spec.rb +13 -533
- data/spec/rubocop/formatter/clang_style_formatter_spec.rb +4 -4
- data/spec/rubocop/formatter/disabled_config_formatter_spec.rb +1 -1
- data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +3 -3
- data/spec/rubocop/formatter/file_list_formatter_spec.rb +3 -3
- data/spec/rubocop/formatter/progress_formatter_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -1
- data/spec/support/ast_helper.rb +15 -0
- data/spec/support/shared_context.rb +18 -0
- data/spec/support/shared_examples.rb +1 -1
- metadata +95 -32
- checksums.yaml +0 -7
- data/lib/rubocop/cop/lint/unused_local_variable.rb +0 -32
- data/lib/rubocop/cop/style/avoid_perl_backrefs.rb +0 -19
- data/spec/rubocop/cop/lint/unused_local_variable_spec.rb +0 -588
- data/spec/rubocop/cop/style/avoid_class_vars_spec.rb +0 -27
- data/spec/rubocop/cop/style/avoid_perl_backrefs_spec.rb +0 -20
- data/spec/rubocop/cop/style/avoid_perlisms_spec.rb +0 -47
@@ -5,13 +5,19 @@ module Rubocop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks whether symbol names are snake_case.
|
7
7
|
# There's also an option to accept CamelCase symbol names as well.
|
8
|
+
# There's also an option to accept symbol names with dots as well.
|
8
9
|
class SymbolName < Cop
|
9
10
|
MSG = 'Use snake_case for symbols.'
|
10
11
|
SNAKE_CASE = /^[\da-z_]+[!?=]?$/
|
12
|
+
SNAKE_CASE_WITH_DOTS = /^[\da-z_\.]+[!?=]?$/
|
11
13
|
CAMEL_CASE = /^[A-Z][A-Za-z\d]*$/
|
12
14
|
|
13
15
|
def allow_camel_case?
|
14
|
-
|
16
|
+
cop_config['AllowCamelCase']
|
17
|
+
end
|
18
|
+
|
19
|
+
def allow_dots?
|
20
|
+
cop_config['AllowDots']
|
15
21
|
end
|
16
22
|
|
17
23
|
def on_send(node)
|
@@ -30,7 +36,8 @@ module Rubocop
|
|
30
36
|
return unless sym_name =~ /^[a-zA-Z]/
|
31
37
|
return if sym_name =~ SNAKE_CASE
|
32
38
|
return if allow_camel_case? && sym_name =~ CAMEL_CASE
|
33
|
-
|
39
|
+
return if allow_dots? && sym_name =~ SNAKE_CASE_WITH_DOTS
|
40
|
+
convention(node, :expression)
|
34
41
|
end
|
35
42
|
end
|
36
43
|
end
|
@@ -12,11 +12,11 @@ module Rubocop
|
|
12
12
|
match = line.match(/^( *)\t/)
|
13
13
|
if match
|
14
14
|
spaces = match.captures[0]
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
convention(nil,
|
16
|
+
source_range(processed_source.buffer,
|
17
|
+
processed_source[0...index],
|
18
|
+
spaces.length, 8),
|
19
|
+
MSG)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -14,9 +14,7 @@ module Rubocop
|
|
14
14
|
# discard non-ternary ops
|
15
15
|
return unless loc.respond_to?(:question)
|
16
16
|
|
17
|
-
if loc.line != loc.colon.line
|
18
|
-
add_offence(:convention, loc.expression, MSG)
|
19
|
-
end
|
17
|
+
convention(node, :expression) if loc.line != loc.colon.line
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
@@ -33,9 +31,7 @@ module Rubocop
|
|
33
31
|
|
34
32
|
node.children.each do |child|
|
35
33
|
on_node(:if, child) do |c|
|
36
|
-
if c.loc.respond_to?(:question)
|
37
|
-
add_offence(:convention, c.loc.expression, MSG)
|
38
|
-
end
|
34
|
+
convention(c, :expression) if c.loc.respond_to?(:question)
|
39
35
|
end
|
40
36
|
end
|
41
37
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for trailing blank lines in the source code.
|
7
|
+
class TrailingBlankLines < Cop
|
8
|
+
MSG = '%d trailing blank lines detected.'
|
9
|
+
|
10
|
+
def investigate(processed_source)
|
11
|
+
blank_lines = 0
|
12
|
+
|
13
|
+
processed_source.lines.reverse_each do |line|
|
14
|
+
if line.blank?
|
15
|
+
blank_lines += 1
|
16
|
+
else
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if blank_lines > 0
|
22
|
+
convention(nil,
|
23
|
+
source_range(processed_source.buffer,
|
24
|
+
processed_source[0...-blank_lines],
|
25
|
+
0, 1),
|
26
|
+
format(MSG, blank_lines))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -10,12 +10,11 @@ module Rubocop
|
|
10
10
|
def investigate(processed_source)
|
11
11
|
processed_source.lines.each_with_index do |line, index|
|
12
12
|
if line =~ /.*[ \t]+$/
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
MSG)
|
13
|
+
convention(nil,
|
14
|
+
source_range(processed_source.buffer,
|
15
|
+
processed_source[0...index],
|
16
|
+
line.rstrip.length,
|
17
|
+
line.length - line.rstrip.length))
|
19
18
|
end
|
20
19
|
end
|
21
20
|
end
|
@@ -29,22 +29,22 @@ module Rubocop
|
|
29
29
|
'writer'
|
30
30
|
end
|
31
31
|
if kind
|
32
|
-
|
33
|
-
|
32
|
+
convention(node, :keyword,
|
33
|
+
sprintf(MSG, kind, kind))
|
34
34
|
end
|
35
35
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def exact_name_match?
|
39
|
-
|
39
|
+
cop_config['ExactNameMatch']
|
40
40
|
end
|
41
41
|
|
42
42
|
def allow_predicates?
|
43
|
-
|
43
|
+
cop_config['AllowPredicates']
|
44
44
|
end
|
45
45
|
|
46
46
|
def whitelist
|
47
|
-
whitelist =
|
47
|
+
whitelist = cop_config['Whitelist']
|
48
48
|
Array(whitelist).map(&:to_sym) + [:initialize]
|
49
49
|
end
|
50
50
|
|
@@ -12,9 +12,7 @@ module Rubocop
|
|
12
12
|
var = (v.type == :nth_ref ? '$' : '') + v.to_a[0].to_s
|
13
13
|
|
14
14
|
if node.loc.expression.source.include?("##{var}")
|
15
|
-
|
16
|
-
v.loc.expression,
|
17
|
-
sprintf(MSG, var, var))
|
15
|
+
convention(v, :expression, sprintf(MSG, var, var))
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -8,10 +8,7 @@ module Rubocop
|
|
8
8
|
MSG = 'Never use "when x;". Use "when x then" instead.'
|
9
9
|
|
10
10
|
def on_when(node)
|
11
|
-
if node.loc.begin && node.loc.begin.is?(';')
|
12
|
-
add_offence(:convention, node.loc.begin, MSG)
|
13
|
-
do_autocorrect(node)
|
14
|
-
end
|
11
|
+
convention(node, :begin) if node.loc.begin && node.loc.begin.is?(';')
|
15
12
|
end
|
16
13
|
|
17
14
|
def autocorrect_action(node)
|
@@ -18,10 +18,8 @@ module Rubocop
|
|
18
18
|
|
19
19
|
if length > 1
|
20
20
|
if node.loc.begin && node.loc.begin.is?('do')
|
21
|
-
|
22
|
-
|
23
|
-
error_message(node.type))
|
24
|
-
do_autocorrect(node)
|
21
|
+
convention(node, :begin,
|
22
|
+
error_message(node.type))
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -34,7 +32,11 @@ module Rubocop
|
|
34
32
|
|
35
33
|
def autocorrect_action(node)
|
36
34
|
@corrections << lambda do |corrector|
|
37
|
-
|
35
|
+
condition_node, = *node
|
36
|
+
end_of_condition_range = condition_node.loc.expression.end
|
37
|
+
do_range = node.loc.begin
|
38
|
+
whitespaces_and_do_range = end_of_condition_range.join(do_range)
|
39
|
+
corrector.remove(whitespaces_and_do_range)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# FIXME
|
6
|
+
class Team
|
7
|
+
attr_reader :errors
|
8
|
+
|
9
|
+
def initialize(cop_classes, config, options = nil)
|
10
|
+
@cop_classes = cop_classes
|
11
|
+
@config = config
|
12
|
+
@options = options || { autocorrect: false, debug: false }
|
13
|
+
@errors = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def autocorrect?
|
17
|
+
@options[:autocorrect]
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug?
|
21
|
+
@options[:debug]
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect_file(file)
|
25
|
+
begin
|
26
|
+
processed_source = SourceParser.parse_file(file)
|
27
|
+
rescue Encoding::UndefinedConversionError, ArgumentError => e
|
28
|
+
handle_error(e,
|
29
|
+
"An error occurred while parsing #{file}.".color(:red))
|
30
|
+
return []
|
31
|
+
end
|
32
|
+
|
33
|
+
offences = processed_source.diagnostics.map do |diagnostic|
|
34
|
+
Offence.from_diagnostic(diagnostic)
|
35
|
+
end
|
36
|
+
|
37
|
+
# If we got any syntax errors, return only the syntax offences.
|
38
|
+
# Parser may return nil for AST even though there are no syntax errors.
|
39
|
+
# e.g. sources which contain only comments
|
40
|
+
if offences.any? { |o| [:error, :fatal].include?(o.severity) }
|
41
|
+
return offences
|
42
|
+
end
|
43
|
+
|
44
|
+
commissioner = Commissioner.new(cops)
|
45
|
+
offences += commissioner.investigate(processed_source)
|
46
|
+
process_commissioner_errors(file, commissioner.errors)
|
47
|
+
autocorrect(processed_source.buffer, cops)
|
48
|
+
offences.sort
|
49
|
+
end
|
50
|
+
|
51
|
+
def cops
|
52
|
+
@cops ||= begin
|
53
|
+
@cop_classes.reduce([]) do |instances, cop_class|
|
54
|
+
next instances unless @config.cop_enabled?(cop_class)
|
55
|
+
instances << cop_class.new(@config, @options)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def autocorrect(buffer, cops)
|
63
|
+
return unless autocorrect?
|
64
|
+
|
65
|
+
corrections = cops.reduce([]) do |array, cop|
|
66
|
+
array.concat(cop.corrections)
|
67
|
+
array
|
68
|
+
end
|
69
|
+
|
70
|
+
corrector = Corrector.new(buffer, corrections)
|
71
|
+
new_source = corrector.rewrite
|
72
|
+
|
73
|
+
unless new_source == buffer.source
|
74
|
+
filename = buffer.name
|
75
|
+
File.open(filename, 'w') { |f| f.write(new_source) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def process_commissioner_errors(file, file_errors)
|
80
|
+
file_errors.each do |cop, errors|
|
81
|
+
errors.each do |e|
|
82
|
+
handle_error(e,
|
83
|
+
"An error occurred while #{cop.name}".color(:red) +
|
84
|
+
" cop was inspecting #{file}.".color(:red))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def handle_error(e, message)
|
90
|
+
@errors << message
|
91
|
+
warn message
|
92
|
+
if debug?
|
93
|
+
puts e.message, e.backtrace
|
94
|
+
else
|
95
|
+
warn 'To see the complete backtrace run rubocop -d.'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -6,296 +6,320 @@ module Rubocop
|
|
6
6
|
# This is intended to be used as mix-in, and the user class may override
|
7
7
|
# some of hook methods.
|
8
8
|
module VariableInspector
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
VARIABLE_ASSIGNMENT_TYPE = :lvasgn
|
10
|
+
REGEXP_NAMED_CAPTURE_TYPE = :match_with_lvasgn
|
11
|
+
VARIABLE_ASSIGNMENT_TYPES =
|
12
|
+
[VARIABLE_ASSIGNMENT_TYPE, REGEXP_NAMED_CAPTURE_TYPE].freeze
|
13
|
+
|
14
|
+
METHOD_ARGUMENT_DECLARATION_TYPES = [
|
15
|
+
:arg, :optarg, :restarg,
|
16
|
+
:kwarg, :kwoptarg, :kwrestarg
|
14
17
|
].freeze
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
class VariableEntry
|
24
|
-
attr_reader :node
|
25
|
-
attr_accessor :used
|
26
|
-
alias_method :used?, :used
|
27
|
-
|
28
|
-
def initialize(node, name = nil)
|
29
|
-
unless VARIABLE_DECLARATION_TYPES.include?(node.type)
|
30
|
-
fail ArgumentError,
|
31
|
-
"Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " +
|
32
|
-
"passed #{node.type}"
|
33
|
-
end
|
34
|
-
@node = node
|
35
|
-
@name = name.to_sym if name
|
36
|
-
@used = false
|
37
|
-
end
|
18
|
+
BLOCK_ARGUMENT_DECLARATION_TYPE = :blockarg
|
19
|
+
ARGUMENT_DECLARATION_TYPES = (
|
20
|
+
METHOD_ARGUMENT_DECLARATION_TYPES + [BLOCK_ARGUMENT_DECLARATION_TYPE]
|
21
|
+
).freeze
|
22
|
+
BLOCK_LOCAL_VARIABLE_DECLARATION_TYPE = :shadowarg
|
23
|
+
DECLARATION_TYPES = (
|
24
|
+
ARGUMENT_DECLARATION_TYPES + [BLOCK_LOCAL_VARIABLE_DECLARATION_TYPE]
|
25
|
+
).freeze
|
38
26
|
|
39
|
-
|
40
|
-
|
41
|
-
|
27
|
+
LOGICAL_OPERATOR_ASSIGNMENT_TYPES = [:or_asgn, :and_asgn].freeze
|
28
|
+
OPERATOR_ASSIGNMENT_TYPES =
|
29
|
+
(LOGICAL_OPERATOR_ASSIGNMENT_TYPES + [:op_asgn]).freeze
|
30
|
+
|
31
|
+
MULTIPLE_ASSIGNMENT_TYPE = :masgn
|
32
|
+
|
33
|
+
VARIABLE_REFERENCE_TYPE = :lvar
|
34
|
+
|
35
|
+
POST_CONDITION_LOOP_TYPES = [:while_post, :until_post].freeze
|
36
|
+
LOOP_TYPES = (POST_CONDITION_LOOP_TYPES + [:while, :until, :for]).freeze
|
37
|
+
|
38
|
+
RESCUE_TYPE = :rescue
|
39
|
+
|
40
|
+
ZERO_ARITY_SUPER_TYPE = :zsuper
|
41
|
+
|
42
|
+
TWISTED_SCOPE_TYPES = [:block, :class, :sclass, :defs].freeze
|
43
|
+
SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:module, :def]).freeze
|
44
|
+
|
45
|
+
def variable_table
|
46
|
+
@variable_table ||= VariableTable.new(self)
|
42
47
|
end
|
43
48
|
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# Accept begin node for top level scope.
|
52
|
-
unless SCOPE_TYPES.include?(node.type) || node.type == :begin
|
53
|
-
fail ArgumentError,
|
54
|
-
"Node type must be any of #{SCOPE_TYPES}, " +
|
55
|
-
"passed #{node.type}"
|
56
|
-
end
|
57
|
-
@node = node
|
58
|
-
@variable_entries = {}
|
49
|
+
# Starting point.
|
50
|
+
def inspect_variables(root_node)
|
51
|
+
return unless root_node
|
52
|
+
|
53
|
+
# Wrap with begin node if it's standalone node.
|
54
|
+
unless root_node.type == :begin
|
55
|
+
root_node = Parser::AST::Node.new(:begin, [root_node])
|
59
56
|
end
|
57
|
+
|
58
|
+
inspect_variables_in_scope(root_node)
|
60
59
|
end
|
61
60
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
def initialize(hook_receiver = nil)
|
69
|
-
@hook_receiver = hook_receiver
|
70
|
-
end
|
61
|
+
# This is called for each scope recursively.
|
62
|
+
def inspect_variables_in_scope(scope_node)
|
63
|
+
variable_table.push_scope(scope_node)
|
64
|
+
process_children(scope_node)
|
65
|
+
variable_table.pop_scope
|
66
|
+
end
|
71
67
|
|
72
|
-
|
73
|
-
|
68
|
+
def process_children(origin_node)
|
69
|
+
origin_node.children.each do |child|
|
70
|
+
next unless child.is_a?(Parser::AST::Node)
|
71
|
+
next if scanned_node?(child)
|
72
|
+
process_node(child)
|
74
73
|
end
|
74
|
+
end
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
def process_node(node)
|
77
|
+
catch(:skip_children) do
|
78
|
+
dispatch_node(node)
|
79
|
+
process_children(node)
|
78
80
|
end
|
81
|
+
end
|
79
82
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
scope_stack.push(scope)
|
84
|
-
invoke_hook(:after_entering_scope, scope)
|
85
|
-
scope
|
86
|
-
end
|
83
|
+
def skip_children!
|
84
|
+
throw :skip_children
|
85
|
+
end
|
87
86
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def dispatch_node(node)
|
88
|
+
case node.type
|
89
|
+
when *DECLARATION_TYPES
|
90
|
+
process_variable_declaration(node)
|
91
|
+
when VARIABLE_ASSIGNMENT_TYPE
|
92
|
+
process_variable_assignment(node)
|
93
|
+
when REGEXP_NAMED_CAPTURE_TYPE
|
94
|
+
process_regexp_named_captures(node)
|
95
|
+
when *OPERATOR_ASSIGNMENT_TYPES
|
96
|
+
process_variable_operator_assignment(node)
|
97
|
+
when MULTIPLE_ASSIGNMENT_TYPE
|
98
|
+
process_variable_multiple_assignment(node)
|
99
|
+
when VARIABLE_REFERENCE_TYPE
|
100
|
+
process_variable_referencing(node)
|
101
|
+
when *LOOP_TYPES
|
102
|
+
process_loop(node)
|
103
|
+
when RESCUE_TYPE
|
104
|
+
process_rescue(node)
|
105
|
+
when ZERO_ARITY_SUPER_TYPE
|
106
|
+
process_zero_arity_super(node)
|
107
|
+
when *SCOPE_TYPES
|
108
|
+
process_scope(node)
|
94
109
|
end
|
110
|
+
end
|
95
111
|
|
96
|
-
|
97
|
-
|
98
|
-
|
112
|
+
def process_variable_declaration(node)
|
113
|
+
# restarg would have no name:
|
114
|
+
#
|
115
|
+
# def initialize(*)
|
116
|
+
# end
|
117
|
+
return if node.type == :restarg && node.children.empty?
|
99
118
|
|
100
|
-
|
101
|
-
|
102
|
-
|
119
|
+
variable_name = node.children.first
|
120
|
+
variable_table.declare_variable(variable_name, node)
|
121
|
+
end
|
103
122
|
|
104
|
-
|
105
|
-
|
106
|
-
invoke_hook(:before_declaring_variable, entry)
|
107
|
-
current_scope.variable_entries[entry.name] = entry
|
108
|
-
invoke_hook(:after_declaring_variable, entry)
|
109
|
-
entry
|
110
|
-
end
|
123
|
+
def process_variable_assignment(node)
|
124
|
+
name = node.children.first
|
111
125
|
|
112
|
-
|
113
|
-
|
114
|
-
entry = scope.variable_entries[variable_name]
|
115
|
-
return entry if entry
|
116
|
-
# Only block scope allows referencing outer scope variables.
|
117
|
-
return nil unless scope.node.type == :block
|
118
|
-
end
|
119
|
-
nil
|
126
|
+
unless variable_table.variable_exist?(name)
|
127
|
+
variable_table.declare_variable(name, node)
|
120
128
|
end
|
129
|
+
|
130
|
+
# Need to scan rhs before assignment so that we can mark previous
|
131
|
+
# assignments as referenced if rhs has referencing to the variable
|
132
|
+
# itself like:
|
133
|
+
#
|
134
|
+
# foo = 1
|
135
|
+
# foo = foo + 1
|
136
|
+
process_children(node)
|
137
|
+
|
138
|
+
variable_table.assign_to_variable(name, node)
|
139
|
+
|
140
|
+
skip_children!
|
121
141
|
end
|
122
142
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
143
|
+
def process_regexp_named_captures(node)
|
144
|
+
regexp_node, rhs_node = *node
|
145
|
+
|
146
|
+
regexp_string = regexp_node.children[0].children[0]
|
147
|
+
regexp = Regexp.new(regexp_string)
|
148
|
+
variable_names = regexp.named_captures.keys
|
127
149
|
|
128
|
-
|
129
|
-
|
130
|
-
|
150
|
+
variable_names.each do |name|
|
151
|
+
unless variable_table.variable_exist?(name)
|
152
|
+
variable_table.declare_variable(name, node)
|
153
|
+
end
|
131
154
|
end
|
132
155
|
|
133
|
-
|
134
|
-
|
156
|
+
process_node(rhs_node)
|
157
|
+
process_node(regexp_node)
|
158
|
+
|
159
|
+
variable_names.each do |name|
|
160
|
+
variable_table.assign_to_variable(name, node)
|
135
161
|
end
|
136
162
|
|
137
|
-
|
138
|
-
|
163
|
+
skip_children!
|
164
|
+
end
|
139
165
|
|
140
|
-
|
141
|
-
|
142
|
-
|
166
|
+
def process_variable_operator_assignment(node)
|
167
|
+
if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
|
168
|
+
asgn_node, rhs_node = *node
|
169
|
+
else
|
170
|
+
asgn_node, _operator, rhs_node = *node
|
171
|
+
end
|
143
172
|
|
144
|
-
|
145
|
-
TWISTED_SCOPE_NODE_TYPES.include?(origin_node.type)
|
146
|
-
next
|
147
|
-
end
|
173
|
+
return unless asgn_node.type == :lvasgn
|
148
174
|
|
149
|
-
|
175
|
+
name = asgn_node.children.first
|
150
176
|
|
151
|
-
|
152
|
-
|
177
|
+
unless variable_table.variable_exist?(name)
|
178
|
+
variable_table.declare_variable(name, asgn_node)
|
153
179
|
end
|
154
180
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
# (send nil :puts
|
176
|
-
# (lvar :foo)))
|
177
|
-
scan_nodes_in_scope(node.children[1], true)
|
178
|
-
scan_nodes_in_scope(node.children[0], true)
|
179
|
-
when *TWISTED_SCOPE_NODE_TYPES
|
180
|
-
# The variable foo belongs to the top level scope,
|
181
|
-
# but in AST, it's under the block node.
|
182
|
-
#
|
183
|
-
# Ruby:
|
184
|
-
# some_method(foo = 1) do
|
185
|
-
# end
|
186
|
-
# puts foo
|
187
|
-
#
|
188
|
-
# AST:
|
189
|
-
# (begin
|
190
|
-
# (block
|
191
|
-
# (send nil :some_method
|
192
|
-
# (lvasgn :foo
|
193
|
-
# (int 1)))
|
194
|
-
# (args) nil)
|
195
|
-
# (send nil :puts
|
196
|
-
# (lvar :foo)))
|
197
|
-
#
|
198
|
-
# So the the method argument nodes need to be processed
|
199
|
-
# in current scope.
|
200
|
-
#
|
201
|
-
# Same thing.
|
202
|
-
#
|
203
|
-
# Ruby:
|
204
|
-
# instance = Object.new
|
205
|
-
# class << instance
|
206
|
-
# foo = 1
|
207
|
-
# end
|
208
|
-
#
|
209
|
-
# AST:
|
210
|
-
# (begin
|
211
|
-
# (lvasgn :instance
|
212
|
-
# (send
|
213
|
-
# (const nil :Object) :new))
|
214
|
-
# (sclass
|
215
|
-
# (lvar :instance)
|
216
|
-
# (begin
|
217
|
-
# (lvasgn :foo
|
218
|
-
# (int 1))
|
219
|
-
scan_nodes_in_scope(node.children.first, true)
|
220
|
-
when *SCOPE_TYPES
|
221
|
-
# Do not go into inner scope.
|
222
|
-
else
|
223
|
-
scan_nodes_in_scope(node)
|
224
|
-
end
|
225
|
-
end
|
181
|
+
# The following statements:
|
182
|
+
#
|
183
|
+
# foo = 1
|
184
|
+
# foo += foo = 2
|
185
|
+
# # => 3
|
186
|
+
#
|
187
|
+
# are equivalent to:
|
188
|
+
#
|
189
|
+
# foo = 1
|
190
|
+
# foo = foo + (foo = 2)
|
191
|
+
# # => 3
|
192
|
+
#
|
193
|
+
# So, at operator assignment node, we need to reference the variable
|
194
|
+
# before processing rhs nodes.
|
195
|
+
|
196
|
+
variable_table.reference_variable(name, node)
|
197
|
+
process_node(rhs_node)
|
198
|
+
variable_table.assign_to_variable(name, asgn_node)
|
199
|
+
|
200
|
+
skip_children!
|
226
201
|
end
|
227
202
|
|
228
|
-
def
|
229
|
-
|
203
|
+
def process_variable_multiple_assignment(node)
|
204
|
+
lhs_node, rhs_node = *node
|
205
|
+
process_node(rhs_node)
|
206
|
+
process_node(lhs_node)
|
207
|
+
skip_children!
|
230
208
|
end
|
231
209
|
|
232
|
-
|
233
|
-
|
234
|
-
|
210
|
+
def process_variable_referencing(node)
|
211
|
+
name = node.children.first
|
212
|
+
variable_table.reference_variable(name, node)
|
213
|
+
end
|
235
214
|
|
236
|
-
|
237
|
-
|
238
|
-
|
215
|
+
def process_loop(node)
|
216
|
+
if POST_CONDITION_LOOP_TYPES.include?(node.type)
|
217
|
+
# See the comment at the end of file for this behavior.
|
218
|
+
condition_node, body_node = *node
|
219
|
+
process_node(body_node)
|
220
|
+
process_node(condition_node)
|
221
|
+
else
|
222
|
+
process_children(node)
|
239
223
|
end
|
240
224
|
|
241
|
-
|
225
|
+
mark_assignments_as_referenced_in_loop(node)
|
226
|
+
|
227
|
+
skip_children!
|
242
228
|
end
|
243
229
|
|
244
|
-
|
245
|
-
|
246
|
-
|
230
|
+
def process_rescue(node)
|
231
|
+
resbody_nodes = node.children.select do |child|
|
232
|
+
next false unless child.is_a?(Parser::AST::Node)
|
233
|
+
child.type == :resbody
|
234
|
+
end
|
247
235
|
|
248
|
-
|
249
|
-
|
250
|
-
|
236
|
+
contain_retry = resbody_nodes.any? do |resbody_node|
|
237
|
+
scan(resbody_node) do |node_in_resbody|
|
238
|
+
break true if node_in_resbody.type == :retry
|
239
|
+
end
|
251
240
|
end
|
252
241
|
|
253
|
-
|
242
|
+
# Treat begin..rescue..end with retry as a loop.
|
243
|
+
process_loop(node) if contain_retry
|
254
244
|
end
|
255
245
|
|
256
|
-
def
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
246
|
+
def process_zero_arity_super(node)
|
247
|
+
variable_table.accessible_variables.each do |variable|
|
248
|
+
next unless variable.method_argument?
|
249
|
+
variable.reference!(node)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def process_scope(node)
|
254
|
+
if TWISTED_SCOPE_TYPES.include?(node.type)
|
255
|
+
# See the comment at the end of file for this behavior.
|
256
|
+
twisted_nodes = [node.children[0]]
|
257
|
+
twisted_nodes << node.children[1] if node.type == :class
|
258
|
+
twisted_nodes.compact!
|
259
|
+
|
260
|
+
twisted_nodes.each do |twisted_node|
|
261
|
+
process_node(twisted_node)
|
262
|
+
scanned_nodes << twisted_node
|
271
263
|
end
|
272
|
-
variable_entry.used = true
|
273
|
-
when *SCOPE_TYPES
|
274
|
-
inspect_variables_in_scope(node)
|
275
264
|
end
|
265
|
+
|
266
|
+
inspect_variables_in_scope(node)
|
267
|
+
skip_children!
|
276
268
|
end
|
277
269
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
270
|
+
# Mark all assignments which are referenced in the same loop
|
271
|
+
# as referenced by ignoring AST order since they would be referenced
|
272
|
+
# in next iteration.
|
273
|
+
def mark_assignments_as_referenced_in_loop(node)
|
274
|
+
referenced_variable_names_in_loop = []
|
275
|
+
assignment_nodes_in_loop = []
|
276
|
+
|
277
|
+
# #scan does not consider scope,
|
278
|
+
# but we don't need to care about it here.
|
279
|
+
scan(node) do |scanning_node|
|
280
|
+
case scanning_node.type
|
281
|
+
when :lvar
|
282
|
+
referenced_variable_names_in_loop << scanning_node.children.first
|
283
|
+
when :lvasgn
|
284
|
+
assignment_nodes_in_loop << scanning_node
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
referenced_variable_names_in_loop.each do |name|
|
289
|
+
variable = variable_table.find_variable(name)
|
290
|
+
# Non related references which are catched in the above scan
|
291
|
+
# would be skipped here.
|
292
|
+
next unless variable
|
293
|
+
variable.assignments.each do |assignment|
|
294
|
+
next if assignment_nodes_in_loop.none? do |assignment_node|
|
295
|
+
assignment_node.equal?(assignment.node)
|
296
|
+
end
|
297
|
+
assignment.reference!
|
298
|
+
end
|
284
299
|
end
|
285
300
|
end
|
286
301
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
302
|
+
# Simple recursive scan
|
303
|
+
def scan(node, &block)
|
304
|
+
node.children.each do |child|
|
305
|
+
next unless child.is_a?(Parser::AST::Node)
|
306
|
+
yield child
|
307
|
+
scan(child, &block)
|
308
|
+
end
|
309
|
+
nil
|
310
|
+
end
|
293
311
|
|
294
|
-
|
295
|
-
|
312
|
+
# Use Node#equal? for accurate check.
|
313
|
+
def scanned_node?(node)
|
314
|
+
scanned_nodes.any? do |scanned_node|
|
315
|
+
scanned_node.equal?(node)
|
296
316
|
end
|
297
317
|
end
|
298
318
|
|
319
|
+
def scanned_nodes
|
320
|
+
@scanned_nodes ||= []
|
321
|
+
end
|
322
|
+
|
299
323
|
# Hooks
|
300
324
|
|
301
325
|
def before_entering_scope(scope)
|
@@ -310,11 +334,75 @@ module Rubocop
|
|
310
334
|
def after_leaving_scope(scope)
|
311
335
|
end
|
312
336
|
|
313
|
-
def before_declaring_variable(
|
337
|
+
def before_declaring_variable(variable_variable)
|
314
338
|
end
|
315
339
|
|
316
|
-
def after_declaring_variable(
|
340
|
+
def after_declaring_variable(variable_variable)
|
317
341
|
end
|
342
|
+
|
343
|
+
# Post condition loops
|
344
|
+
#
|
345
|
+
# Loop body nodes need to be scanned first.
|
346
|
+
#
|
347
|
+
# Ruby:
|
348
|
+
# begin
|
349
|
+
# foo = 1
|
350
|
+
# end while foo > 10
|
351
|
+
# puts foo
|
352
|
+
#
|
353
|
+
# AST:
|
354
|
+
# (begin
|
355
|
+
# (while-post
|
356
|
+
# (send
|
357
|
+
# (lvar :foo) :>
|
358
|
+
# (int 10))
|
359
|
+
# (kwbegin
|
360
|
+
# (lvasgn :foo
|
361
|
+
# (int 1))))
|
362
|
+
# (send nil :puts
|
363
|
+
# (lvar :foo)))
|
364
|
+
|
365
|
+
# Twisted scope types
|
366
|
+
#
|
367
|
+
# The variable foo belongs to the top level scope,
|
368
|
+
# but in AST, it's under the block node.
|
369
|
+
#
|
370
|
+
# Ruby:
|
371
|
+
# some_method(foo = 1) do
|
372
|
+
# end
|
373
|
+
# puts foo
|
374
|
+
#
|
375
|
+
# AST:
|
376
|
+
# (begin
|
377
|
+
# (block
|
378
|
+
# (send nil :some_method
|
379
|
+
# (lvasgn :foo
|
380
|
+
# (int 1)))
|
381
|
+
# (args) nil)
|
382
|
+
# (send nil :puts
|
383
|
+
# (lvar :foo)))
|
384
|
+
#
|
385
|
+
# So the the method argument nodes need to be processed
|
386
|
+
# in current scope.
|
387
|
+
#
|
388
|
+
# Same thing.
|
389
|
+
#
|
390
|
+
# Ruby:
|
391
|
+
# instance = Object.new
|
392
|
+
# class << instance
|
393
|
+
# foo = 1
|
394
|
+
# end
|
395
|
+
#
|
396
|
+
# AST:
|
397
|
+
# (begin
|
398
|
+
# (lvasgn :instance
|
399
|
+
# (send
|
400
|
+
# (const nil :Object) :new))
|
401
|
+
# (sclass
|
402
|
+
# (lvar :instance)
|
403
|
+
# (begin
|
404
|
+
# (lvasgn :foo
|
405
|
+
# (int 1))
|
318
406
|
end
|
319
407
|
end
|
320
408
|
end
|