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.

Files changed (279) hide show
  1. data/CHANGELOG.md +40 -0
  2. data/README.md +49 -8
  3. data/config/default.yml +40 -0
  4. data/config/enabled.yml +37 -9
  5. data/lib/rubocop.rb +24 -10
  6. data/lib/rubocop/cli.rb +41 -106
  7. data/lib/rubocop/config.rb +3 -2
  8. data/lib/rubocop/cop/commissioner.rb +15 -5
  9. data/lib/rubocop/cop/cop.rb +47 -32
  10. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  11. data/lib/rubocop/cop/lint/block_alignment.rb +30 -9
  12. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  13. data/lib/rubocop/cop/lint/end_alignment.rb +4 -4
  14. data/lib/rubocop/cop/lint/end_in_method.rb +1 -1
  15. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  16. data/lib/rubocop/cop/lint/eval.rb +1 -3
  17. data/lib/rubocop/cop/lint/handle_exceptions.rb +1 -1
  18. data/lib/rubocop/cop/lint/literal_in_condition.rb +6 -4
  19. data/lib/rubocop/cop/lint/loop.rb +1 -1
  20. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  21. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  22. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -8
  23. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  24. data/lib/rubocop/cop/lint/useless_assignment.rb +57 -60
  25. data/lib/rubocop/cop/lint/useless_comparison.rb +1 -1
  26. data/lib/rubocop/cop/lint/useless_setter_call.rb +85 -0
  27. data/lib/rubocop/cop/lint/void.rb +6 -8
  28. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
  29. data/lib/rubocop/cop/rails/read_attribute.rb +1 -1
  30. data/lib/rubocop/cop/rails/validation.rb +1 -1
  31. data/lib/rubocop/cop/style/access_control.rb +4 -6
  32. data/lib/rubocop/cop/style/alias.rb +1 -3
  33. data/lib/rubocop/cop/style/align_array.rb +47 -0
  34. data/lib/rubocop/cop/style/align_hash.rb +145 -0
  35. data/lib/rubocop/cop/style/align_parameters.rb +9 -3
  36. data/lib/rubocop/cop/style/and_or.rb +3 -4
  37. data/lib/rubocop/cop/style/ascii_comments.rb +1 -3
  38. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -1
  39. data/lib/rubocop/cop/style/attr.rb +1 -4
  40. data/lib/rubocop/cop/style/begin_block.rb +1 -1
  41. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  42. data/lib/rubocop/cop/style/block_nesting.rb +2 -2
  43. data/lib/rubocop/cop/style/blocks.rb +14 -2
  44. data/lib/rubocop/cop/style/case_equality.rb +1 -3
  45. data/lib/rubocop/cop/style/case_indentation.rb +1 -1
  46. data/lib/rubocop/cop/style/character_literal.rb +1 -2
  47. data/lib/rubocop/cop/style/class_and_module_camel_case.rb +1 -1
  48. data/lib/rubocop/cop/style/class_methods.rb +1 -3
  49. data/lib/rubocop/cop/style/{avoid_class_vars.rb → class_vars.rb} +6 -2
  50. data/lib/rubocop/cop/style/collection_methods.rb +7 -9
  51. data/lib/rubocop/cop/style/colon_method_call.rb +1 -2
  52. data/lib/rubocop/cop/style/comment_annotation.rb +6 -6
  53. data/lib/rubocop/cop/style/constant_name.rb +1 -3
  54. data/lib/rubocop/cop/style/def_parentheses.rb +4 -12
  55. data/lib/rubocop/cop/style/documentation.rb +2 -2
  56. data/lib/rubocop/cop/style/dot_position.rb +2 -4
  57. data/lib/rubocop/cop/style/empty_line_between_defs.rb +21 -6
  58. data/lib/rubocop/cop/style/empty_lines.rb +1 -1
  59. data/lib/rubocop/cop/style/empty_literal.rb +3 -12
  60. data/lib/rubocop/cop/style/encoding.rb +6 -6
  61. data/lib/rubocop/cop/style/end_block.rb +1 -1
  62. data/lib/rubocop/cop/style/end_of_line.rb +5 -5
  63. data/lib/rubocop/cop/style/even_odd.rb +2 -2
  64. data/lib/rubocop/cop/style/favor_join.rb +1 -3
  65. data/lib/rubocop/cop/style/favor_modifier.rb +7 -3
  66. data/lib/rubocop/cop/style/favor_sprintf.rb +1 -1
  67. data/lib/rubocop/cop/style/favor_unless_over_negated_if.rb +1 -1
  68. data/lib/rubocop/cop/style/final_newline.rb +23 -0
  69. data/lib/rubocop/cop/style/{avoid_for.rb → for.rb} +2 -2
  70. data/lib/rubocop/cop/style/{avoid_global_vars.rb → global_vars.rb} +19 -6
  71. data/lib/rubocop/cop/style/hash_methods.rb +3 -5
  72. data/lib/rubocop/cop/style/hash_syntax.rb +4 -4
  73. data/lib/rubocop/cop/style/if_then_else.rb +1 -1
  74. data/lib/rubocop/cop/style/indentation_width.rb +4 -4
  75. data/lib/rubocop/cop/style/lambda.rb +2 -2
  76. data/lib/rubocop/cop/style/leading_comment_space.rb +1 -1
  77. data/lib/rubocop/cop/style/line_length.rb +7 -8
  78. data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +1 -1
  79. data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -4
  80. data/lib/rubocop/cop/style/method_length.rb +4 -4
  81. data/lib/rubocop/cop/style/module_function.rb +1 -3
  82. data/lib/rubocop/cop/style/multiline_block_chain.rb +44 -0
  83. data/lib/rubocop/cop/style/nil_comparison.rb +1 -3
  84. data/lib/rubocop/cop/style/not.rb +1 -1
  85. data/lib/rubocop/cop/style/numeric_literals.rb +26 -6
  86. data/lib/rubocop/cop/style/op_method.rb +2 -2
  87. data/lib/rubocop/cop/style/parameter_lists.rb +4 -4
  88. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  89. data/lib/rubocop/cop/style/perl_backrefs.rb +26 -0
  90. data/lib/rubocop/cop/style/proc.rb +1 -3
  91. data/lib/rubocop/cop/style/reduce_arguments.rb +7 -5
  92. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  93. data/lib/rubocop/cop/style/redundant_return.rb +9 -2
  94. data/lib/rubocop/cop/style/redundant_self.rb +9 -2
  95. data/lib/rubocop/cop/style/regexp_literal.rb +7 -8
  96. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  97. data/lib/rubocop/cop/style/semicolon.rb +10 -10
  98. data/lib/rubocop/cop/style/signal_exception.rb +2 -4
  99. data/lib/rubocop/cop/style/single_line_methods.rb +2 -4
  100. data/lib/rubocop/cop/style/space_after_comma_etc.rb +1 -1
  101. data/lib/rubocop/cop/style/space_after_control_keyword.rb +1 -1
  102. data/lib/rubocop/cop/style/space_after_method_name.rb +1 -1
  103. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +34 -0
  104. data/lib/rubocop/cop/style/{avoid_perlisms.rb → special_global_vars.rb} +17 -8
  105. data/lib/rubocop/cop/style/string_literals.rb +1 -2
  106. data/lib/rubocop/cop/style/surrounding_space.rb +9 -8
  107. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  108. data/lib/rubocop/cop/style/symbol_name.rb +9 -2
  109. data/lib/rubocop/cop/style/tab.rb +5 -5
  110. data/lib/rubocop/cop/style/ternary_operator.rb +2 -6
  111. data/lib/rubocop/cop/style/trailing_blank_lines.rb +32 -0
  112. data/lib/rubocop/cop/style/trailing_whitespace.rb +5 -6
  113. data/lib/rubocop/cop/style/trivial_accessors.rb +5 -5
  114. data/lib/rubocop/cop/style/unless_else.rb +1 -1
  115. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -3
  116. data/lib/rubocop/cop/style/when_then.rb +1 -4
  117. data/lib/rubocop/cop/style/while_until_do.rb +7 -5
  118. data/lib/rubocop/cop/style/word_array.rb +1 -1
  119. data/lib/rubocop/cop/team.rb +100 -0
  120. data/lib/rubocop/cop/variable_inspector.rb +323 -235
  121. data/lib/rubocop/cop/variable_inspector/assignment.rb +103 -0
  122. data/lib/rubocop/cop/variable_inspector/locatable.rb +162 -0
  123. data/lib/rubocop/cop/variable_inspector/reference.rb +31 -0
  124. data/lib/rubocop/cop/variable_inspector/scope.rb +70 -0
  125. data/lib/rubocop/cop/variable_inspector/variable.rb +87 -0
  126. data/lib/rubocop/cop/variable_inspector/variable_table.rb +129 -0
  127. data/lib/rubocop/formatter/json_formatter.rb +8 -8
  128. data/lib/rubocop/formatter/progress_formatter.rb +4 -4
  129. data/lib/rubocop/processed_source.rb +22 -1
  130. data/lib/rubocop/version.rb +1 -1
  131. data/rubocop.gemspec +1 -1
  132. data/spec/rubocop/cli_spec.rb +32 -30
  133. data/spec/rubocop/config_spec.rb +4 -6
  134. data/spec/rubocop/cop/commissioner_spec.rb +4 -5
  135. data/spec/rubocop/cop/cop_spec.rb +8 -26
  136. data/spec/rubocop/cop/lint/assignment_in_condition_spec.rb +5 -9
  137. data/spec/rubocop/cop/lint/block_alignment_spec.rb +105 -57
  138. data/spec/rubocop/cop/lint/empty_ensure_spec.rb +1 -1
  139. data/spec/rubocop/cop/lint/end_alignment_spec.rb +1 -1
  140. data/spec/rubocop/cop/lint/end_in_method_spec.rb +1 -1
  141. data/spec/rubocop/cop/lint/ensure_return_spec.rb +1 -1
  142. data/spec/rubocop/cop/lint/eval_spec.rb +3 -3
  143. data/spec/rubocop/cop/lint/handle_exceptions_spec.rb +2 -2
  144. data/spec/rubocop/cop/lint/literal_in_condition_spec.rb +1 -1
  145. data/spec/rubocop/cop/lint/loop_spec.rb +1 -1
  146. data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +1 -1
  147. data/spec/rubocop/cop/lint/rescue_exception_spec.rb +5 -5
  148. data/spec/rubocop/cop/lint/unreachable_code_spec.rb +1 -1
  149. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +1545 -108
  150. data/spec/rubocop/cop/lint/useless_comparison_spec.rb +1 -1
  151. data/spec/rubocop/cop/lint/useless_setter_call_spec.rb +101 -0
  152. data/spec/rubocop/cop/lint/void_spec.rb +1 -1
  153. data/spec/rubocop/cop/offence_spec.rb +4 -4
  154. data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +1 -1
  155. data/spec/rubocop/cop/rails/read_attribute_spec.rb +1 -1
  156. data/spec/rubocop/cop/rails/validation_spec.rb +1 -1
  157. data/spec/rubocop/cop/style/access_control_spec.rb +20 -20
  158. data/spec/rubocop/cop/style/alias_spec.rb +3 -3
  159. data/spec/rubocop/cop/style/align_array_spec.rb +62 -0
  160. data/spec/rubocop/cop/style/align_hash_spec.rb +267 -0
  161. data/spec/rubocop/cop/style/align_parameters_spec.rb +2 -2
  162. data/spec/rubocop/cop/style/and_or_spec.rb +1 -1
  163. data/spec/rubocop/cop/style/ascii_comments_spec.rb +2 -2
  164. data/spec/rubocop/cop/style/ascii_identifiers_spec.rb +2 -2
  165. data/spec/rubocop/cop/style/attr_spec.rb +1 -1
  166. data/spec/rubocop/cop/style/begin_block_spec.rb +1 -1
  167. data/spec/rubocop/cop/style/block_comments_spec.rb +1 -1
  168. data/spec/rubocop/cop/style/block_nesting_spec.rb +3 -3
  169. data/spec/rubocop/cop/style/blocks_spec.rb +25 -1
  170. data/spec/rubocop/cop/style/case_equality_spec.rb +1 -1
  171. data/spec/rubocop/cop/style/case_indentation_spec.rb +5 -5
  172. data/spec/rubocop/cop/style/character_literal_spec.rb +1 -1
  173. data/spec/rubocop/cop/style/class_and_module_camel_case_spec.rb +1 -1
  174. data/spec/rubocop/cop/style/class_methods_spec.rb +1 -1
  175. data/spec/rubocop/cop/style/class_vars_spec.rb +25 -0
  176. data/spec/rubocop/cop/style/collection_methods_spec.rb +5 -6
  177. data/spec/rubocop/cop/style/colon_method_call_spec.rb +0 -3
  178. data/spec/rubocop/cop/style/comment_annotation_spec.rb +20 -18
  179. data/spec/rubocop/cop/style/constant_name_spec.rb +1 -1
  180. data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +1 -1
  181. data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +1 -1
  182. data/spec/rubocop/cop/style/documentation_spec.rb +1 -1
  183. data/spec/rubocop/cop/style/dot_position_spec.rb +5 -5
  184. data/spec/rubocop/cop/style/empty_line_between_defs_spec.rb +35 -4
  185. data/spec/rubocop/cop/style/empty_lines_spec.rb +1 -1
  186. data/spec/rubocop/cop/style/empty_literal_spec.rb +7 -7
  187. data/spec/rubocop/cop/style/encoding_spec.rb +11 -5
  188. data/spec/rubocop/cop/style/end_block_spec.rb +1 -1
  189. data/spec/rubocop/cop/style/end_of_line_spec.rb +4 -3
  190. data/spec/rubocop/cop/style/even_odd_spec.rb +1 -1
  191. data/spec/rubocop/cop/style/favor_join_spec.rb +2 -2
  192. data/spec/rubocop/cop/style/favor_modifier_spec.rb +13 -10
  193. data/spec/rubocop/cop/style/favor_sprintf_spec.rb +4 -4
  194. data/spec/rubocop/cop/style/favor_unless_over_negated_if_spec.rb +1 -1
  195. data/spec/rubocop/cop/style/favor_until_over_negated_while_spec.rb +4 -4
  196. data/spec/rubocop/cop/style/final_newline_spec.rb +25 -0
  197. data/spec/rubocop/cop/style/{avoid_for_spec.rb → for_spec.rb} +8 -12
  198. data/spec/rubocop/cop/style/{avoid_global_vars_spec.rb → global_vars_spec.rb} +13 -3
  199. data/spec/rubocop/cop/style/hash_methods_spec.rb +1 -1
  200. data/spec/rubocop/cop/style/hash_syntax_spec.rb +20 -9
  201. data/spec/rubocop/cop/style/if_with_semicolon_spec.rb +3 -3
  202. data/spec/rubocop/cop/style/indentation_width_spec.rb +19 -19
  203. data/spec/rubocop/cop/style/lambda_spec.rb +6 -6
  204. data/spec/rubocop/cop/style/leading_comment_space_spec.rb +1 -1
  205. data/spec/rubocop/cop/style/line_length_spec.rb +3 -3
  206. data/spec/rubocop/cop/style/method_and_variable_snake_case_spec.rb +8 -9
  207. data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +1 -1
  208. data/spec/rubocop/cop/style/method_length_spec.rb +18 -17
  209. data/spec/rubocop/cop/style/module_function_spec.rb +1 -1
  210. data/spec/rubocop/cop/style/multiline_block_chain_spec.rb +84 -0
  211. data/spec/rubocop/cop/style/multiline_if_then_spec.rb +2 -2
  212. data/spec/rubocop/cop/style/nil_comparison_spec.rb +1 -1
  213. data/spec/rubocop/cop/style/not_spec.rb +1 -1
  214. data/spec/rubocop/cop/style/numeric_literals_spec.rb +15 -25
  215. data/spec/rubocop/cop/style/one_line_conditional_spec.rb +2 -2
  216. data/spec/rubocop/cop/style/op_method_spec.rb +3 -3
  217. data/spec/rubocop/cop/style/parameter_lists_spec.rb +5 -5
  218. data/spec/rubocop/cop/style/parentheses_around_condition_spec.rb +4 -8
  219. data/spec/rubocop/cop/style/perl_backrefs_spec.rb +23 -0
  220. data/spec/rubocop/cop/style/proc_spec.rb +1 -1
  221. data/spec/rubocop/cop/style/reduce_arguments_spec.rb +18 -11
  222. data/spec/rubocop/cop/style/redundant_begin_spec.rb +1 -1
  223. data/spec/rubocop/cop/style/redundant_return_spec.rb +16 -1
  224. data/spec/rubocop/cop/style/redundant_self_spec.rb +6 -1
  225. data/spec/rubocop/cop/style/regexp_literal_spec.rb +19 -23
  226. data/spec/rubocop/cop/style/rescue_modifier_spec.rb +3 -3
  227. data/spec/rubocop/cop/style/semicolon_spec.rb +3 -3
  228. data/spec/rubocop/cop/style/signal_exception_spec.rb +1 -1
  229. data/spec/rubocop/cop/style/single_line_methods_spec.rb +22 -18
  230. data/spec/rubocop/cop/style/space_after_colon_spec.rb +4 -4
  231. data/spec/rubocop/cop/style/space_after_comma_spec.rb +4 -4
  232. data/spec/rubocop/cop/style/space_after_control_keyword_spec.rb +1 -1
  233. data/spec/rubocop/cop/style/space_after_method_name_spec.rb +1 -1
  234. data/spec/rubocop/cop/style/space_after_semicolon_spec.rb +3 -3
  235. data/spec/rubocop/cop/style/space_around_braces_spec.rb +13 -12
  236. data/spec/rubocop/cop/style/space_around_equals_in_default_parameter_spec.rb +3 -3
  237. data/spec/rubocop/cop/style/space_around_operators_spec.rb +25 -25
  238. data/spec/rubocop/cop/style/space_before_modifier_keyword_spec.rb +53 -0
  239. data/spec/rubocop/cop/style/space_inside_brackets_spec.rb +9 -9
  240. data/spec/rubocop/cop/style/space_inside_hash_literal_braces_spec.rb +47 -61
  241. data/spec/rubocop/cop/style/space_inside_parens_spec.rb +4 -4
  242. data/spec/rubocop/cop/style/special_global_vars_spec.rb +52 -0
  243. data/spec/rubocop/cop/style/string_literals_spec.rb +5 -5
  244. data/spec/rubocop/cop/style/symbol_array_spec.rb +1 -1
  245. data/spec/rubocop/cop/style/symbol_name_spec.rb +27 -18
  246. data/spec/rubocop/cop/style/tab_spec.rb +1 -1
  247. data/spec/rubocop/cop/style/ternary_operator_spec.rb +2 -2
  248. data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +24 -0
  249. data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +7 -7
  250. data/spec/rubocop/cop/style/trivial_accessors_spec.rb +6 -14
  251. data/spec/rubocop/cop/style/unless_else_spec.rb +3 -3
  252. data/spec/rubocop/cop/style/variable_interpolation_spec.rb +5 -5
  253. data/spec/rubocop/cop/style/when_then_spec.rb +15 -15
  254. data/spec/rubocop/cop/style/while_until_do_spec.rb +3 -3
  255. data/spec/rubocop/cop/style/word_array_spec.rb +1 -1
  256. data/spec/rubocop/cop/team_spec.rb +158 -0
  257. data/spec/rubocop/cop/variable_inspector/assignment_spec.rb +217 -0
  258. data/spec/rubocop/cop/variable_inspector/locatable_spec.rb +740 -0
  259. data/spec/rubocop/cop/variable_inspector/scope_spec.rb +191 -0
  260. data/spec/rubocop/cop/variable_inspector/variable_spec.rb +79 -0
  261. data/spec/rubocop/cop/variable_inspector/variable_table_spec.rb +275 -0
  262. data/spec/rubocop/cop/variable_inspector_spec.rb +13 -533
  263. data/spec/rubocop/formatter/clang_style_formatter_spec.rb +4 -4
  264. data/spec/rubocop/formatter/disabled_config_formatter_spec.rb +1 -1
  265. data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +3 -3
  266. data/spec/rubocop/formatter/file_list_formatter_spec.rb +3 -3
  267. data/spec/rubocop/formatter/progress_formatter_spec.rb +1 -1
  268. data/spec/spec_helper.rb +5 -1
  269. data/spec/support/ast_helper.rb +15 -0
  270. data/spec/support/shared_context.rb +18 -0
  271. data/spec/support/shared_examples.rb +1 -1
  272. metadata +95 -32
  273. checksums.yaml +0 -7
  274. data/lib/rubocop/cop/lint/unused_local_variable.rb +0 -32
  275. data/lib/rubocop/cop/style/avoid_perl_backrefs.rb +0 -19
  276. data/spec/rubocop/cop/lint/unused_local_variable_spec.rb +0 -588
  277. data/spec/rubocop/cop/style/avoid_class_vars_spec.rb +0 -27
  278. data/spec/rubocop/cop/style/avoid_perl_backrefs_spec.rb +0 -20
  279. 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