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
@@ -0,0 +1,103 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module VariableInspector
|
6
|
+
# This class represents each assignment of a variable.
|
7
|
+
class Assignment
|
8
|
+
include Locatable
|
9
|
+
|
10
|
+
MULTIPLE_LEFT_HAND_SIDE_TYPE = :mlhs
|
11
|
+
REFERENCE_PENETRABLE_BRANCH_TYPES = %w(rescue_main ensure_main).freeze
|
12
|
+
|
13
|
+
attr_reader :node, :variable, :referenced
|
14
|
+
alias_method :referenced?, :referenced
|
15
|
+
|
16
|
+
def initialize(node, variable)
|
17
|
+
unless VARIABLE_ASSIGNMENT_TYPES.include?(node.type)
|
18
|
+
fail ArgumentError,
|
19
|
+
"Node type must be any of #{VARIABLE_ASSIGNMENT_TYPES}, " +
|
20
|
+
"passed #{node.type}"
|
21
|
+
end
|
22
|
+
|
23
|
+
@node = node
|
24
|
+
@variable = variable
|
25
|
+
@referenced = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
@node.children.first
|
30
|
+
end
|
31
|
+
|
32
|
+
def scope
|
33
|
+
@variable.scope
|
34
|
+
end
|
35
|
+
|
36
|
+
def reference!
|
37
|
+
@referenced = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def used?
|
41
|
+
@variable.captured_by_block? || @referenced
|
42
|
+
end
|
43
|
+
|
44
|
+
def reference_penetrable?
|
45
|
+
REFERENCE_PENETRABLE_BRANCH_TYPES.include?(branch_type)
|
46
|
+
end
|
47
|
+
|
48
|
+
def regexp_named_capture?
|
49
|
+
@node.type == REGEXP_NAMED_CAPTURE_TYPE
|
50
|
+
end
|
51
|
+
|
52
|
+
def operator_assignment?
|
53
|
+
return false unless meta_assignment_node
|
54
|
+
OPERATOR_ASSIGNMENT_TYPES.include?(meta_assignment_node.type)
|
55
|
+
end
|
56
|
+
|
57
|
+
def multiple_assignment?
|
58
|
+
return false unless meta_assignment_node
|
59
|
+
meta_assignment_node.type == MULTIPLE_ASSIGNMENT_TYPE
|
60
|
+
end
|
61
|
+
|
62
|
+
def operator
|
63
|
+
assignment_node = meta_assignment_node || @node
|
64
|
+
assignment_node.loc.operator.source
|
65
|
+
end
|
66
|
+
|
67
|
+
def meta_assignment_node
|
68
|
+
if instance_variable_defined?(:@meta_assignment_node)
|
69
|
+
return @meta_assignment_node
|
70
|
+
end
|
71
|
+
|
72
|
+
@meta_assignment_node = nil
|
73
|
+
|
74
|
+
return unless parent_node
|
75
|
+
|
76
|
+
if OPERATOR_ASSIGNMENT_TYPES.include?(parent_node.type) &&
|
77
|
+
parent_node.children.index(@node) == 0
|
78
|
+
return @meta_assignment_node = parent_node
|
79
|
+
end
|
80
|
+
|
81
|
+
return unless grantparent_node
|
82
|
+
|
83
|
+
if parent_node.type == MULTIPLE_LEFT_HAND_SIDE_TYPE &&
|
84
|
+
grantparent_node.type == MULTIPLE_ASSIGNMENT_TYPE
|
85
|
+
return @meta_assignment_node = grantparent_node
|
86
|
+
end
|
87
|
+
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def parent_node
|
94
|
+
ancestor_nodes_in_scope.last
|
95
|
+
end
|
96
|
+
|
97
|
+
def grantparent_node
|
98
|
+
ancestor_nodes_in_scope[-2]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module VariableInspector
|
6
|
+
# This module provides a way to locate the conditional branch the node is
|
7
|
+
# in. This is intended to be used as mix-in.
|
8
|
+
module Locatable
|
9
|
+
BRANCH_TYPES = [:if, :case].freeze
|
10
|
+
CONDITION_INDEX_OF_BRANCH_NODE = 0
|
11
|
+
|
12
|
+
LOGICAL_OPERATOR_TYPES = [:and, :or].freeze
|
13
|
+
LEFT_SIDE_INDEX_OF_LOGICAL_OPERATOR_NODE = 0
|
14
|
+
|
15
|
+
ENSURE_TYPE = :ensure
|
16
|
+
ENSURE_INDEX_OF_ENSURE_NODE = 1
|
17
|
+
|
18
|
+
def node
|
19
|
+
fail '#node must be declared!'
|
20
|
+
end
|
21
|
+
|
22
|
+
def scope
|
23
|
+
fail '#scope must be declared!'
|
24
|
+
end
|
25
|
+
|
26
|
+
def inside_of_branch?
|
27
|
+
!branch_point_node.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def branch_id
|
31
|
+
return nil unless inside_of_branch?
|
32
|
+
@branch_id ||= [branch_point_node.object_id, branch_type].join('_')
|
33
|
+
end
|
34
|
+
|
35
|
+
def branch_type
|
36
|
+
return nil unless inside_of_branch?
|
37
|
+
@branch_type ||= [branch_point_node.type, branch_body_name].join('_')
|
38
|
+
end
|
39
|
+
|
40
|
+
# Inner if, case, rescue, or ensure node.
|
41
|
+
def branch_point_node
|
42
|
+
if instance_variable_defined?(:@branch_point_node)
|
43
|
+
return @branch_point_node
|
44
|
+
end
|
45
|
+
|
46
|
+
set_branch_point_and_body_nodes!
|
47
|
+
@branch_point_node
|
48
|
+
end
|
49
|
+
|
50
|
+
# A child node of #branch_point_node this assignment belongs.
|
51
|
+
def branch_body_node
|
52
|
+
if instance_variable_defined?(:@branch_body_node)
|
53
|
+
return @branch_body_node
|
54
|
+
end
|
55
|
+
|
56
|
+
set_branch_point_and_body_nodes!
|
57
|
+
@branch_body_node
|
58
|
+
end
|
59
|
+
|
60
|
+
def ancestor_nodes_in_scope
|
61
|
+
@ancestor_nodes_in_scope ||= scope.ancestors_of_node(@node)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def branch_body_name
|
67
|
+
case branch_point_node.type
|
68
|
+
when :if
|
69
|
+
if_body_name
|
70
|
+
when :case
|
71
|
+
case_body_name
|
72
|
+
when *LOGICAL_OPERATOR_TYPES
|
73
|
+
logical_operator_body_name
|
74
|
+
when RESCUE_TYPE
|
75
|
+
rescue_body_name
|
76
|
+
when ENSURE_TYPE
|
77
|
+
ensure_body_name
|
78
|
+
else
|
79
|
+
fail InvalidBranchBodyError
|
80
|
+
end
|
81
|
+
rescue InvalidBranchBodyError
|
82
|
+
raise InvalidBranchBodyError,
|
83
|
+
"Invalid body index #{body_index} of #{branch_point_node.type}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def if_body_name
|
87
|
+
case body_index
|
88
|
+
when 1 then 'true'
|
89
|
+
when 2 then 'false'
|
90
|
+
else fail InvalidBranchBodyError
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def case_body_name
|
95
|
+
if branch_body_node.type == :when
|
96
|
+
"when#{body_index - 1}"
|
97
|
+
else
|
98
|
+
'else'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def logical_operator_body_name
|
103
|
+
case body_index
|
104
|
+
when 1 then 'right'
|
105
|
+
else fail InvalidBranchBodyError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def rescue_body_name
|
110
|
+
if body_index == 0
|
111
|
+
'main'
|
112
|
+
elsif branch_body_node.type == :resbody
|
113
|
+
"rescue#{body_index - 1}"
|
114
|
+
else
|
115
|
+
'else'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def ensure_body_name
|
120
|
+
case body_index
|
121
|
+
when 0 then 'main'
|
122
|
+
else fail InvalidBranchBodyError
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def body_index
|
127
|
+
branch_point_node.children.index(branch_body_node)
|
128
|
+
end
|
129
|
+
|
130
|
+
def set_branch_point_and_body_nodes!
|
131
|
+
ancestors_and_self_nodes = ancestor_nodes_in_scope + [@node]
|
132
|
+
|
133
|
+
ancestors_and_self_nodes.reverse.each_cons(2) do |child, parent|
|
134
|
+
next unless branch?(parent, child)
|
135
|
+
@branch_point_node = parent
|
136
|
+
@branch_body_node = child
|
137
|
+
break
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def branch?(parent_node, child_node)
|
142
|
+
child_index = parent_node.children.index(child_node)
|
143
|
+
|
144
|
+
case parent_node.type
|
145
|
+
when *BRANCH_TYPES
|
146
|
+
child_index != CONDITION_INDEX_OF_BRANCH_NODE
|
147
|
+
when *LOGICAL_OPERATOR_TYPES
|
148
|
+
child_index != LEFT_SIDE_INDEX_OF_LOGICAL_OPERATOR_NODE
|
149
|
+
when RESCUE_TYPE
|
150
|
+
true
|
151
|
+
when ENSURE_TYPE
|
152
|
+
child_index != ENSURE_INDEX_OF_ENSURE_NODE
|
153
|
+
else
|
154
|
+
false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class InvalidBranchBodyError < StandardError; end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module VariableInspector
|
6
|
+
# This class represents each reference of a variable.
|
7
|
+
class Reference
|
8
|
+
include Locatable
|
9
|
+
|
10
|
+
VARIABLE_REFERENCE_TYPES = (
|
11
|
+
[VARIABLE_REFERENCE_TYPE] +
|
12
|
+
OPERATOR_ASSIGNMENT_TYPES +
|
13
|
+
[ZERO_ARITY_SUPER_TYPE]
|
14
|
+
).freeze
|
15
|
+
|
16
|
+
attr_reader :node, :scope
|
17
|
+
|
18
|
+
def initialize(node, scope)
|
19
|
+
unless VARIABLE_REFERENCE_TYPES.include?(node.type)
|
20
|
+
fail ArgumentError,
|
21
|
+
"Node type must be any of #{VARIABLE_REFERENCE_TYPES}, " +
|
22
|
+
"passed #{node.type}"
|
23
|
+
end
|
24
|
+
|
25
|
+
@node = node
|
26
|
+
@scope = scope
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module VariableInspector
|
6
|
+
# A Scope represents a context of local variable visibility.
|
7
|
+
# This is a place where local variables belong to.
|
8
|
+
# A scope instance holds a scope node and variable entries.
|
9
|
+
class Scope
|
10
|
+
attr_reader :node, :variables
|
11
|
+
|
12
|
+
def initialize(node)
|
13
|
+
# Accept begin node for top level scope.
|
14
|
+
unless SCOPE_TYPES.include?(node.type) || node.type == :begin
|
15
|
+
fail ArgumentError,
|
16
|
+
"Node type must be any of #{SCOPE_TYPES}, " +
|
17
|
+
"passed #{node.type}"
|
18
|
+
end
|
19
|
+
@node = node
|
20
|
+
@variables = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
@node.equal?(other.node)
|
25
|
+
end
|
26
|
+
|
27
|
+
def body_node
|
28
|
+
child_index = case @node.type
|
29
|
+
when :module, :sclass, :begin then 1
|
30
|
+
when :def, :class, :block then 2
|
31
|
+
when :defs then 3
|
32
|
+
end
|
33
|
+
|
34
|
+
@node.children[child_index]
|
35
|
+
end
|
36
|
+
|
37
|
+
def ancestors_of_node(target_node)
|
38
|
+
ASTScanner.scan(@node) do |scanning_node, ancestor_nodes|
|
39
|
+
return ancestor_nodes[1..-1] if scanning_node.equal?(target_node)
|
40
|
+
end
|
41
|
+
|
42
|
+
fail "Node #{target_node} is not found in scope #{@node}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# This class provides a ways to scan AST with tracking ancestor nodes.
|
46
|
+
class ASTScanner
|
47
|
+
def self.scan(node, &block)
|
48
|
+
new.scan(node, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize
|
52
|
+
@ancestor_nodes = []
|
53
|
+
end
|
54
|
+
|
55
|
+
def scan(node, &block)
|
56
|
+
@ancestor_nodes.push(node)
|
57
|
+
|
58
|
+
node.children.each do |child|
|
59
|
+
next unless child.is_a?(Parser::AST::Node)
|
60
|
+
yield child, @ancestor_nodes
|
61
|
+
scan(child, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
@ancestor_nodes.pop
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
module VariableInspector
|
6
|
+
# A Variable represents existance of a local variable.
|
7
|
+
# This holds a variable declaration node,
|
8
|
+
# and some states of the variable.
|
9
|
+
class Variable
|
10
|
+
VARIABLE_DECLARATION_TYPES =
|
11
|
+
(VARIABLE_ASSIGNMENT_TYPES + DECLARATION_TYPES).freeze
|
12
|
+
|
13
|
+
attr_reader :name, :declaration_node, :scope,
|
14
|
+
:assignments, :captured_by_block
|
15
|
+
alias_method :captured_by_block?, :captured_by_block
|
16
|
+
|
17
|
+
def initialize(name, declaration_node, scope)
|
18
|
+
unless VARIABLE_DECLARATION_TYPES.include?(declaration_node.type)
|
19
|
+
fail ArgumentError,
|
20
|
+
"Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " +
|
21
|
+
"passed #{declaration_node.type}"
|
22
|
+
end
|
23
|
+
|
24
|
+
@name = name.to_sym
|
25
|
+
@declaration_node = declaration_node
|
26
|
+
@scope = scope
|
27
|
+
|
28
|
+
@assignments = []
|
29
|
+
@captured_by_block = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def assign(node)
|
33
|
+
@assignments << Assignment.new(node, self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def referenced?
|
37
|
+
@assignments.any?(&:referenced?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def reference!(node)
|
41
|
+
reference = Reference.new(node, @scope)
|
42
|
+
consumed_branch_ids = Set.new
|
43
|
+
|
44
|
+
@assignments.reverse_each do |assignment|
|
45
|
+
next if consumed_branch_ids.include?(assignment.branch_id)
|
46
|
+
|
47
|
+
assignment.reference!
|
48
|
+
|
49
|
+
if assignment.inside_of_branch?
|
50
|
+
break if assignment.branch_id == reference.branch_id
|
51
|
+
|
52
|
+
unless assignment.reference_penetrable?
|
53
|
+
consumed_branch_ids << assignment.branch_id
|
54
|
+
end
|
55
|
+
else
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def capture_with_block!
|
62
|
+
@captured_by_block = true
|
63
|
+
end
|
64
|
+
|
65
|
+
# This is a convenient way to check whether the variable is used
|
66
|
+
# in its entire variable lifetime.
|
67
|
+
# For more precise usage check, refer Assignment#used?.
|
68
|
+
#
|
69
|
+
# Once the variable is captured by a block, we have no idea
|
70
|
+
# when, where and how many times the block would be invoked
|
71
|
+
# and it means we cannot track the usage of the variable.
|
72
|
+
# So we consider it's used to suppress false positive offences.
|
73
|
+
def used?
|
74
|
+
@captured_by_block || referenced?
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_argument?
|
78
|
+
METHOD_ARGUMENT_DECLARATION_TYPES.include?(@declaration_node.type)
|
79
|
+
end
|
80
|
+
|
81
|
+
def block_local_variable?
|
82
|
+
@declaration_node.type == BLOCK_LOCAL_VARIABLE_DECLARATION_TYPE
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|