rubocop 0.80.1 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/config/default.yml +202 -49
  4. data/lib/rubocop.rb +20 -61
  5. data/lib/rubocop/ast_aliases.rb +8 -0
  6. data/lib/rubocop/cli.rb +13 -7
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  8. data/lib/rubocop/cli/command/show_cops.rb +2 -6
  9. data/lib/rubocop/comment_config.rb +1 -1
  10. data/lib/rubocop/config.rb +14 -2
  11. data/lib/rubocop/config_loader.rb +37 -33
  12. data/lib/rubocop/config_loader_resolver.rb +45 -6
  13. data/lib/rubocop/config_obsoletion.rb +2 -0
  14. data/lib/rubocop/config_store.rb +12 -2
  15. data/lib/rubocop/config_validator.rb +18 -1
  16. data/lib/rubocop/cop/autocorrect_logic.rb +1 -2
  17. data/lib/rubocop/cop/badge.rb +5 -5
  18. data/lib/rubocop/cop/bundler/gem_comment.rb +70 -1
  19. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +1 -1
  20. data/lib/rubocop/cop/commissioner.rb +0 -21
  21. data/lib/rubocop/cop/cop.rb +14 -6
  22. data/lib/rubocop/cop/corrector.rb +48 -24
  23. data/lib/rubocop/cop/correctors/alignment_corrector.rb +4 -8
  24. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -2
  25. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +4 -4
  27. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  28. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/space_corrector.rb +1 -3
  30. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +2 -2
  31. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -3
  32. data/lib/rubocop/cop/generator.rb +4 -3
  33. data/lib/rubocop/cop/ignored_node.rb +1 -3
  34. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -1
  35. data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
  36. data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
  37. data/lib/rubocop/cop/layout/case_indentation.rb +3 -3
  38. data/lib/rubocop/cop/layout/class_structure.rb +19 -16
  39. data/lib/rubocop/cop/layout/condition_position.rb +12 -2
  40. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  41. data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
  42. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -6
  43. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +126 -0
  44. data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
  45. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -3
  46. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +14 -10
  47. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +1 -1
  48. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  49. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -3
  50. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  51. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -6
  52. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -9
  53. data/lib/rubocop/cop/layout/heredoc_indentation.rb +20 -103
  54. data/lib/rubocop/cop/layout/{tab.rb → indentation_style.rb} +48 -6
  55. data/lib/rubocop/cop/layout/indentation_width.rb +1 -3
  56. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  57. data/lib/rubocop/cop/layout/line_length.rb +23 -20
  58. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
  59. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -3
  60. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  61. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +13 -4
  62. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -3
  63. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  64. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +131 -0
  65. data/lib/rubocop/cop/layout/space_around_operators.rb +19 -2
  66. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -3
  67. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -1
  68. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -3
  69. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -2
  70. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +2 -2
  71. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -3
  72. data/lib/rubocop/cop/layout/trailing_whitespace.rb +2 -2
  73. data/lib/rubocop/cop/lint/ambiguous_operator.rb +41 -0
  74. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +14 -0
  75. data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
  76. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  77. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +137 -0
  78. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -5
  79. data/lib/rubocop/cop/lint/empty_when.rb +29 -6
  80. data/lib/rubocop/cop/lint/ensure_return.rb +19 -2
  81. data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -4
  82. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  83. data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
  84. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
  85. data/lib/rubocop/cop/lint/literal_as_condition.rb +10 -13
  86. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  87. data/lib/rubocop/cop/lint/loop.rb +7 -5
  88. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +62 -0
  89. data/lib/rubocop/cop/lint/multiple_comparison.rb +1 -1
  90. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  91. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  92. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  93. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +7 -7
  94. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  95. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +33 -11
  96. data/lib/rubocop/cop/lint/percent_string_array.rb +2 -4
  97. data/lib/rubocop/cop/lint/raise_exception.rb +75 -0
  98. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -6
  99. data/lib/rubocop/cop/lint/redundant_require_statement.rb +3 -3
  100. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  101. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  102. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  103. data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
  104. data/lib/rubocop/cop/lint/suppressed_exception.rb +23 -26
  105. data/lib/rubocop/cop/lint/syntax.rb +1 -3
  106. data/lib/rubocop/cop/lint/unified_integer.rb +0 -2
  107. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  108. data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
  109. data/lib/rubocop/cop/lint/uri_regexp.rb +4 -4
  110. data/lib/rubocop/cop/lint/useless_access_modifier.rb +13 -3
  111. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -2
  112. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +6 -1
  113. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  114. data/lib/rubocop/cop/migration/department_name.rb +22 -9
  115. data/lib/rubocop/cop/mixin/alignment.rb +1 -3
  116. data/lib/rubocop/cop/mixin/array_min_size.rb +1 -3
  117. data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -9
  118. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -3
  119. data/lib/rubocop/cop/mixin/configurable_formatting.rb +2 -4
  120. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
  121. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +10 -1
  122. data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -2
  123. data/lib/rubocop/cop/mixin/ignored_pattern.rb +1 -1
  124. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -2
  125. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
  126. data/lib/rubocop/cop/mixin/parser_diagnostic.rb +1 -1
  127. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +16 -0
  128. data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -22
  129. data/lib/rubocop/cop/mixin/target_ruby_version.rb +5 -1
  130. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
  131. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +1 -1
  132. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +11 -1
  133. data/lib/rubocop/cop/naming/constant_name.rb +2 -1
  134. data/lib/rubocop/cop/naming/file_name.rb +27 -14
  135. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +1 -1
  136. data/lib/rubocop/cop/naming/method_name.rb +26 -0
  137. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  138. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  139. data/lib/rubocop/cop/registry.rb +12 -7
  140. data/lib/rubocop/cop/severity.rb +1 -3
  141. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
  142. data/lib/rubocop/cop/style/alias.rb +4 -4
  143. data/lib/rubocop/cop/style/and_or.rb +7 -8
  144. data/lib/rubocop/cop/style/array_join.rb +2 -2
  145. data/lib/rubocop/cop/style/attr.rb +1 -3
  146. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -1
  147. data/lib/rubocop/cop/style/block_delimiters.rb +2 -8
  148. data/lib/rubocop/cop/style/case_equality.rb +24 -1
  149. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  150. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  151. data/lib/rubocop/cop/style/conditional_assignment.rb +9 -11
  152. data/lib/rubocop/cop/style/copyright.rb +3 -3
  153. data/lib/rubocop/cop/style/dir.rb +1 -1
  154. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -0
  155. data/lib/rubocop/cop/style/documentation.rb +43 -5
  156. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -1
  157. data/lib/rubocop/cop/style/double_negation.rb +41 -4
  158. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  159. data/lib/rubocop/cop/style/each_with_object.rb +3 -3
  160. data/lib/rubocop/cop/style/empty_literal.rb +1 -3
  161. data/lib/rubocop/cop/style/empty_method.rb +2 -6
  162. data/lib/rubocop/cop/style/end_block.rb +6 -0
  163. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  164. data/lib/rubocop/cop/style/expand_path_arguments.rb +3 -3
  165. data/lib/rubocop/cop/style/exponential_notation.rb +119 -0
  166. data/lib/rubocop/cop/style/format_string.rb +2 -2
  167. data/lib/rubocop/cop/style/format_string_token.rb +2 -3
  168. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -6
  169. data/lib/rubocop/cop/style/guard_clause.rb +25 -2
  170. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -4
  171. data/lib/rubocop/cop/style/hash_syntax.rb +19 -12
  172. data/lib/rubocop/cop/style/hash_transform_keys.rb +6 -2
  173. data/lib/rubocop/cop/style/hash_transform_values.rb +6 -5
  174. data/lib/rubocop/cop/style/if_unless_modifier.rb +23 -3
  175. data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -0
  176. data/lib/rubocop/cop/style/inline_comment.rb +1 -1
  177. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  178. data/lib/rubocop/cop/style/lambda.rb +3 -2
  179. data/lib/rubocop/cop/style/lambda_call.rb +1 -21
  180. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +1 -3
  181. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -3
  182. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  183. data/lib/rubocop/cop/style/module_function.rb +58 -12
  184. data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
  185. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  186. data/lib/rubocop/cop/style/multiline_when_then.rb +16 -1
  187. data/lib/rubocop/cop/style/mutable_constant.rb +2 -4
  188. data/lib/rubocop/cop/style/negated_if.rb +3 -3
  189. data/lib/rubocop/cop/style/negated_unless.rb +3 -3
  190. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  191. data/lib/rubocop/cop/style/next.rb +2 -2
  192. data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
  193. data/lib/rubocop/cop/style/non_nil_check.rb +5 -5
  194. data/lib/rubocop/cop/style/not.rb +1 -1
  195. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  196. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  197. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  198. data/lib/rubocop/cop/style/one_line_conditional.rb +6 -9
  199. data/lib/rubocop/cop/style/optional_arguments.rb +1 -1
  200. data/lib/rubocop/cop/style/or_assignment.rb +1 -1
  201. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  202. data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
  203. data/lib/rubocop/cop/style/proc.rb +1 -1
  204. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  205. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  206. data/lib/rubocop/cop/style/redundant_condition.rb +3 -4
  207. data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
  208. data/lib/rubocop/cop/style/redundant_exception.rb +3 -3
  209. data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
  210. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -6
  211. data/lib/rubocop/cop/style/redundant_percent_q.rb +3 -3
  212. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +89 -0
  213. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +130 -0
  214. data/lib/rubocop/cop/style/redundant_return.rb +5 -7
  215. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  216. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  217. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
  218. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  219. data/lib/rubocop/cop/style/safe_navigation.rb +3 -7
  220. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  221. data/lib/rubocop/cop/style/slicing_with_range.rb +39 -0
  222. data/lib/rubocop/cop/style/special_global_vars.rb +3 -7
  223. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -4
  224. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -1
  225. data/lib/rubocop/cop/style/symbol_array.rb +2 -2
  226. data/lib/rubocop/cop/style/symbol_literal.rb +2 -2
  227. data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -5
  228. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +35 -0
  229. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
  230. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +88 -0
  231. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
  232. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +1 -3
  233. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  234. data/lib/rubocop/cop/style/unless_else.rb +1 -1
  235. data/lib/rubocop/cop/style/unpack_first.rb +0 -4
  236. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
  237. data/lib/rubocop/cop/style/when_then.rb +1 -1
  238. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  239. data/lib/rubocop/cop/style/word_array.rb +1 -1
  240. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
  241. data/lib/rubocop/cop/team.rb +61 -25
  242. data/lib/rubocop/cop/util.rb +25 -1
  243. data/lib/rubocop/cop/variable_force.rb +3 -9
  244. data/lib/rubocop/cop/variable_force/assignment.rb +1 -0
  245. data/lib/rubocop/cop/variable_force/branch.rb +1 -3
  246. data/lib/rubocop/cop/variable_force/scope.rb +1 -0
  247. data/lib/rubocop/cop/variable_force/variable.rb +3 -6
  248. data/lib/rubocop/ext/processed_source.rb +18 -0
  249. data/lib/rubocop/formatter/base_formatter.rb +0 -4
  250. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  251. data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -12
  252. data/lib/rubocop/formatter/formatter_set.rb +1 -4
  253. data/lib/rubocop/formatter/junit_formatter.rb +27 -6
  254. data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
  255. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  256. data/lib/rubocop/magic_comment.rb +1 -1
  257. data/lib/rubocop/name_similarity.rb +12 -9
  258. data/lib/rubocop/options.rb +33 -12
  259. data/lib/rubocop/remote_config.rb +1 -3
  260. data/lib/rubocop/result_cache.rb +5 -7
  261. data/lib/rubocop/rspec/cop_helper.rb +3 -26
  262. data/lib/rubocop/rspec/expect_offense.rb +46 -16
  263. data/lib/rubocop/rspec/shared_contexts.rb +54 -20
  264. data/lib/rubocop/runner.rb +21 -14
  265. data/lib/rubocop/target_finder.rb +7 -7
  266. data/lib/rubocop/target_ruby.rb +5 -2
  267. data/lib/rubocop/version.rb +5 -3
  268. metadata +50 -77
  269. data/lib/rubocop/ast/builder.rb +0 -83
  270. data/lib/rubocop/ast/node.rb +0 -632
  271. data/lib/rubocop/ast/node/alias_node.rb +0 -24
  272. data/lib/rubocop/ast/node/and_node.rb +0 -29
  273. data/lib/rubocop/ast/node/args_node.rb +0 -29
  274. data/lib/rubocop/ast/node/array_node.rb +0 -57
  275. data/lib/rubocop/ast/node/block_node.rb +0 -117
  276. data/lib/rubocop/ast/node/break_node.rb +0 -17
  277. data/lib/rubocop/ast/node/case_node.rb +0 -56
  278. data/lib/rubocop/ast/node/class_node.rb +0 -31
  279. data/lib/rubocop/ast/node/def_node.rb +0 -82
  280. data/lib/rubocop/ast/node/defined_node.rb +0 -17
  281. data/lib/rubocop/ast/node/ensure_node.rb +0 -17
  282. data/lib/rubocop/ast/node/float_node.rb +0 -12
  283. data/lib/rubocop/ast/node/for_node.rb +0 -53
  284. data/lib/rubocop/ast/node/forward_args_node.rb +0 -18
  285. data/lib/rubocop/ast/node/hash_node.rb +0 -109
  286. data/lib/rubocop/ast/node/if_node.rb +0 -175
  287. data/lib/rubocop/ast/node/int_node.rb +0 -12
  288. data/lib/rubocop/ast/node/keyword_splat_node.rb +0 -45
  289. data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +0 -16
  290. data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +0 -43
  291. data/lib/rubocop/ast/node/mixin/collection_node.rb +0 -15
  292. data/lib/rubocop/ast/node/mixin/conditional_node.rb +0 -45
  293. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +0 -125
  294. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -261
  295. data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +0 -114
  296. data/lib/rubocop/ast/node/mixin/modifier_node.rb +0 -17
  297. data/lib/rubocop/ast/node/mixin/numeric_node.rb +0 -21
  298. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +0 -61
  299. data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +0 -35
  300. data/lib/rubocop/ast/node/module_node.rb +0 -24
  301. data/lib/rubocop/ast/node/or_node.rb +0 -29
  302. data/lib/rubocop/ast/node/pair_node.rb +0 -63
  303. data/lib/rubocop/ast/node/range_node.rb +0 -18
  304. data/lib/rubocop/ast/node/regexp_node.rb +0 -33
  305. data/lib/rubocop/ast/node/resbody_node.rb +0 -24
  306. data/lib/rubocop/ast/node/retry_node.rb +0 -17
  307. data/lib/rubocop/ast/node/return_node.rb +0 -24
  308. data/lib/rubocop/ast/node/self_class_node.rb +0 -24
  309. data/lib/rubocop/ast/node/send_node.rb +0 -13
  310. data/lib/rubocop/ast/node/str_node.rb +0 -16
  311. data/lib/rubocop/ast/node/super_node.rb +0 -21
  312. data/lib/rubocop/ast/node/symbol_node.rb +0 -12
  313. data/lib/rubocop/ast/node/until_node.rb +0 -35
  314. data/lib/rubocop/ast/node/when_node.rb +0 -53
  315. data/lib/rubocop/ast/node/while_node.rb +0 -35
  316. data/lib/rubocop/ast/node/yield_node.rb +0 -21
  317. data/lib/rubocop/ast/sexp.rb +0 -16
  318. data/lib/rubocop/ast/traversal.rb +0 -200
  319. data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
  320. data/lib/rubocop/formatter/disabled_lines_formatter.rb +0 -57
  321. data/lib/rubocop/node_pattern.rb +0 -887
  322. data/lib/rubocop/processed_source.rb +0 -216
  323. data/lib/rubocop/string_util.rb +0 -14
  324. data/lib/rubocop/token.rb +0 -114
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Lint
6
- # This cop checks for END blocks in method definitions.
7
- #
8
- # @example
9
- #
10
- # # bad
11
- #
12
- # def some_method
13
- # END { do_something }
14
- # end
15
- #
16
- # @example
17
- #
18
- # # good
19
- #
20
- # def some_method
21
- # at_exit { do_something }
22
- # end
23
- #
24
- # @example
25
- #
26
- # # good
27
- #
28
- # # outside defs
29
- # END { do_something }
30
- class EndInMethod < Cop
31
- MSG = '`END` found in method definition. Use `at_exit` instead.'
32
-
33
- def on_postexe(node)
34
- inside_of_method = node.each_ancestor(:def, :defs).count.nonzero?
35
- add_offense(node, location: :keyword) if inside_of_method
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Formatter
5
- # A basic formatter that displays the lines disabled
6
- # inline comments.
7
- class DisabledLinesFormatter < BaseFormatter
8
- include PathUtil
9
- include Colorizable
10
-
11
- attr_reader :cop_disabled_line_ranges
12
-
13
- def started(_target_files)
14
- @cop_disabled_line_ranges = {}
15
- end
16
-
17
- def file_started(file, options)
18
- return unless options[:cop_disabled_line_ranges]
19
-
20
- @cop_disabled_line_ranges[file] =
21
- options[:cop_disabled_line_ranges]
22
- end
23
-
24
- def finished(_inspected_files)
25
- cops_disabled_in_comments_summary
26
- end
27
-
28
- private
29
-
30
- def cops_disabled_in_comments_summary
31
- summary = "\nCops disabled line ranges:\n\n"
32
-
33
- @cop_disabled_line_ranges.each do |file, disabled_cops|
34
- disabled_cops.each do |cop, line_ranges|
35
- line_ranges.each do |line_range|
36
- file = cyan(smart_path(file))
37
- summary += "#{file}:#{line_range}: #{cop}\n"
38
- end
39
- end
40
- end
41
-
42
- output.puts summary
43
- end
44
-
45
- def smart_path(path)
46
- # Ideally, we calculate this relative to the project root.
47
- base_dir = Dir.pwd
48
-
49
- if path.start_with? base_dir
50
- relative_path(path, base_dir)
51
- else
52
- path
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,887 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'delegate'
4
- require 'erb'
5
-
6
- # rubocop:disable Metrics/ClassLength, Metrics/CyclomaticComplexity
7
- module RuboCop
8
- # This class performs a pattern-matching operation on an AST node.
9
- #
10
- # Initialize a new `NodePattern` with `NodePattern.new(pattern_string)`, then
11
- # pass an AST node to `NodePattern#match`. Alternatively, use one of the class
12
- # macros in `NodePattern::Macros` to define your own pattern-matching method.
13
- #
14
- # If the match fails, `nil` will be returned. If the match succeeds, the
15
- # return value depends on whether a block was provided to `#match`, and
16
- # whether the pattern contained any "captures" (values which are extracted
17
- # from a matching AST.)
18
- #
19
- # - With block: #match yields the captures (if any) and passes the return
20
- # value of the block through.
21
- # - With no block, but one capture: the capture is returned.
22
- # - With no block, but multiple captures: captures are returned as an array.
23
- # - With no block and no captures: #match returns `true`.
24
- #
25
- # ## Pattern string format examples
26
- #
27
- # ':sym' # matches a literal symbol
28
- # '1' # matches a literal integer
29
- # 'nil' # matches a literal nil
30
- # 'send' # matches (send ...)
31
- # '(send)' # matches (send)
32
- # '(send ...)' # matches (send ...)
33
- # '(op-asgn)' # node types with hyphenated names also work
34
- # '{send class}' # matches (send ...) or (class ...)
35
- # '({send class})' # matches (send) or (class)
36
- # '(send const)' # matches (send (const ...))
37
- # '(send _ :new)' # matches (send <anything> :new)
38
- # '(send $_ :new)' # as above, but whatever matches the $_ is captured
39
- # '(send $_ $_)' # you can use as many captures as you want
40
- # '(send !const ...)' # ! negates the next part of the pattern
41
- # '$(send const ...)' # arbitrary matching can be performed on a capture
42
- # '(send _recv _msg)' # wildcards can be named (for readability)
43
- # '(send ... :new)' # you can match against the last children
44
- # '(array <str sym>)' # you can match children in any order. This
45
- # # would match `['x', :y]` as well as `[:y, 'x']
46
- # '(_ <str sym ...>)' # will match if arguments have at least a `str` and
47
- # # a `sym` node, but can have more.
48
- # '(array <$str $_>)' # captures are in the order of the pattern,
49
- # # irrespective of the actual order of the children
50
- # '(array int*)' # will match an array of 0 or more integers
51
- # '(array int ?)' # will match 0 or 1 integer.
52
- # # Note: Space needed to distinguish from int?
53
- # '(array int+)' # will match an array of 1 or more integers
54
- # '(array (int $_)+)' # as above and will capture the numbers in an array
55
- # '(send $...)' # capture all the children as an array
56
- # '(send $... int)' # capture all children but the last as an array
57
- # '(send _x :+ _x)' # unification is performed on named wildcards
58
- # # (like Prolog variables...)
59
- # # (#== is used to see if values unify)
60
- # '(int odd?)' # words which end with a ? are predicate methods,
61
- # # are are called on the target to see if it matches
62
- # # any Ruby method which the matched object supports
63
- # # can be used
64
- # # if a truthy value is returned, the match succeeds
65
- # '(int [!1 !2])' # [] contains multiple patterns, ALL of which must
66
- # # match in that position
67
- # # in other words, while {} is pattern union (logical
68
- # # OR), [] is intersection (logical AND)
69
- # '(send %1 _)' # % stands for a parameter which must be supplied to
70
- # # #match at matching time
71
- # # it will be compared to the corresponding value in
72
- # # the AST using #==
73
- # # a bare '%' is the same as '%1'
74
- # # the number of extra parameters passed to #match
75
- # # must equal the highest % value in the pattern
76
- # # for consistency, %0 is the 'root node' which is
77
- # # passed as the 1st argument to #match, where the
78
- # # matching process starts
79
- # '^^send' # each ^ ascends one level in the AST
80
- # # so this matches against the grandparent node
81
- # '`send' # descends any number of level in the AST
82
- # # so this matches against any descendant node
83
- # '#method' # we call this a 'funcall'; it calls a method in the
84
- # # context where a pattern-matching method is defined
85
- # # if that returns a truthy value, the match succeeds
86
- # 'equal?(%1)' # predicates can be given 1 or more extra args
87
- # '#method(%0, 1)' # funcalls can also be given 1 or more extra args
88
- #
89
- # You can nest arbitrarily deep:
90
- #
91
- # # matches node parsed from 'Const = Class.new' or 'Const = Module.new':
92
- # '(casgn nil? :Const (send (const nil? {:Class :Module}) :new))'
93
- # # matches a node parsed from an 'if', with a '==' comparison,
94
- # # and no 'else' branch:
95
- # '(if (send _ :== _) _ nil?)'
96
- #
97
- # Note that patterns like 'send' are implemented by calling `#send_type?` on
98
- # the node being matched, 'const' by `#const_type?`, 'int' by `#int_type?`,
99
- # and so on. Therefore, if you add methods which are named like
100
- # `#prefix_type?` to the AST node class, then 'prefix' will become usable as
101
- # a pattern.
102
- #
103
- # Also note that if you need a "guard clause" to protect against possible nils
104
- # in a certain place in the AST, you can do it like this: `[!nil <pattern>]`
105
- #
106
- # The compiler code is very simple; don't be afraid to read through it!
107
- class NodePattern
108
- # @private
109
- Invalid = Class.new(StandardError)
110
-
111
- # @private
112
- # Builds Ruby code which implements a pattern
113
- class Compiler
114
- SYMBOL = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
115
- IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
116
- META = Regexp.union(
117
- %w"( ) { } [ ] $< < > $... $ ! ^ ` ... + * ?"
118
- ).freeze
119
- NUMBER = /-?\d+(?:\.\d+)?/.freeze
120
- STRING = /".+?"/.freeze
121
- METHOD_NAME = /\#?#{IDENTIFIER}[\!\?]?\(?/.freeze
122
- PARAM_NUMBER = /%\d*/.freeze
123
-
124
- SEPARATORS = /[\s]+/.freeze
125
- TOKENS = Regexp.union(META, PARAM_NUMBER, NUMBER,
126
- METHOD_NAME, SYMBOL, STRING)
127
-
128
- TOKEN = /\G(?:#{SEPARATORS}|#{TOKENS}|.)/.freeze
129
-
130
- NODE = /\A#{IDENTIFIER}\Z/.freeze
131
- PREDICATE = /\A#{IDENTIFIER}\?\(?\Z/.freeze
132
- WILDCARD = /\A_(?:#{IDENTIFIER})?\Z/.freeze
133
-
134
- FUNCALL = /\A\##{METHOD_NAME}/.freeze
135
- LITERAL = /\A(?:#{SYMBOL}|#{NUMBER}|#{STRING})\Z/.freeze
136
- PARAM = /\A#{PARAM_NUMBER}\Z/.freeze
137
- CLOSING = /\A(?:\)|\}|\])\Z/.freeze
138
-
139
- REST = '...'
140
- CAPTURED_REST = '$...'
141
-
142
- attr_reader :match_code, :tokens, :captures
143
-
144
- SEQ_HEAD_INDEX = -1
145
-
146
- # Placeholders while compiling, see with_..._context methods
147
- CUR_PLACEHOLDER = '@@@cur'
148
- CUR_NODE = "#{CUR_PLACEHOLDER} node@@@"
149
- CUR_ELEMENT = "#{CUR_PLACEHOLDER} element@@@"
150
- SEQ_HEAD_GUARD = '@@@seq guard head@@@'
151
-
152
- line = __LINE__
153
- ANY_ORDER_TEMPLATE = ERB.new <<~RUBY.gsub("-%>\n", '%>')
154
- <% if capture_rest %>(<%= capture_rest %> = []) && <% end -%>
155
- <% if capture_all %>(<%= capture_all %> = <% end -%>
156
- <%= CUR_NODE %>.children[<%= range %>]<% if capture_all %>)<% end -%>
157
- .each_with_object({}) { |<%= child %>, <%= matched %>|
158
- case
159
- <% patterns.each_with_index do |pattern, i| -%>
160
- when !<%= matched %>[<%= i %>] && <%=
161
- with_context(pattern, child, use_temp_node: false)
162
- %> then <%= matched %>[<%= i %>] = true
163
- <% end -%>
164
- <% if !rest %> else break({})
165
- <% elsif capture_rest %> else <%= capture_rest %> << <%= child %>
166
- <% end -%>
167
- end
168
- }.size == <%= patterns.size -%>
169
- RUBY
170
- ANY_ORDER_TEMPLATE.location = [__FILE__, line + 1]
171
-
172
- line = __LINE__
173
- REPEATED_TEMPLATE = ERB.new <<~RUBY.gsub("-%>\n", '%>')
174
- <% if captured %>(<%= accumulate %> = Array.new) && <% end %>
175
- <%= CUR_NODE %>.children[<%= range %>].all? do |<%= child %>|
176
- <%= with_context(expr, child, use_temp_node: false) %><% if captured %>&&
177
- <%= accumulate %>.push(<%= captured %>)<% end %>
178
- end <% if captured %>&&
179
- (<%= captured %> = if <%= accumulate %>.empty?
180
- <%= captured %>.map{[]} # Transpose hack won't work for empty case
181
- else
182
- <%= accumulate %>.transpose
183
- end) <% end -%>
184
- RUBY
185
- REPEATED_TEMPLATE.location = [__FILE__, line + 1]
186
-
187
- def initialize(str, node_var = 'node0')
188
- @string = str
189
- @root = node_var
190
-
191
- @temps = 0 # avoid name clashes between temp variables
192
- @captures = 0 # number of captures seen
193
- @unify = {} # named wildcard -> temp variable
194
- @params = 0 # highest % (param) number seen
195
- run(node_var)
196
- end
197
-
198
- def run(node_var)
199
- @tokens = Compiler.tokens(@string)
200
-
201
- @match_code = with_context(compile_expr, node_var, use_temp_node: false)
202
- @match_code.prepend("(captures = Array.new(#{@captures})) && ") \
203
- if @captures.positive?
204
-
205
- fail_due_to('unbalanced pattern') unless tokens.empty?
206
- end
207
-
208
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
209
- def compile_expr(token = tokens.shift)
210
- # read a single pattern-matching expression from the token stream,
211
- # return Ruby code which performs the corresponding matching operation
212
- #
213
- # the 'pattern-matching' expression may be a composite which
214
- # contains an arbitrary number of sub-expressions, but that composite
215
- # must all have precedence higher or equal to that of `&&`
216
- #
217
- # Expressions may use placeholders like:
218
- # CUR_NODE: Ruby code that evaluates to an AST node
219
- # CUR_ELEMENT: Either the node or the type if in first element of
220
- # a sequence (aka seq_head, e.g. "(seq_head first_node_arg ...")
221
- case token
222
- when '(' then compile_seq
223
- when '{' then compile_union
224
- when '[' then compile_intersect
225
- when '!' then compile_negation
226
- when '$' then compile_capture
227
- when '^' then compile_ascend
228
- when '`' then compile_descend
229
- when WILDCARD then compile_wildcard(token[1..-1])
230
- when FUNCALL then compile_funcall(token)
231
- when LITERAL then compile_literal(token)
232
- when PREDICATE then compile_predicate(token)
233
- when NODE then compile_nodetype(token)
234
- when PARAM then compile_param(token[1..-1])
235
- when CLOSING then fail_due_to("#{token} in invalid position")
236
- when nil then fail_due_to('pattern ended prematurely')
237
- else fail_due_to("invalid token #{token.inspect}")
238
- end
239
- end
240
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
241
-
242
- def tokens_until(stop, what)
243
- return to_enum __method__, stop, what unless block_given?
244
-
245
- fail_due_to("empty #{what}") if tokens.first == stop && what
246
- yield until tokens.first == stop
247
- tokens.shift
248
- end
249
-
250
- def compile_seq
251
- terms = tokens_until(')', 'sequence').map { variadic_seq_term }
252
- Sequence.new(self, *terms).compile
253
- end
254
-
255
- def compile_guard_clause
256
- "#{CUR_NODE}.is_a?(RuboCop::AST::Node)"
257
- end
258
-
259
- def variadic_seq_term
260
- token = tokens.shift
261
- case token
262
- when CAPTURED_REST then compile_captured_ellipsis
263
- when REST then compile_ellipsis
264
- when '$<' then compile_any_order(next_capture)
265
- when '<' then compile_any_order
266
- else compile_repeated_expr(token)
267
- end
268
- end
269
-
270
- def compile_repeated_expr(token)
271
- before = @captures
272
- expr = compile_expr(token)
273
- min, max = parse_repetition_token
274
- return [1, expr] if min.nil?
275
-
276
- if @captures != before
277
- captured = "captures[#{before}...#{@captures}]"
278
- accumulate = next_temp_variable(:accumulate)
279
- end
280
- arity = min..max || Float::INFINITY
281
-
282
- [arity, repeated_generator(expr, captured, accumulate)]
283
- end
284
-
285
- def repeated_generator(expr, captured, accumulate)
286
- with_temp_variables do |child|
287
- lambda do |range|
288
- if range.begin == SEQ_HEAD_INDEX
289
- fail_due_to 'repeated pattern at beginning of sequence'
290
- end
291
- REPEATED_TEMPLATE.result(binding)
292
- end
293
- end
294
- end
295
-
296
- def parse_repetition_token
297
- case tokens.first
298
- when '*' then min = 0
299
- when '+' then min = 1
300
- when '?' then min = 0
301
- max = 1
302
- else return
303
- end
304
- tokens.shift
305
- [min, max]
306
- end
307
-
308
- # @private
309
- # Builds Ruby code for a sequence
310
- # (head *first_terms variadic_term *last_terms)
311
- class Sequence < SimpleDelegator
312
- def initialize(compiler, *arity_term_list)
313
- @arities, @terms = arity_term_list.transpose
314
-
315
- super(compiler)
316
- @variadic_index = @arities.find_index { |a| a.is_a?(Range) }
317
- fail_due_to 'multiple variable patterns in same sequence' \
318
- if @variadic_index && !@arities.one? { |a| a.is_a?(Range) }
319
- end
320
-
321
- def compile
322
- [
323
- compile_guard_clause,
324
- compile_child_nb_guard,
325
- compile_seq_head,
326
- *compile_first_terms,
327
- compile_variadic_term,
328
- *compile_last_terms
329
- ].compact.join(" &&\n") << SEQ_HEAD_GUARD
330
- end
331
-
332
- private
333
-
334
- def first_terms_arity
335
- first_terms_range { |r| @arities[r].inject(0, :+) } || 0
336
- end
337
-
338
- def last_terms_arity
339
- last_terms_range { |r| @arities[r].inject(0, :+) } || 0
340
- end
341
-
342
- def variadic_term_min_arity
343
- @variadic_index ? @arities[@variadic_index].begin : 0
344
- end
345
-
346
- def first_terms_range
347
- yield 1..(@variadic_index || @terms.size) - 1 if seq_head?
348
- end
349
-
350
- def last_terms_range
351
- yield @variadic_index + 1...@terms.size if @variadic_index
352
- end
353
-
354
- def seq_head?
355
- @variadic_index != 0
356
- end
357
-
358
- def compile_child_nb_guard
359
- fixed = first_terms_arity + last_terms_arity
360
- min = fixed + variadic_term_min_arity
361
- op = if @variadic_index
362
- max_variadic = @arities[@variadic_index].end
363
- if max_variadic != Float::INFINITY
364
- range = min..fixed + max_variadic
365
- return "(#{range}).cover?(#{CUR_NODE}.children.size)"
366
- end
367
- '>='
368
- else
369
- '=='
370
- end
371
- "#{CUR_NODE}.children.size #{op} #{min}"
372
- end
373
-
374
- def term(index, range)
375
- t = @terms[index]
376
- if t.respond_to? :call
377
- t.call(range)
378
- else
379
- with_child_context(t, range.begin)
380
- end
381
- end
382
-
383
- def compile_seq_head
384
- return unless seq_head?
385
-
386
- fail_due_to 'sequences cannot start with <' \
387
- if @terms[0].respond_to? :call
388
-
389
- with_seq_head_context(@terms[0])
390
- end
391
-
392
- def compile_first_terms
393
- first_terms_range { |range| compile_terms(range, 0) }
394
- end
395
-
396
- def compile_last_terms
397
- last_terms_range { |r| compile_terms(r, -last_terms_arity) }
398
- end
399
-
400
- def compile_terms(index_range, start)
401
- index_range.map do |i|
402
- current = start
403
- start += @arities.fetch(i)
404
- term(i, current..start - 1)
405
- end
406
- end
407
-
408
- def compile_variadic_term
409
- variadic_arity { |arity| term(@variadic_index, arity) }
410
- end
411
-
412
- def variadic_arity
413
- return unless @variadic_index
414
-
415
- first = @variadic_index.positive? ? first_terms_arity : SEQ_HEAD_INDEX
416
- yield first..-last_terms_arity - 1
417
- end
418
- end
419
- private_constant :Sequence
420
-
421
- def compile_captured_ellipsis
422
- capture = next_capture
423
- block = lambda { |range|
424
- # Consider ($...) like (_ $...):
425
- range = 0..range.end if range.begin == SEQ_HEAD_INDEX
426
- "(#{capture} = #{CUR_NODE}.children[#{range}])"
427
- }
428
- [0..Float::INFINITY, block]
429
- end
430
-
431
- def compile_ellipsis
432
- [0..Float::INFINITY, 'true']
433
- end
434
-
435
- # rubocop:disable Metrics/AbcSize
436
- # rubocop:disable Metrics/MethodLength
437
- def compile_any_order(capture_all = nil)
438
- rest = capture_rest = nil
439
- patterns = []
440
- with_temp_variables do |child, matched|
441
- tokens_until('>', 'any child') do
442
- fail_due_to 'ellipsis must be at the end of <>' if rest
443
- token = tokens.shift
444
- case token
445
- when CAPTURED_REST then rest = capture_rest = next_capture
446
- when REST then rest = true
447
- else patterns << compile_expr(token)
448
- end
449
- end
450
- [rest ? patterns.size..Float::INFINITY : patterns.size,
451
- ->(range) { ANY_ORDER_TEMPLATE.result(binding) }]
452
- end
453
- end
454
- # rubocop:enable Metrics/MethodLength
455
- # rubocop:enable Metrics/AbcSize
456
-
457
- def insure_same_captures(enum, what)
458
- return to_enum __method__, enum, what unless block_given?
459
-
460
- captures_before = captures_after = nil
461
- enum.each do
462
- captures_before ||= @captures
463
- @captures = captures_before
464
- yield
465
- captures_after ||= @captures
466
- if captures_after != @captures
467
- fail_due_to("each #{what} must have same # of captures")
468
- end
469
- end
470
- end
471
-
472
- def access_unify(name)
473
- var = @unify[name]
474
-
475
- if var == :forbidden_unification
476
- fail_due_to "Wildcard #{name} was first seen in a subset of a" \
477
- " union and can't be used outside that union"
478
- end
479
- var
480
- end
481
-
482
- def forbid_unification(*names)
483
- names.each do |name|
484
- @unify[name] = :forbidden_unification
485
- end
486
- end
487
-
488
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
489
- def unify_in_union(enum)
490
- # We need to reset @unify before each branch is processed.
491
- # Moreover we need to keep track of newly encountered wildcards.
492
- # Var `new_unify_intersection` will hold those that are encountered
493
- # in all branches; these are not a problem.
494
- # Var `partial_unify` will hold those encountered in only a subset
495
- # of the branches; these can't be used outside of the union.
496
-
497
- return to_enum __method__, enum unless block_given?
498
-
499
- new_unify_intersection = nil
500
- partial_unify = []
501
- unify_before = @unify.dup
502
-
503
- result = enum.each do |e|
504
- @unify = unify_before.dup if new_unify_intersection
505
- yield e
506
- new_unify = @unify.keys - unify_before.keys
507
- if new_unify_intersection.nil?
508
- # First iteration
509
- new_unify_intersection = new_unify
510
- else
511
- union = new_unify_intersection | new_unify
512
- new_unify_intersection &= new_unify
513
- partial_unify |= union - new_unify_intersection
514
- end
515
- end
516
-
517
- # At this point, all members of `new_unify_intersection` can be used
518
- # for unification outside of the union, but partial_unify may not
519
-
520
- forbid_unification(*partial_unify)
521
-
522
- result
523
- end
524
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
525
-
526
- def compile_union
527
- # we need to ensure that each branch of the {} contains the same
528
- # number of captures (since only one branch of the {} can actually
529
- # match, the same variables are used to hold the captures for each
530
- # branch)
531
- enum = tokens_until('}', 'union')
532
- enum = unify_in_union(enum)
533
- terms = insure_same_captures(enum, 'branch of {}')
534
- .map { compile_expr }
535
-
536
- "(#{terms.join(' || ')})"
537
- end
538
-
539
- def compile_intersect
540
- tokens_until(']', 'intersection')
541
- .map { compile_expr }
542
- .join(' && ')
543
- end
544
-
545
- def compile_capture
546
- "(#{next_capture} = #{CUR_ELEMENT}; #{compile_expr})"
547
- end
548
-
549
- def compile_negation
550
- "!(#{compile_expr})"
551
- end
552
-
553
- def compile_ascend
554
- with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
555
- end
556
-
557
- def compile_descend
558
- with_temp_variables do |descendant|
559
- pattern = with_context(compile_expr, descendant,
560
- use_temp_node: false)
561
- [
562
- "RuboCop::NodePattern.descend(#{CUR_ELEMENT}).",
563
- "any? do |#{descendant}|",
564
- " #{pattern}",
565
- 'end'
566
- ].join("\n")
567
- end
568
- end
569
-
570
- def compile_wildcard(name)
571
- if name.empty?
572
- 'true'
573
- elsif @unify.key?(name)
574
- # we have already seen a wildcard with this name before
575
- # so the value it matched the first time will already be stored
576
- # in a temp. check if this value matches the one stored in the temp
577
- "#{CUR_ELEMENT} == #{access_unify(name)}"
578
- else
579
- n = @unify[name] = "unify_#{name.gsub('-', '__')}"
580
- # double assign to avoid "assigned but unused variable"
581
- "(#{n} = #{CUR_ELEMENT}; " \
582
- "#{n} = #{n}; true)"
583
- end
584
- end
585
-
586
- def compile_literal(literal)
587
- "#{CUR_ELEMENT} == #{literal}"
588
- end
589
-
590
- def compile_predicate(predicate)
591
- if predicate.end_with?('(') # is there an arglist?
592
- args = compile_args(tokens)
593
- predicate = predicate[0..-2] # drop the trailing (
594
- "#{CUR_ELEMENT}.#{predicate}(#{args.join(',')})"
595
- else
596
- "#{CUR_ELEMENT}.#{predicate}"
597
- end
598
- end
599
-
600
- def compile_funcall(method)
601
- # call a method in the context which this pattern-matching
602
- # code is used in. pass target value as an argument
603
- method = method[1..-1] # drop the leading #
604
- if method.end_with?('(') # is there an arglist?
605
- args = compile_args(tokens)
606
- method = method[0..-2] # drop the trailing (
607
- "#{method}(#{CUR_ELEMENT},#{args.join(',')})"
608
- else
609
- "#{method}(#{CUR_ELEMENT})"
610
- end
611
- end
612
-
613
- def compile_nodetype(type)
614
- "#{compile_guard_clause} && #{CUR_NODE}.#{type.tr('-', '_')}_type?"
615
- end
616
-
617
- def compile_param(number)
618
- "#{CUR_ELEMENT} == #{get_param(number)}"
619
- end
620
-
621
- def compile_args(tokens)
622
- index = tokens.find_index { |token| token == ')' }
623
-
624
- tokens.slice!(0..index).each_with_object([]) do |token, args|
625
- next if [')', ','].include?(token)
626
-
627
- args << compile_arg(token)
628
- end
629
- end
630
-
631
- def compile_arg(token)
632
- case token
633
- when WILDCARD then
634
- name = token[1..-1]
635
- access_unify(name) || fail_due_to('invalid in arglist: ' + token)
636
- when LITERAL then token
637
- when PARAM then get_param(token[1..-1])
638
- when CLOSING then fail_due_to("#{token} in invalid position")
639
- when nil then fail_due_to('pattern ended prematurely')
640
- else fail_due_to("invalid token in arglist: #{token.inspect}")
641
- end
642
- end
643
-
644
- def next_capture
645
- index = @captures
646
- @captures += 1
647
- "captures[#{index}]"
648
- end
649
-
650
- def get_param(number)
651
- number = number.empty? ? 1 : Integer(number)
652
- @params = number if number > @params
653
- number.zero? ? @root : "param#{number}"
654
- end
655
-
656
- def emit_yield_capture(when_no_capture = '')
657
- yield_val = if @captures.zero?
658
- when_no_capture
659
- elsif @captures == 1
660
- 'captures[0]' # Circumvent https://github.com/jruby/jruby/issues/5710
661
- else
662
- '*captures'
663
- end
664
- "yield(#{yield_val})"
665
- end
666
-
667
- def emit_retval
668
- if @captures.zero?
669
- 'true'
670
- elsif @captures == 1
671
- 'captures[0]'
672
- else
673
- 'captures'
674
- end
675
- end
676
-
677
- def emit_param_list
678
- (1..@params).map { |n| "param#{n}" }.join(',')
679
- end
680
-
681
- def emit_trailing_params
682
- params = emit_param_list
683
- params.empty? ? '' : ",#{params}"
684
- end
685
-
686
- def emit_method_code
687
- <<~RUBY
688
- return unless #{@match_code}
689
- block_given? ? #{emit_yield_capture} : (return #{emit_retval})
690
- RUBY
691
- end
692
-
693
- def fail_due_to(message)
694
- raise Invalid, "Couldn't compile due to #{message}. Pattern: #{@string}"
695
- end
696
-
697
- def with_temp_node(cur_node)
698
- with_temp_variables do |node|
699
- yield "(#{node} = #{cur_node})", node
700
- end
701
- .gsub("\n", "\n ") # Nicer indent for debugging
702
- end
703
-
704
- def with_temp_variables(&block)
705
- names = block.parameters.map { |_, name| next_temp_variable(name) }
706
- yield(*names)
707
- end
708
-
709
- def next_temp_variable(name)
710
- "#{name}#{next_temp_value}"
711
- end
712
-
713
- def next_temp_value
714
- @temps += 1
715
- end
716
-
717
- def auto_use_temp_node?(code)
718
- code.scan(CUR_PLACEHOLDER).count > 1
719
- end
720
-
721
- # with_<...>_context methods are used whenever the context,
722
- # i.e the current node or the current element can be determined.
723
-
724
- def with_child_context(code, child_index)
725
- with_context(code, "#{CUR_NODE}.children[#{child_index}]")
726
- end
727
-
728
- def with_context(code, cur_node,
729
- use_temp_node: auto_use_temp_node?(code))
730
- if use_temp_node
731
- with_temp_node(cur_node) do |init, temp_var|
732
- substitute_cur_node(code, temp_var, first_cur_node: init)
733
- end
734
- else
735
- substitute_cur_node(code, cur_node)
736
- end
737
- end
738
-
739
- def with_seq_head_context(code)
740
- if code.include?(SEQ_HEAD_GUARD)
741
- fail_due_to('parentheses at sequence head')
742
- end
743
-
744
- code.gsub CUR_ELEMENT, "#{CUR_NODE}.type"
745
- end
746
-
747
- def substitute_cur_node(code, cur_node, first_cur_node: cur_node)
748
- iter = 0
749
- code
750
- .gsub(CUR_ELEMENT, CUR_NODE)
751
- .gsub(CUR_NODE) do
752
- iter += 1
753
- iter == 1 ? first_cur_node : cur_node
754
- end
755
- .gsub(SEQ_HEAD_GUARD, '')
756
- end
757
-
758
- def self.tokens(pattern)
759
- pattern.scan(TOKEN).reject { |token| token =~ /\A#{SEPARATORS}\Z/ }
760
- end
761
- end
762
- private_constant :Compiler
763
-
764
- # Helpers for defining methods based on a pattern string
765
- module Macros
766
- # Define a method which applies a pattern to an AST node
767
- #
768
- # The new method will return nil if the node does not match
769
- # If the node matches, and a block is provided, the new method will
770
- # yield to the block (passing any captures as block arguments).
771
- # If the node matches, and no block is provided, the new method will
772
- # return the captures, or `true` if there were none.
773
- def def_node_matcher(method_name, pattern_str)
774
- compiler = Compiler.new(pattern_str, 'node')
775
- src = "def #{method_name}(node = self" \
776
- "#{compiler.emit_trailing_params});" \
777
- "#{compiler.emit_method_code};end"
778
-
779
- location = caller_locations(1, 1).first
780
- class_eval(src, location.path, location.lineno)
781
- end
782
-
783
- # Define a method which recurses over the descendants of an AST node,
784
- # checking whether any of them match the provided pattern
785
- #
786
- # If the method name ends with '?', the new method will return `true`
787
- # as soon as it finds a descendant which matches. Otherwise, it will
788
- # yield all descendants which match.
789
- def def_node_search(method_name, pattern_str)
790
- compiler = Compiler.new(pattern_str, 'node')
791
- called_from = caller(1..1).first.split(':')
792
-
793
- if method_name.to_s.end_with?('?')
794
- node_search_first(method_name, compiler, called_from)
795
- else
796
- node_search_all(method_name, compiler, called_from)
797
- end
798
- end
799
-
800
- def node_search_first(method_name, compiler, called_from)
801
- node_search(method_name, compiler, 'return true', '', called_from)
802
- end
803
-
804
- def node_search_all(method_name, compiler, called_from)
805
- yield_code = compiler.emit_yield_capture('node')
806
- prelude = "return enum_for(:#{method_name}, node0" \
807
- "#{compiler.emit_trailing_params}) unless block_given?"
808
-
809
- node_search(method_name, compiler, yield_code, prelude, called_from)
810
- end
811
-
812
- def node_search(method_name, compiler, on_match, prelude, called_from)
813
- src = node_search_body(method_name, compiler.emit_trailing_params,
814
- prelude, compiler.match_code, on_match)
815
- filename, lineno = *called_from
816
- class_eval(src, filename, lineno.to_i)
817
- end
818
-
819
- def node_search_body(method_name, trailing_params, prelude, match_code,
820
- on_match)
821
- <<~RUBY
822
- def #{method_name}(node0#{trailing_params})
823
- #{prelude}
824
- node0.each_node do |node|
825
- if #{match_code}
826
- #{on_match}
827
- end
828
- end
829
- nil
830
- end
831
- RUBY
832
- end
833
- end
834
-
835
- attr_reader :pattern
836
-
837
- def initialize(str)
838
- @pattern = str
839
- compiler = Compiler.new(str)
840
- src = "def match(node0#{compiler.emit_trailing_params});" \
841
- "#{compiler.emit_method_code}end"
842
- instance_eval(src, __FILE__, __LINE__ + 1)
843
- end
844
-
845
- def match(*args)
846
- # If we're here, it's because the singleton method has not been defined,
847
- # either because we've been dup'ed or serialized through YAML
848
- initialize(pattern)
849
- match(*args)
850
- end
851
-
852
- def marshal_load(pattern)
853
- initialize pattern
854
- end
855
-
856
- def marshal_dump
857
- pattern
858
- end
859
-
860
- def ==(other)
861
- other.is_a?(NodePattern) &&
862
- Compiler.tokens(other.pattern) == Compiler.tokens(pattern)
863
- end
864
- alias eql? ==
865
-
866
- def to_s
867
- "#<#{self.class} #{pattern}>"
868
- end
869
-
870
- # Yields its argument and any descendants, depth-first.
871
- #
872
- def self.descend(element, &block)
873
- return to_enum(__method__, element) unless block_given?
874
-
875
- yield element
876
-
877
- if element.is_a?(::RuboCop::AST::Node)
878
- element.children.each do |child|
879
- descend(child, &block)
880
- end
881
- end
882
-
883
- nil
884
- end
885
- end
886
- end
887
- # rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity