rubbycop 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (499) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +211 -0
  4. data/assets/logo.png +0 -0
  5. data/assets/output.html.erb +261 -0
  6. data/bin/rubbycop +17 -0
  7. data/config/default.yml +1548 -0
  8. data/config/disabled.yml +119 -0
  9. data/config/enabled.yml +1734 -0
  10. data/lib/rubbycop.rb +510 -0
  11. data/lib/rubbycop/ast/builder.rb +64 -0
  12. data/lib/rubbycop/ast/node.rb +610 -0
  13. data/lib/rubbycop/ast/node/and_node.rb +37 -0
  14. data/lib/rubbycop/ast/node/array_node.rb +48 -0
  15. data/lib/rubbycop/ast/node/case_node.rb +64 -0
  16. data/lib/rubbycop/ast/node/ensure_node.rb +25 -0
  17. data/lib/rubbycop/ast/node/for_node.rb +53 -0
  18. data/lib/rubbycop/ast/node/hash_node.rb +109 -0
  19. data/lib/rubbycop/ast/node/if_node.rb +138 -0
  20. data/lib/rubbycop/ast/node/keyword_splat_node.rb +45 -0
  21. data/lib/rubbycop/ast/node/mixin/binary_operator_node.rb +23 -0
  22. data/lib/rubbycop/ast/node/mixin/conditional_node.rb +45 -0
  23. data/lib/rubbycop/ast/node/mixin/hash_element_node.rb +125 -0
  24. data/lib/rubbycop/ast/node/mixin/modifier_node.rb +17 -0
  25. data/lib/rubbycop/ast/node/mixin/predicate_operator_node.rb +35 -0
  26. data/lib/rubbycop/ast/node/or_node.rb +37 -0
  27. data/lib/rubbycop/ast/node/pair_node.rb +64 -0
  28. data/lib/rubbycop/ast/node/resbody_node.rb +25 -0
  29. data/lib/rubbycop/ast/node/send_node.rb +209 -0
  30. data/lib/rubbycop/ast/node/until_node.rb +43 -0
  31. data/lib/rubbycop/ast/node/when_node.rb +61 -0
  32. data/lib/rubbycop/ast/node/while_node.rb +43 -0
  33. data/lib/rubbycop/ast/sexp.rb +16 -0
  34. data/lib/rubbycop/ast/traversal.rb +171 -0
  35. data/lib/rubbycop/cached_data.rb +63 -0
  36. data/lib/rubbycop/cli.rb +199 -0
  37. data/lib/rubbycop/comment_config.rb +155 -0
  38. data/lib/rubbycop/config.rb +444 -0
  39. data/lib/rubbycop/config_loader.rb +244 -0
  40. data/lib/rubbycop/config_loader_resolver.rb +43 -0
  41. data/lib/rubbycop/config_store.rb +48 -0
  42. data/lib/rubbycop/cop/autocorrect_logic.rb +26 -0
  43. data/lib/rubbycop/cop/badge.rb +73 -0
  44. data/lib/rubbycop/cop/bundler/duplicated_gem.rb +69 -0
  45. data/lib/rubbycop/cop/bundler/ordered_gems.rb +113 -0
  46. data/lib/rubbycop/cop/commissioner.rb +118 -0
  47. data/lib/rubbycop/cop/cop.rb +222 -0
  48. data/lib/rubbycop/cop/corrector.rb +135 -0
  49. data/lib/rubbycop/cop/force.rb +41 -0
  50. data/lib/rubbycop/cop/ignored_node.rb +38 -0
  51. data/lib/rubbycop/cop/layout/access_modifier_indentation.rb +109 -0
  52. data/lib/rubbycop/cop/layout/align_array.rb +35 -0
  53. data/lib/rubbycop/cop/layout/align_hash.rb +235 -0
  54. data/lib/rubbycop/cop/layout/align_parameters.rb +97 -0
  55. data/lib/rubbycop/cop/layout/block_end_newline.rb +56 -0
  56. data/lib/rubbycop/cop/layout/case_indentation.rb +163 -0
  57. data/lib/rubbycop/cop/layout/closing_parenthesis_indentation.rb +88 -0
  58. data/lib/rubbycop/cop/layout/comment_indentation.rb +71 -0
  59. data/lib/rubbycop/cop/layout/dot_position.rb +84 -0
  60. data/lib/rubbycop/cop/layout/else_alignment.rb +105 -0
  61. data/lib/rubbycop/cop/layout/empty_line_after_magic_comment.rb +63 -0
  62. data/lib/rubbycop/cop/layout/empty_line_between_defs.rb +143 -0
  63. data/lib/rubbycop/cop/layout/empty_lines.rb +60 -0
  64. data/lib/rubbycop/cop/layout/empty_lines_around_access_modifier.rb +90 -0
  65. data/lib/rubbycop/cop/layout/empty_lines_around_begin_body.rb +42 -0
  66. data/lib/rubbycop/cop/layout/empty_lines_around_block_body.rb +41 -0
  67. data/lib/rubbycop/cop/layout/empty_lines_around_class_body.rb +39 -0
  68. data/lib/rubbycop/cop/layout/empty_lines_around_exception_handling_keywords.rb +127 -0
  69. data/lib/rubbycop/cop/layout/empty_lines_around_method_body.rb +41 -0
  70. data/lib/rubbycop/cop/layout/empty_lines_around_module_body.rb +44 -0
  71. data/lib/rubbycop/cop/layout/end_of_line.rb +52 -0
  72. data/lib/rubbycop/cop/layout/extra_spacing.rb +237 -0
  73. data/lib/rubbycop/cop/layout/first_array_element_line_break.rb +41 -0
  74. data/lib/rubbycop/cop/layout/first_hash_element_line_break.rb +33 -0
  75. data/lib/rubbycop/cop/layout/first_method_argument_line_break.rb +49 -0
  76. data/lib/rubbycop/cop/layout/first_method_parameter_line_break.rb +42 -0
  77. data/lib/rubbycop/cop/layout/first_parameter_indentation.rb +109 -0
  78. data/lib/rubbycop/cop/layout/indent_array.rb +114 -0
  79. data/lib/rubbycop/cop/layout/indent_assignment.rb +42 -0
  80. data/lib/rubbycop/cop/layout/indent_hash.rb +134 -0
  81. data/lib/rubbycop/cop/layout/indent_heredoc.rb +173 -0
  82. data/lib/rubbycop/cop/layout/indentation_consistency.rb +51 -0
  83. data/lib/rubbycop/cop/layout/indentation_width.rb +303 -0
  84. data/lib/rubbycop/cop/layout/initial_indentation.rb +42 -0
  85. data/lib/rubbycop/cop/layout/leading_comment_space.rb +43 -0
  86. data/lib/rubbycop/cop/layout/multiline_array_brace_layout.rb +81 -0
  87. data/lib/rubbycop/cop/layout/multiline_assignment_layout.rb +88 -0
  88. data/lib/rubbycop/cop/layout/multiline_block_layout.rb +134 -0
  89. data/lib/rubbycop/cop/layout/multiline_hash_brace_layout.rb +81 -0
  90. data/lib/rubbycop/cop/layout/multiline_method_call_brace_layout.rb +97 -0
  91. data/lib/rubbycop/cop/layout/multiline_method_call_indentation.rb +215 -0
  92. data/lib/rubbycop/cop/layout/multiline_method_definition_brace_layout.rb +82 -0
  93. data/lib/rubbycop/cop/layout/multiline_operation_indentation.rb +89 -0
  94. data/lib/rubbycop/cop/layout/rescue_ensure_alignment.rb +86 -0
  95. data/lib/rubbycop/cop/layout/space_after_colon.rb +40 -0
  96. data/lib/rubbycop/cop/layout/space_after_comma.rb +21 -0
  97. data/lib/rubbycop/cop/layout/space_after_method_name.rb +37 -0
  98. data/lib/rubbycop/cop/layout/space_after_not.rb +38 -0
  99. data/lib/rubbycop/cop/layout/space_after_semicolon.rb +21 -0
  100. data/lib/rubbycop/cop/layout/space_around_block_parameters.rb +109 -0
  101. data/lib/rubbycop/cop/layout/space_around_equals_in_parameter_default.rb +68 -0
  102. data/lib/rubbycop/cop/layout/space_around_keyword.rb +224 -0
  103. data/lib/rubbycop/cop/layout/space_around_operators.rb +142 -0
  104. data/lib/rubbycop/cop/layout/space_before_block_braces.rb +54 -0
  105. data/lib/rubbycop/cop/layout/space_before_comma.rb +16 -0
  106. data/lib/rubbycop/cop/layout/space_before_comment.rb +27 -0
  107. data/lib/rubbycop/cop/layout/space_before_first_arg.rb +64 -0
  108. data/lib/rubbycop/cop/layout/space_before_semicolon.rb +16 -0
  109. data/lib/rubbycop/cop/layout/space_in_lambda_literal.rb +87 -0
  110. data/lib/rubbycop/cop/layout/space_inside_array_percent_literal.rb +53 -0
  111. data/lib/rubbycop/cop/layout/space_inside_block_braces.rb +158 -0
  112. data/lib/rubbycop/cop/layout/space_inside_brackets.rb +20 -0
  113. data/lib/rubbycop/cop/layout/space_inside_hash_literal_braces.rb +150 -0
  114. data/lib/rubbycop/cop/layout/space_inside_parens.rb +16 -0
  115. data/lib/rubbycop/cop/layout/space_inside_percent_literal_delimiters.rb +64 -0
  116. data/lib/rubbycop/cop/layout/space_inside_range_literal.rb +63 -0
  117. data/lib/rubbycop/cop/layout/space_inside_string_interpolation.rb +65 -0
  118. data/lib/rubbycop/cop/layout/tab.rb +57 -0
  119. data/lib/rubbycop/cop/layout/trailing_blank_lines.rb +78 -0
  120. data/lib/rubbycop/cop/layout/trailing_whitespace.rb +28 -0
  121. data/lib/rubbycop/cop/lint/ambiguous_block_association.rb +66 -0
  122. data/lib/rubbycop/cop/lint/ambiguous_operator.rb +55 -0
  123. data/lib/rubbycop/cop/lint/ambiguous_regexp_literal.rb +43 -0
  124. data/lib/rubbycop/cop/lint/assignment_in_condition.rb +80 -0
  125. data/lib/rubbycop/cop/lint/block_alignment.rb +229 -0
  126. data/lib/rubbycop/cop/lint/circular_argument_reference.rb +83 -0
  127. data/lib/rubbycop/cop/lint/condition_position.rb +52 -0
  128. data/lib/rubbycop/cop/lint/debugger.rb +72 -0
  129. data/lib/rubbycop/cop/lint/def_end_alignment.rb +78 -0
  130. data/lib/rubbycop/cop/lint/deprecated_class_methods.rb +90 -0
  131. data/lib/rubbycop/cop/lint/duplicate_case_condition.rb +53 -0
  132. data/lib/rubbycop/cop/lint/duplicate_methods.rb +151 -0
  133. data/lib/rubbycop/cop/lint/duplicated_key.rb +38 -0
  134. data/lib/rubbycop/cop/lint/each_with_object_argument.rb +39 -0
  135. data/lib/rubbycop/cop/lint/else_layout.rb +65 -0
  136. data/lib/rubbycop/cop/lint/empty_ensure.rb +60 -0
  137. data/lib/rubbycop/cop/lint/empty_expression.rb +42 -0
  138. data/lib/rubbycop/cop/lint/empty_interpolation.rb +36 -0
  139. data/lib/rubbycop/cop/lint/empty_when.rb +38 -0
  140. data/lib/rubbycop/cop/lint/end_alignment.rb +157 -0
  141. data/lib/rubbycop/cop/lint/end_in_method.rb +40 -0
  142. data/lib/rubbycop/cop/lint/ensure_return.rb +43 -0
  143. data/lib/rubbycop/cop/lint/float_out_of_range.rb +35 -0
  144. data/lib/rubbycop/cop/lint/format_parameter_mismatch.rb +182 -0
  145. data/lib/rubbycop/cop/lint/handle_exceptions.rb +56 -0
  146. data/lib/rubbycop/cop/lint/implicit_string_concatenation.rb +95 -0
  147. data/lib/rubbycop/cop/lint/ineffective_access_modifier.rb +143 -0
  148. data/lib/rubbycop/cop/lint/inherit_exception.rb +83 -0
  149. data/lib/rubbycop/cop/lint/invalid_character_literal.rb +41 -0
  150. data/lib/rubbycop/cop/lint/literal_in_condition.rb +127 -0
  151. data/lib/rubbycop/cop/lint/literal_in_interpolation.rb +76 -0
  152. data/lib/rubbycop/cop/lint/loop.rb +63 -0
  153. data/lib/rubbycop/cop/lint/multiple_compare.rb +48 -0
  154. data/lib/rubbycop/cop/lint/nested_method_definition.rb +105 -0
  155. data/lib/rubbycop/cop/lint/next_without_accumulator.rb +50 -0
  156. data/lib/rubbycop/cop/lint/non_local_exit_from_iterator.rb +85 -0
  157. data/lib/rubbycop/cop/lint/parentheses_as_grouped_expression.rb +60 -0
  158. data/lib/rubbycop/cop/lint/percent_string_array.rb +84 -0
  159. data/lib/rubbycop/cop/lint/percent_symbol_array.rb +66 -0
  160. data/lib/rubbycop/cop/lint/rand_one.rb +39 -0
  161. data/lib/rubbycop/cop/lint/require_parentheses.rb +61 -0
  162. data/lib/rubbycop/cop/lint/rescue_exception.rb +45 -0
  163. data/lib/rubbycop/cop/lint/safe_navigation_chain.rb +70 -0
  164. data/lib/rubbycop/cop/lint/shadowed_exception.rb +132 -0
  165. data/lib/rubbycop/cop/lint/shadowing_outer_local_variable.rb +53 -0
  166. data/lib/rubbycop/cop/lint/string_conversion_in_interpolation.rb +58 -0
  167. data/lib/rubbycop/cop/lint/syntax.rb +55 -0
  168. data/lib/rubbycop/cop/lint/underscore_prefixed_variable_name.rb +62 -0
  169. data/lib/rubbycop/cop/lint/unified_integer.rb +42 -0
  170. data/lib/rubbycop/cop/lint/unneeded_disable.rb +231 -0
  171. data/lib/rubbycop/cop/lint/unneeded_splat_expansion.rb +141 -0
  172. data/lib/rubbycop/cop/lint/unreachable_code.rb +52 -0
  173. data/lib/rubbycop/cop/lint/unused_block_argument.rb +145 -0
  174. data/lib/rubbycop/cop/lint/unused_method_argument.rb +61 -0
  175. data/lib/rubbycop/cop/lint/useless_access_modifier.rb +229 -0
  176. data/lib/rubbycop/cop/lint/useless_assignment.rb +132 -0
  177. data/lib/rubbycop/cop/lint/useless_comparison.rb +28 -0
  178. data/lib/rubbycop/cop/lint/useless_else_without_rescue.rb +46 -0
  179. data/lib/rubbycop/cop/lint/useless_setter_call.rb +162 -0
  180. data/lib/rubbycop/cop/lint/void.rb +108 -0
  181. data/lib/rubbycop/cop/message_annotator.rb +116 -0
  182. data/lib/rubbycop/cop/metrics/abc_size.rb +39 -0
  183. data/lib/rubbycop/cop/metrics/block_length.rb +32 -0
  184. data/lib/rubbycop/cop/metrics/block_nesting.rb +64 -0
  185. data/lib/rubbycop/cop/metrics/class_length.rb +24 -0
  186. data/lib/rubbycop/cop/metrics/cyclomatic_complexity.rb +31 -0
  187. data/lib/rubbycop/cop/metrics/line_length.rb +168 -0
  188. data/lib/rubbycop/cop/metrics/method_length.rb +27 -0
  189. data/lib/rubbycop/cop/metrics/module_length.rb +24 -0
  190. data/lib/rubbycop/cop/metrics/parameter_lists.rb +45 -0
  191. data/lib/rubbycop/cop/metrics/perceived_complexity.rb +61 -0
  192. data/lib/rubbycop/cop/mixin/access_modifier_node.rb +41 -0
  193. data/lib/rubbycop/cop/mixin/annotation_comment.rb +36 -0
  194. data/lib/rubbycop/cop/mixin/array_hash_indentation.rb +82 -0
  195. data/lib/rubbycop/cop/mixin/array_min_size.rb +59 -0
  196. data/lib/rubbycop/cop/mixin/array_syntax.rb +15 -0
  197. data/lib/rubbycop/cop/mixin/autocorrect_alignment.rb +149 -0
  198. data/lib/rubbycop/cop/mixin/check_assignment.rb +40 -0
  199. data/lib/rubbycop/cop/mixin/classish_length.rb +36 -0
  200. data/lib/rubbycop/cop/mixin/code_length.rb +32 -0
  201. data/lib/rubbycop/cop/mixin/configurable_enforced_style.rb +97 -0
  202. data/lib/rubbycop/cop/mixin/configurable_formatting.rb +48 -0
  203. data/lib/rubbycop/cop/mixin/configurable_max.rb +19 -0
  204. data/lib/rubbycop/cop/mixin/configurable_naming.rb +16 -0
  205. data/lib/rubbycop/cop/mixin/configurable_numbering.rb +17 -0
  206. data/lib/rubbycop/cop/mixin/def_node.rb +27 -0
  207. data/lib/rubbycop/cop/mixin/documentation_comment.rb +46 -0
  208. data/lib/rubbycop/cop/mixin/duplication.rb +46 -0
  209. data/lib/rubbycop/cop/mixin/empty_lines_around_body.rb +161 -0
  210. data/lib/rubbycop/cop/mixin/end_keyword_alignment.rb +85 -0
  211. data/lib/rubbycop/cop/mixin/enforce_superclass.rb +36 -0
  212. data/lib/rubbycop/cop/mixin/first_element_line_break.rb +41 -0
  213. data/lib/rubbycop/cop/mixin/frozen_string_literal.rb +37 -0
  214. data/lib/rubbycop/cop/mixin/hash_alignment.rb +116 -0
  215. data/lib/rubbycop/cop/mixin/ignored_pattern.rb +27 -0
  216. data/lib/rubbycop/cop/mixin/integer_node.rb +12 -0
  217. data/lib/rubbycop/cop/mixin/match_range.rb +22 -0
  218. data/lib/rubbycop/cop/mixin/method_complexity.rb +30 -0
  219. data/lib/rubbycop/cop/mixin/method_preference.rb +30 -0
  220. data/lib/rubbycop/cop/mixin/min_body_length.rb +19 -0
  221. data/lib/rubbycop/cop/mixin/multiline_expression_indentation.rb +183 -0
  222. data/lib/rubbycop/cop/mixin/multiline_literal_brace_layout.rb +152 -0
  223. data/lib/rubbycop/cop/mixin/negative_conditional.rb +43 -0
  224. data/lib/rubbycop/cop/mixin/on_method_def.rb +44 -0
  225. data/lib/rubbycop/cop/mixin/on_normal_if_unless.rb +14 -0
  226. data/lib/rubbycop/cop/mixin/parentheses.rb +22 -0
  227. data/lib/rubbycop/cop/mixin/parser_diagnostic.rb +34 -0
  228. data/lib/rubbycop/cop/mixin/percent_literal.rb +100 -0
  229. data/lib/rubbycop/cop/mixin/preceding_following_alignment.rb +89 -0
  230. data/lib/rubbycop/cop/mixin/rescue_node.rb +21 -0
  231. data/lib/rubbycop/cop/mixin/safe_assignment.rb +20 -0
  232. data/lib/rubbycop/cop/mixin/safe_mode.rb +22 -0
  233. data/lib/rubbycop/cop/mixin/space_after_punctuation.rb +55 -0
  234. data/lib/rubbycop/cop/mixin/space_before_punctuation.rb +48 -0
  235. data/lib/rubbycop/cop/mixin/space_inside.rb +76 -0
  236. data/lib/rubbycop/cop/mixin/statement_modifier.rb +69 -0
  237. data/lib/rubbycop/cop/mixin/string_help.rb +33 -0
  238. data/lib/rubbycop/cop/mixin/string_literals_help.rb +33 -0
  239. data/lib/rubbycop/cop/mixin/surrounding_space.rb +40 -0
  240. data/lib/rubbycop/cop/mixin/target_rails_version.rb +16 -0
  241. data/lib/rubbycop/cop/mixin/target_ruby_version.rb +16 -0
  242. data/lib/rubbycop/cop/mixin/too_many_lines.rb +39 -0
  243. data/lib/rubbycop/cop/mixin/trailing_comma.rb +161 -0
  244. data/lib/rubbycop/cop/mixin/unused_argument.rb +42 -0
  245. data/lib/rubbycop/cop/offense.rb +188 -0
  246. data/lib/rubbycop/cop/performance/caller.rb +41 -0
  247. data/lib/rubbycop/cop/performance/case_when_splat.rb +176 -0
  248. data/lib/rubbycop/cop/performance/casecmp.rb +107 -0
  249. data/lib/rubbycop/cop/performance/compare_with_block.rb +107 -0
  250. data/lib/rubbycop/cop/performance/count.rb +98 -0
  251. data/lib/rubbycop/cop/performance/detect.rb +107 -0
  252. data/lib/rubbycop/cop/performance/double_start_end_with.rb +102 -0
  253. data/lib/rubbycop/cop/performance/end_with.rb +55 -0
  254. data/lib/rubbycop/cop/performance/fixed_size.rb +56 -0
  255. data/lib/rubbycop/cop/performance/flat_map.rb +73 -0
  256. data/lib/rubbycop/cop/performance/hash_each_methods.rb +84 -0
  257. data/lib/rubbycop/cop/performance/lstrip_rstrip.rb +41 -0
  258. data/lib/rubbycop/cop/performance/range_include.rb +41 -0
  259. data/lib/rubbycop/cop/performance/redundant_block_call.rb +93 -0
  260. data/lib/rubbycop/cop/performance/redundant_match.rb +55 -0
  261. data/lib/rubbycop/cop/performance/redundant_merge.rb +149 -0
  262. data/lib/rubbycop/cop/performance/redundant_sort_by.rb +45 -0
  263. data/lib/rubbycop/cop/performance/regexp_match.rb +215 -0
  264. data/lib/rubbycop/cop/performance/reverse_each.rb +40 -0
  265. data/lib/rubbycop/cop/performance/sample.rb +140 -0
  266. data/lib/rubbycop/cop/performance/size.rb +71 -0
  267. data/lib/rubbycop/cop/performance/start_with.rb +58 -0
  268. data/lib/rubbycop/cop/performance/string_replacement.rb +170 -0
  269. data/lib/rubbycop/cop/performance/times_map.rb +61 -0
  270. data/lib/rubbycop/cop/rails/action_filter.rb +96 -0
  271. data/lib/rubbycop/cop/rails/active_support_aliases.rb +68 -0
  272. data/lib/rubbycop/cop/rails/application_job.rb +32 -0
  273. data/lib/rubbycop/cop/rails/application_record.rb +32 -0
  274. data/lib/rubbycop/cop/rails/blank.rb +138 -0
  275. data/lib/rubbycop/cop/rails/date.rb +127 -0
  276. data/lib/rubbycop/cop/rails/delegate.rb +106 -0
  277. data/lib/rubbycop/cop/rails/delegate_allow_blank.rb +51 -0
  278. data/lib/rubbycop/cop/rails/dynamic_find_by.rb +81 -0
  279. data/lib/rubbycop/cop/rails/enum_uniqueness.rb +43 -0
  280. data/lib/rubbycop/cop/rails/exit.rb +61 -0
  281. data/lib/rubbycop/cop/rails/file_path.rb +75 -0
  282. data/lib/rubbycop/cop/rails/find_by.rb +51 -0
  283. data/lib/rubbycop/cop/rails/find_each.rb +47 -0
  284. data/lib/rubbycop/cop/rails/has_and_belongs_to_many.rb +18 -0
  285. data/lib/rubbycop/cop/rails/http_positional_arguments.rb +106 -0
  286. data/lib/rubbycop/cop/rails/not_null_column.rb +67 -0
  287. data/lib/rubbycop/cop/rails/output.rb +23 -0
  288. data/lib/rubbycop/cop/rails/output_safety.rb +58 -0
  289. data/lib/rubbycop/cop/rails/pluralization_grammar.rb +106 -0
  290. data/lib/rubbycop/cop/rails/present.rb +143 -0
  291. data/lib/rubbycop/cop/rails/read_write_attribute.rb +65 -0
  292. data/lib/rubbycop/cop/rails/relative_date_constant.rb +88 -0
  293. data/lib/rubbycop/cop/rails/request_referer.rb +56 -0
  294. data/lib/rubbycop/cop/rails/reversible_migration.rb +216 -0
  295. data/lib/rubbycop/cop/rails/safe_navigation.rb +91 -0
  296. data/lib/rubbycop/cop/rails/save_bang.rb +160 -0
  297. data/lib/rubbycop/cop/rails/scope_args.rb +29 -0
  298. data/lib/rubbycop/cop/rails/skips_model_validations.rb +63 -0
  299. data/lib/rubbycop/cop/rails/time_zone.rb +197 -0
  300. data/lib/rubbycop/cop/rails/uniq_before_pluck.rb +93 -0
  301. data/lib/rubbycop/cop/rails/validation.rb +64 -0
  302. data/lib/rubbycop/cop/registry.rb +171 -0
  303. data/lib/rubbycop/cop/security/eval.rb +30 -0
  304. data/lib/rubbycop/cop/security/json_load.rb +44 -0
  305. data/lib/rubbycop/cop/security/marshal_load.rb +37 -0
  306. data/lib/rubbycop/cop/security/yaml_load.rb +37 -0
  307. data/lib/rubbycop/cop/severity.rb +76 -0
  308. data/lib/rubbycop/cop/style/accessor_method_name.rb +45 -0
  309. data/lib/rubbycop/cop/style/alias.rb +119 -0
  310. data/lib/rubbycop/cop/style/and_or.rb +125 -0
  311. data/lib/rubbycop/cop/style/array_join.rb +30 -0
  312. data/lib/rubbycop/cop/style/ascii_comments.rb +38 -0
  313. data/lib/rubbycop/cop/style/ascii_identifiers.rb +36 -0
  314. data/lib/rubbycop/cop/style/attr.rb +50 -0
  315. data/lib/rubbycop/cop/style/auto_resource_cleanup.rb +42 -0
  316. data/lib/rubbycop/cop/style/bare_percent_literals.rb +57 -0
  317. data/lib/rubbycop/cop/style/begin_block.rb +16 -0
  318. data/lib/rubbycop/cop/style/block_comments.rb +46 -0
  319. data/lib/rubbycop/cop/style/block_delimiters.rb +228 -0
  320. data/lib/rubbycop/cop/style/braces_around_hash_parameters.rb +138 -0
  321. data/lib/rubbycop/cop/style/case_equality.rb +18 -0
  322. data/lib/rubbycop/cop/style/character_literal.rb +43 -0
  323. data/lib/rubbycop/cop/style/class_and_module_camel_case.rb +29 -0
  324. data/lib/rubbycop/cop/style/class_and_module_children.rb +69 -0
  325. data/lib/rubbycop/cop/style/class_check.rb +40 -0
  326. data/lib/rubbycop/cop/style/class_methods.rb +67 -0
  327. data/lib/rubbycop/cop/style/class_vars.rb +23 -0
  328. data/lib/rubbycop/cop/style/collection_methods.rb +51 -0
  329. data/lib/rubbycop/cop/style/colon_method_call.rb +33 -0
  330. data/lib/rubbycop/cop/style/command_literal.rb +119 -0
  331. data/lib/rubbycop/cop/style/comment_annotation.rb +62 -0
  332. data/lib/rubbycop/cop/style/conditional_assignment.rb +691 -0
  333. data/lib/rubbycop/cop/style/constant_name.rb +29 -0
  334. data/lib/rubbycop/cop/style/copyright.rb +89 -0
  335. data/lib/rubbycop/cop/style/def_with_parentheses.rb +31 -0
  336. data/lib/rubbycop/cop/style/documentation.rb +79 -0
  337. data/lib/rubbycop/cop/style/documentation_method.rb +80 -0
  338. data/lib/rubbycop/cop/style/double_negation.rb +35 -0
  339. data/lib/rubbycop/cop/style/each_for_simple_loop.rb +57 -0
  340. data/lib/rubbycop/cop/style/each_with_object.rb +91 -0
  341. data/lib/rubbycop/cop/style/empty_case_condition.rb +84 -0
  342. data/lib/rubbycop/cop/style/empty_else.rb +138 -0
  343. data/lib/rubbycop/cop/style/empty_literal.rb +108 -0
  344. data/lib/rubbycop/cop/style/empty_method.rb +102 -0
  345. data/lib/rubbycop/cop/style/encoding.rb +92 -0
  346. data/lib/rubbycop/cop/style/end_block.rb +17 -0
  347. data/lib/rubbycop/cop/style/even_odd.rb +56 -0
  348. data/lib/rubbycop/cop/style/file_name.rb +183 -0
  349. data/lib/rubbycop/cop/style/flip_flop.rb +20 -0
  350. data/lib/rubbycop/cop/style/for.rb +50 -0
  351. data/lib/rubbycop/cop/style/format_string.rb +46 -0
  352. data/lib/rubbycop/cop/style/format_string_token.rb +141 -0
  353. data/lib/rubbycop/cop/style/frozen_string_literal_comment.rb +96 -0
  354. data/lib/rubbycop/cop/style/global_vars.rb +70 -0
  355. data/lib/rubbycop/cop/style/guard_clause.rb +90 -0
  356. data/lib/rubbycop/cop/style/hash_syntax.rb +214 -0
  357. data/lib/rubbycop/cop/style/identical_conditional_branches.rb +130 -0
  358. data/lib/rubbycop/cop/style/if_inside_else.rb +45 -0
  359. data/lib/rubbycop/cop/style/if_unless_modifier.rb +80 -0
  360. data/lib/rubbycop/cop/style/if_unless_modifier_of_if_unless.rb +38 -0
  361. data/lib/rubbycop/cop/style/if_with_semicolon.rb +20 -0
  362. data/lib/rubbycop/cop/style/implicit_runtime_error.rb +31 -0
  363. data/lib/rubbycop/cop/style/infinite_loop.rb +91 -0
  364. data/lib/rubbycop/cop/style/inline_comment.rb +32 -0
  365. data/lib/rubbycop/cop/style/inverse_methods.rb +130 -0
  366. data/lib/rubbycop/cop/style/lambda.rb +209 -0
  367. data/lib/rubbycop/cop/style/lambda_call.rb +66 -0
  368. data/lib/rubbycop/cop/style/line_end_concatenation.rb +115 -0
  369. data/lib/rubbycop/cop/style/method_call_with_args_parentheses.rb +107 -0
  370. data/lib/rubbycop/cop/style/method_call_without_args_parentheses.rb +75 -0
  371. data/lib/rubbycop/cop/style/method_called_on_do_end_block.rb +44 -0
  372. data/lib/rubbycop/cop/style/method_def_parentheses.rb +83 -0
  373. data/lib/rubbycop/cop/style/method_missing.rb +81 -0
  374. data/lib/rubbycop/cop/style/method_name.rb +28 -0
  375. data/lib/rubbycop/cop/style/missing_else.rb +100 -0
  376. data/lib/rubbycop/cop/style/mixin_grouping.rb +135 -0
  377. data/lib/rubbycop/cop/style/module_function.rb +64 -0
  378. data/lib/rubbycop/cop/style/multiline_block_chain.rb +42 -0
  379. data/lib/rubbycop/cop/style/multiline_if_modifier.rb +63 -0
  380. data/lib/rubbycop/cop/style/multiline_if_then.rb +47 -0
  381. data/lib/rubbycop/cop/style/multiline_memoization.rb +77 -0
  382. data/lib/rubbycop/cop/style/multiline_ternary_operator.rb +19 -0
  383. data/lib/rubbycop/cop/style/mutable_constant.rb +68 -0
  384. data/lib/rubbycop/cop/style/negated_if.rb +103 -0
  385. data/lib/rubbycop/cop/style/negated_while.rb +32 -0
  386. data/lib/rubbycop/cop/style/nested_modifier.rb +87 -0
  387. data/lib/rubbycop/cop/style/nested_parenthesized_calls.rb +61 -0
  388. data/lib/rubbycop/cop/style/nested_ternary_operator.rb +21 -0
  389. data/lib/rubbycop/cop/style/next.rb +225 -0
  390. data/lib/rubbycop/cop/style/nil_comparison.rb +35 -0
  391. data/lib/rubbycop/cop/style/non_nil_check.rb +121 -0
  392. data/lib/rubbycop/cop/style/not.rb +69 -0
  393. data/lib/rubbycop/cop/style/numeric_literal_prefix.rb +97 -0
  394. data/lib/rubbycop/cop/style/numeric_literals.rb +101 -0
  395. data/lib/rubbycop/cop/style/numeric_predicate.rb +140 -0
  396. data/lib/rubbycop/cop/style/one_line_conditional.rb +75 -0
  397. data/lib/rubbycop/cop/style/op_method.rb +41 -0
  398. data/lib/rubbycop/cop/style/option_hash.rb +58 -0
  399. data/lib/rubbycop/cop/style/optional_arguments.rb +62 -0
  400. data/lib/rubbycop/cop/style/parallel_assignment.rb +287 -0
  401. data/lib/rubbycop/cop/style/parentheses_around_condition.rb +56 -0
  402. data/lib/rubbycop/cop/style/percent_literal_delimiters.rb +100 -0
  403. data/lib/rubbycop/cop/style/percent_q_literals.rb +52 -0
  404. data/lib/rubbycop/cop/style/perl_backrefs.rb +31 -0
  405. data/lib/rubbycop/cop/style/predicate_name.rb +67 -0
  406. data/lib/rubbycop/cop/style/preferred_hash_methods.rb +78 -0
  407. data/lib/rubbycop/cop/style/proc.rb +26 -0
  408. data/lib/rubbycop/cop/style/raise_args.rb +140 -0
  409. data/lib/rubbycop/cop/style/redundant_begin.rb +47 -0
  410. data/lib/rubbycop/cop/style/redundant_exception.rb +55 -0
  411. data/lib/rubbycop/cop/style/redundant_freeze.rb +45 -0
  412. data/lib/rubbycop/cop/style/redundant_parentheses.rb +199 -0
  413. data/lib/rubbycop/cop/style/redundant_return.rb +121 -0
  414. data/lib/rubbycop/cop/style/redundant_self.rb +144 -0
  415. data/lib/rubbycop/cop/style/regexp_literal.rb +114 -0
  416. data/lib/rubbycop/cop/style/rescue_modifier.rb +37 -0
  417. data/lib/rubbycop/cop/style/safe_navigation.rb +145 -0
  418. data/lib/rubbycop/cop/style/self_assignment.rb +93 -0
  419. data/lib/rubbycop/cop/style/semicolon.rb +70 -0
  420. data/lib/rubbycop/cop/style/send.rb +21 -0
  421. data/lib/rubbycop/cop/style/signal_exception.rb +109 -0
  422. data/lib/rubbycop/cop/style/single_line_block_params.rb +68 -0
  423. data/lib/rubbycop/cop/style/single_line_methods.rb +77 -0
  424. data/lib/rubbycop/cop/style/special_global_vars.rb +156 -0
  425. data/lib/rubbycop/cop/style/stabby_lambda_parentheses.rb +113 -0
  426. data/lib/rubbycop/cop/style/string_literals.rb +102 -0
  427. data/lib/rubbycop/cop/style/string_literals_in_interpolation.rb +30 -0
  428. data/lib/rubbycop/cop/style/string_methods.rb +34 -0
  429. data/lib/rubbycop/cop/style/struct_inheritance.rb +32 -0
  430. data/lib/rubbycop/cop/style/symbol_array.rb +109 -0
  431. data/lib/rubbycop/cop/style/symbol_literal.rb +32 -0
  432. data/lib/rubbycop/cop/style/symbol_proc.rb +143 -0
  433. data/lib/rubbycop/cop/style/ternary_parentheses.rb +200 -0
  434. data/lib/rubbycop/cop/style/trailing_comma_in_arguments.rb +64 -0
  435. data/lib/rubbycop/cop/style/trailing_comma_in_literal.rb +56 -0
  436. data/lib/rubbycop/cop/style/trailing_underscore_variable.rb +113 -0
  437. data/lib/rubbycop/cop/style/trivial_accessors.rb +176 -0
  438. data/lib/rubbycop/cop/style/unless_else.rb +39 -0
  439. data/lib/rubbycop/cop/style/unneeded_capital_w.rb +41 -0
  440. data/lib/rubbycop/cop/style/unneeded_interpolation.rb +98 -0
  441. data/lib/rubbycop/cop/style/unneeded_percent_q.rb +96 -0
  442. data/lib/rubbycop/cop/style/variable_interpolation.rb +44 -0
  443. data/lib/rubbycop/cop/style/variable_name.rb +39 -0
  444. data/lib/rubbycop/cop/style/variable_number.rb +78 -0
  445. data/lib/rubbycop/cop/style/when_then.rb +24 -0
  446. data/lib/rubbycop/cop/style/while_until_do.rb +36 -0
  447. data/lib/rubbycop/cop/style/while_until_modifier.rb +41 -0
  448. data/lib/rubbycop/cop/style/word_array.rb +114 -0
  449. data/lib/rubbycop/cop/style/zero_length_predicate.rb +90 -0
  450. data/lib/rubbycop/cop/team.rb +193 -0
  451. data/lib/rubbycop/cop/util.rb +309 -0
  452. data/lib/rubbycop/cop/variable_force.rb +458 -0
  453. data/lib/rubbycop/cop/variable_force/assignment.rb +90 -0
  454. data/lib/rubbycop/cop/variable_force/branch.rb +318 -0
  455. data/lib/rubbycop/cop/variable_force/branchable.rb +21 -0
  456. data/lib/rubbycop/cop/variable_force/reference.rb +49 -0
  457. data/lib/rubbycop/cop/variable_force/scope.rb +107 -0
  458. data/lib/rubbycop/cop/variable_force/variable.rb +103 -0
  459. data/lib/rubbycop/cop/variable_force/variable_table.rb +128 -0
  460. data/lib/rubbycop/error.rb +11 -0
  461. data/lib/rubbycop/formatter/base_formatter.rb +123 -0
  462. data/lib/rubbycop/formatter/clang_style_formatter.rb +54 -0
  463. data/lib/rubbycop/formatter/colorizable.rb +41 -0
  464. data/lib/rubbycop/formatter/disabled_config_formatter.rb +181 -0
  465. data/lib/rubbycop/formatter/disabled_lines_formatter.rb +57 -0
  466. data/lib/rubbycop/formatter/emacs_style_formatter.rb +24 -0
  467. data/lib/rubbycop/formatter/file_list_formatter.rb +19 -0
  468. data/lib/rubbycop/formatter/formatter_set.rb +102 -0
  469. data/lib/rubbycop/formatter/fuubar_style_formatter.rb +80 -0
  470. data/lib/rubbycop/formatter/html_formatter.rb +134 -0
  471. data/lib/rubbycop/formatter/json_formatter.rb +74 -0
  472. data/lib/rubbycop/formatter/offense_count_formatter.rb +55 -0
  473. data/lib/rubbycop/formatter/progress_formatter.rb +63 -0
  474. data/lib/rubbycop/formatter/simple_text_formatter.rb +136 -0
  475. data/lib/rubbycop/formatter/text_util.rb +20 -0
  476. data/lib/rubbycop/formatter/worst_offenders_formatter.rb +60 -0
  477. data/lib/rubbycop/magic_comment.rb +210 -0
  478. data/lib/rubbycop/name_similarity.rb +21 -0
  479. data/lib/rubbycop/node_pattern.rb +543 -0
  480. data/lib/rubbycop/options.rb +355 -0
  481. data/lib/rubbycop/path_util.rb +36 -0
  482. data/lib/rubbycop/platform.rb +11 -0
  483. data/lib/rubbycop/processed_source.rb +151 -0
  484. data/lib/rubbycop/rake_task.rb +86 -0
  485. data/lib/rubbycop/remote_config.rb +78 -0
  486. data/lib/rubbycop/result_cache.rb +176 -0
  487. data/lib/rubbycop/rspec/cop_helper.rb +98 -0
  488. data/lib/rubbycop/rspec/host_environment_simulation_helper.rb +32 -0
  489. data/lib/rubbycop/rspec/shared_contexts.rb +98 -0
  490. data/lib/rubbycop/rspec/shared_examples.rb +92 -0
  491. data/lib/rubbycop/rspec/support.rb +8 -0
  492. data/lib/rubbycop/runner.rb +338 -0
  493. data/lib/rubbycop/string_interpreter.rb +57 -0
  494. data/lib/rubbycop/string_util.rb +156 -0
  495. data/lib/rubbycop/target_finder.rb +201 -0
  496. data/lib/rubbycop/token.rb +25 -0
  497. data/lib/rubbycop/version.rb +19 -0
  498. data/lib/rubbycop/warning.rb +11 -0
  499. metadata +663 -0
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubbyCop
4
+ module AST
5
+ # `RubbyCop::Builder` is an AST builder that is utilized to let `Parser`
6
+ # generate ASTs with {RubbyCop::AST::Node}.
7
+ #
8
+ # @example
9
+ # buffer = Parser::Source::Buffer.new('(string)')
10
+ # buffer.source = 'puts :foo'
11
+ #
12
+ # builder = RubbyCop::Builder.new
13
+ # parser = Parser::CurrentRuby.new(builder)
14
+ # root_node = parser.parse(buffer)
15
+ class Builder < Parser::Builders::Default
16
+ NODE_MAP = {
17
+ AndNode => [:and],
18
+ ArrayNode => [:array],
19
+ CaseNode => [:case],
20
+ EnsureNode => [:ensure],
21
+ ForNode => [:for],
22
+ HashNode => [:hash],
23
+ IfNode => [:if],
24
+ KeywordSplatNode => [:kwsplat],
25
+ OrNode => [:or],
26
+ PairNode => [:pair],
27
+ ResbodyNode => [:resbody],
28
+ SendNode => [:send],
29
+ UntilNode => %i[until until_post],
30
+ WhenNode => [:when],
31
+ WhileNode => %i[while while_post]
32
+ }.freeze
33
+
34
+ # Generates {Node} from the given information.
35
+ #
36
+ # @return [Node] the generated node
37
+ def n(type, children, source_map)
38
+ node_klass(type).new(type, children, location: source_map)
39
+ end
40
+
41
+ # TODO: Figure out what to do about literal encoding handling...
42
+ # More details here https://github.com/whitequark/parser/issues/283
43
+ def string_value(token)
44
+ value(token)
45
+ end
46
+
47
+ private
48
+
49
+ def node_klass(type)
50
+ node_map[type] || Node
51
+ end
52
+
53
+ # Take the human readable constant and generate a hash map where each
54
+ # (mapped) node type is a key with its constant as the value.
55
+ def node_map
56
+ @node_map ||= begin
57
+ NODE_MAP.each_pair.each_with_object({}) do |(klass, types), map|
58
+ types.each { |type| map[type] = klass }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,610 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubbyCop
4
+ module AST
5
+ # `RubbyCop::AST::Node` is a subclass of `Parser::AST::Node`. It provides
6
+ # access to parent nodes and an object-oriented way to traverse an AST with
7
+ # the power of `Enumerable`.
8
+ #
9
+ # It has predicate methods for every node type, like this:
10
+ #
11
+ # @example
12
+ # node.send_type? # Equivalent to: `node.type == :send`
13
+ # node.op_asgn_type? # Equivalent to: `node.type == :op_asgn`
14
+ #
15
+ # # Non-word characters (other than a-zA-Z0-9_) in type names are omitted.
16
+ # node.defined_type? # Equivalent to: `node.type == :defined?`
17
+ #
18
+ # # Find the first lvar node under the receiver node.
19
+ # lvar_node = node.each_descendant.find(&:lvar_type?)
20
+ #
21
+ class Node < Parser::AST::Node # rubbycop:disable Metrics/ClassLength
22
+ include RubbyCop::AST::Sexp
23
+
24
+ COMPARISON_OPERATORS = %i[! == === != <= >= > < <=>].freeze
25
+
26
+ TRUTHY_LITERALS = %i[str dstr xstr int float sym dsym array
27
+ hash regexp true irange erange complex
28
+ rational regopt].freeze
29
+ FALSEY_LITERALS = %i[false nil].freeze
30
+ LITERALS = (TRUTHY_LITERALS + FALSEY_LITERALS).freeze
31
+ COMPOSITE_LITERALS = %i[dstr xstr dsym array hash irange
32
+ erange regexp].freeze
33
+ BASIC_LITERALS = (LITERALS - COMPOSITE_LITERALS).freeze
34
+ MUTABLE_LITERALS = %i[str dstr xstr array hash].freeze
35
+ IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze
36
+
37
+ VARIABLES = %i[ivar gvar cvar lvar].freeze
38
+ REFERENCES = %i[nth_ref back_ref].freeze
39
+ KEYWORDS = %i[alias and break case class def defs defined?
40
+ kwbegin do else ensure for if module next
41
+ not or postexe redo rescue retry return self
42
+ super zsuper then undef until when while
43
+ yield].freeze
44
+ OPERATOR_KEYWORDS = %i[and or].freeze
45
+ SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze
46
+
47
+ # def_matcher can be used to define a pattern-matching method on Node
48
+ class << self
49
+ def def_matcher(method_name, pattern_str)
50
+ compiler = RubbyCop::NodePattern::Compiler.new(pattern_str, 'self')
51
+ src = "def #{method_name}(" \
52
+ "#{compiler.emit_param_list});" \
53
+ "#{compiler.emit_method_code};end"
54
+
55
+ location = caller_locations(1, 1).first
56
+ class_eval(src, location.path, location.lineno)
57
+ end
58
+ end
59
+
60
+ # @see http://rubydoc.info/gems/ast/AST/Node:initialize
61
+ def initialize(type, children = [], properties = {})
62
+ @mutable_attributes = {}
63
+
64
+ # ::AST::Node#initialize freezes itself.
65
+ super
66
+
67
+ # #parent= may be invoked multiple times for a node because there are
68
+ # pending nodes while constructing AST and they are replaced later.
69
+ # For example, `lvar` and `send` type nodes are initially created as an
70
+ # `ident` type node and fixed to the appropriate type later.
71
+ # So, the #parent attribute needs to be mutable.
72
+ each_child_node do |child_node|
73
+ child_node.parent = self unless child_node.complete?
74
+ end
75
+ end
76
+
77
+ Parser::Meta::NODE_TYPES.each do |node_type|
78
+ method_name = "#{node_type.to_s.gsub(/\W/, '')}_type?"
79
+ define_method(method_name) do
80
+ type == node_type
81
+ end
82
+ end
83
+
84
+ # Returns the parent node, or `nil` if the receiver is a root node.
85
+ #
86
+ # @return [Node, nil] the parent node or `nil`
87
+ def parent
88
+ @mutable_attributes[:parent]
89
+ end
90
+
91
+ def parent=(node)
92
+ @mutable_attributes[:parent] = node
93
+ end
94
+
95
+ def complete!
96
+ @mutable_attributes.freeze
97
+ each_child_node(&:complete!)
98
+ end
99
+
100
+ def complete?
101
+ @mutable_attributes.frozen?
102
+ end
103
+
104
+ protected :parent=
105
+
106
+ # Override `AST::Node#updated` so that `AST::Processor` does not try to
107
+ # mutate our ASTs. Since we keep references from children to parents and
108
+ # not just the other way around, we cannot update an AST and share
109
+ # identical subtrees. Rather, the entire AST must be copied any time any
110
+ # part of it is changed.
111
+ def updated(type = nil, children = nil, properties = {})
112
+ properties[:location] ||= @location
113
+ self.class.new(type || @type, children || @children, properties)
114
+ end
115
+
116
+ # Returns the index of the receiver node in its siblings. (Sibling index
117
+ # uses zero based numbering.)
118
+ #
119
+ # @return [Integer] the index of the receiver node in its siblings
120
+ def sibling_index
121
+ parent.children.index { |sibling| sibling.equal?(self) }
122
+ end
123
+
124
+ # Calls the given block for each ancestor node from parent to root.
125
+ # If no block is given, an `Enumerator` is returned.
126
+ #
127
+ # @overload each_ancestor
128
+ # Yield all nodes.
129
+ # @overload each_ancestor(type)
130
+ # Yield only nodes matching the type.
131
+ # @param [Symbol] type a node type
132
+ # @overload each_ancestor(type_a, type_b, ...)
133
+ # Yield only nodes matching any of the types.
134
+ # @param [Symbol] type_a a node type
135
+ # @param [Symbol] type_b a node type
136
+ # @overload each_ancestor(types)
137
+ # Yield only nodes matching any of types in the array.
138
+ # @param [Array<Symbol>] types an array containing node types
139
+ # @yieldparam [Node] node each ancestor node
140
+ # @return [self] if a block is given
141
+ # @return [Enumerator] if no block is given
142
+ def each_ancestor(*types, &block)
143
+ return to_enum(__method__, *types) unless block_given?
144
+
145
+ visit_ancestors(types, &block)
146
+
147
+ self
148
+ end
149
+
150
+ # Returns an array of ancestor nodes.
151
+ # This is a shorthand for `node.each_ancestor.to_a`.
152
+ #
153
+ # @return [Array<Node>] an array of ancestor nodes
154
+ def ancestors
155
+ each_ancestor.to_a
156
+ end
157
+
158
+ # Calls the given block for each child node.
159
+ # If no block is given, an `Enumerator` is returned.
160
+ #
161
+ # Note that this is different from `node.children.each { |child| ... }`
162
+ # which yields all children including non-node elements.
163
+ #
164
+ # @overload each_child_node
165
+ # Yield all nodes.
166
+ # @overload each_child_node(type)
167
+ # Yield only nodes matching the type.
168
+ # @param [Symbol] type a node type
169
+ # @overload each_child_node(type_a, type_b, ...)
170
+ # Yield only nodes matching any of the types.
171
+ # @param [Symbol] type_a a node type
172
+ # @param [Symbol] type_b a node type
173
+ # @overload each_child_node(types)
174
+ # Yield only nodes matching any of types in the array.
175
+ # @param [Array<Symbol>] types an array containing node types
176
+ # @yieldparam [Node] node each child node
177
+ # @return [self] if a block is given
178
+ # @return [Enumerator] if no block is given
179
+ def each_child_node(*types)
180
+ return to_enum(__method__, *types) unless block_given?
181
+
182
+ children.each do |child|
183
+ next unless child.is_a?(Node)
184
+ yield child if types.empty? || types.include?(child.type)
185
+ end
186
+
187
+ self
188
+ end
189
+
190
+ # Returns an array of child nodes.
191
+ # This is a shorthand for `node.each_child_node.to_a`.
192
+ #
193
+ # @return [Array<Node>] an array of child nodes
194
+ def child_nodes
195
+ each_child_node.to_a
196
+ end
197
+
198
+ # Calls the given block for each descendant node with depth first order.
199
+ # If no block is given, an `Enumerator` is returned.
200
+ #
201
+ # @overload each_descendant
202
+ # Yield all nodes.
203
+ # @overload each_descendant(type)
204
+ # Yield only nodes matching the type.
205
+ # @param [Symbol] type a node type
206
+ # @overload each_descendant(type_a, type_b, ...)
207
+ # Yield only nodes matching any of the types.
208
+ # @param [Symbol] type_a a node type
209
+ # @param [Symbol] type_b a node type
210
+ # @overload each_descendant(types)
211
+ # Yield only nodes matching any of types in the array.
212
+ # @param [Array<Symbol>] types an array containing node types
213
+ # @yieldparam [Node] node each descendant node
214
+ # @return [self] if a block is given
215
+ # @return [Enumerator] if no block is given
216
+ def each_descendant(*types, &block)
217
+ return to_enum(__method__, *types) unless block_given?
218
+
219
+ visit_descendants(types, &block)
220
+
221
+ self
222
+ end
223
+
224
+ # Returns an array of descendant nodes.
225
+ # This is a shorthand for `node.each_descendant.to_a`.
226
+ #
227
+ # @return [Array<Node>] an array of descendant nodes
228
+ def descendants
229
+ each_descendant.to_a
230
+ end
231
+
232
+ # Calls the given block for the receiver and each descendant node in
233
+ # depth-first order.
234
+ # If no block is given, an `Enumerator` is returned.
235
+ #
236
+ # This method would be useful when you treat the receiver node as the root
237
+ # of a tree and want to iterate over all nodes in the tree.
238
+ #
239
+ # @overload each_node
240
+ # Yield all nodes.
241
+ # @overload each_node(type)
242
+ # Yield only nodes matching the type.
243
+ # @param [Symbol] type a node type
244
+ # @overload each_node(type_a, type_b, ...)
245
+ # Yield only nodes matching any of the types.
246
+ # @param [Symbol] type_a a node type
247
+ # @param [Symbol] type_b a node type
248
+ # @overload each_node(types)
249
+ # Yield only nodes matching any of types in the array.
250
+ # @param [Array<Symbol>] types an array containing node types
251
+ # @yieldparam [Node] node each node
252
+ # @return [self] if a block is given
253
+ # @return [Enumerator] if no block is given
254
+ def each_node(*types, &block)
255
+ return to_enum(__method__, *types) unless block_given?
256
+
257
+ yield self if types.empty? || types.include?(type)
258
+
259
+ visit_descendants(types, &block)
260
+
261
+ self
262
+ end
263
+
264
+ def source
265
+ loc.expression.source
266
+ end
267
+
268
+ def source_range
269
+ loc.expression
270
+ end
271
+
272
+ ## Destructuring
273
+
274
+ def_matcher :receiver, '{(send $_ ...) (block (send $_ ...) ...)}'
275
+ def_matcher :method_name, '{(send _ $_ ...) (block (send _ $_ ...) ...)}'
276
+ def_matcher :method_args, '{(send _ _ $...) (block (send _ _ $...) ...)}'
277
+ # Note: for masgn, #asgn_rhs will be an array node
278
+ def_matcher :asgn_rhs, '[assignment? (... $_)]'
279
+ def_matcher :str_content, '(str $_)'
280
+
281
+ def const_name
282
+ return unless const_type?
283
+ namespace, name = *self
284
+ if namespace && !namespace.cbase_type?
285
+ "#{namespace.const_name}::#{name}"
286
+ else
287
+ name.to_s
288
+ end
289
+ end
290
+
291
+ def_matcher :defined_module0, <<-PATTERN
292
+ {(class (const $_ $_) ...)
293
+ (module (const $_ $_) ...)
294
+ (casgn $_ $_ (send (const nil {:Class :Module}) :new ...))
295
+ (casgn $_ $_ (block (send (const nil {:Class :Module}) :new ...) ...))}
296
+ PATTERN
297
+ private :defined_module0
298
+
299
+ def defined_module
300
+ namespace, name = *defined_module0
301
+ s(:const, namespace, name) if name
302
+ end
303
+
304
+ def defined_module_name
305
+ (const = defined_module) && const.const_name
306
+ end
307
+
308
+ ## Searching the AST
309
+
310
+ def parent_module_name
311
+ # what class or module is this method/constant/etc definition in?
312
+ # returns nil if answer cannot be determined
313
+ ancestors = each_ancestor(:class, :module, :sclass, :casgn, :block)
314
+ result = ancestors.map do |ancestor|
315
+ parent_module_name_part(ancestor) { |full_name| return full_name }
316
+ end.compact.reverse.join('::')
317
+ result.empty? ? 'Object' : result
318
+ end
319
+
320
+ ## Predicates
321
+
322
+ def multiline?
323
+ source_range && (source_range.first_line != source_range.last_line)
324
+ end
325
+
326
+ def single_line?
327
+ !multiline?
328
+ end
329
+
330
+ def asgn_method_call?
331
+ !COMPARISON_OPERATORS.include?(method_name) &&
332
+ method_name.to_s.end_with?('='.freeze)
333
+ end
334
+
335
+ def_matcher :equals_asgn?, '{lvasgn ivasgn cvasgn gvasgn casgn masgn}'
336
+ def_matcher :shorthand_asgn?, '{op_asgn or_asgn and_asgn}'
337
+ def_matcher :assignment?,
338
+ '{equals_asgn? shorthand_asgn? asgn_method_call?}'
339
+
340
+ def literal?
341
+ LITERALS.include?(type)
342
+ end
343
+
344
+ def basic_literal?
345
+ BASIC_LITERALS.include?(type)
346
+ end
347
+
348
+ def truthy_literal?
349
+ TRUTHY_LITERALS.include?(type)
350
+ end
351
+
352
+ def falsey_literal?
353
+ FALSEY_LITERALS.include?(type)
354
+ end
355
+
356
+ def mutable_literal?
357
+ MUTABLE_LITERALS.include?(type)
358
+ end
359
+
360
+ def immutable_literal?
361
+ IMMUTABLE_LITERALS.include?(type)
362
+ end
363
+
364
+ %i[literal basic_literal].each do |kind|
365
+ recursive_kind = :"recursive_#{kind}?"
366
+ kind_filter = :"#{kind}?"
367
+ define_method(recursive_kind) do
368
+ case type
369
+ when :send
370
+ receiver, method_name, *args = *self
371
+ COMPARISON_OPERATORS.include?(method_name) &&
372
+ receiver.send(recursive_kind) &&
373
+ args.all?(&recursive_kind)
374
+ when :begin, :pair, *OPERATOR_KEYWORDS, *COMPOSITE_LITERALS
375
+ children.all?(&recursive_kind)
376
+ else
377
+ send(kind_filter)
378
+ end
379
+ end
380
+ end
381
+
382
+ def variable?
383
+ VARIABLES.include?(type)
384
+ end
385
+
386
+ def reference?
387
+ REFERENCES.include?(type)
388
+ end
389
+
390
+ def keyword?
391
+ return true if special_keyword? || keyword_not?
392
+ return false unless KEYWORDS.include?(type)
393
+
394
+ !OPERATOR_KEYWORDS.include?(type) || loc.operator.is?(type.to_s)
395
+ end
396
+
397
+ def special_keyword?
398
+ SPECIAL_KEYWORDS.include?(source)
399
+ end
400
+
401
+ def operator_keyword?
402
+ OPERATOR_KEYWORDS.include?(type)
403
+ end
404
+
405
+ def keyword_not?
406
+ _receiver, method_name, *args = *self
407
+ args.empty? && method_name == :! && loc.selector.is?('not'.freeze)
408
+ end
409
+
410
+ def keyword_bang?
411
+ _receiver, method_name, *args = *self
412
+ args.empty? && method_name == :! && loc.selector.is?('!'.freeze)
413
+ end
414
+
415
+ def unary_operation?
416
+ return false unless loc.respond_to?(:selector) && loc.selector
417
+ Cop::Util.operator?(loc.selector.source.to_sym) &&
418
+ source_range.begin_pos == loc.selector.begin_pos
419
+ end
420
+
421
+ def binary_operation?
422
+ return false unless loc.respond_to?(:selector) && loc.selector
423
+ Cop::Util.operator?(method_name) &&
424
+ source_range.begin_pos != loc.selector.begin_pos
425
+ end
426
+
427
+ def chained?
428
+ return false unless argument?
429
+
430
+ receiver, _method_name, *_args = *parent
431
+ equal?(receiver)
432
+ end
433
+
434
+ def argument?
435
+ parent && parent.send_type?
436
+ end
437
+
438
+ def numeric_type?
439
+ int_type? || float_type?
440
+ end
441
+
442
+ def_matcher :guard_clause?, <<-PATTERN
443
+ [{(send nil {:raise :fail} ...) return break next} single_line?]
444
+ PATTERN
445
+
446
+ def_matcher :lambda?, '(block (send nil :lambda) ...)'
447
+ def_matcher :proc?, <<-PATTERN
448
+ {(block (send nil :proc) ...)
449
+ (block (send (const nil :Proc) :new) ...)
450
+ (send (const nil :Proc) :new)}
451
+ PATTERN
452
+ def_matcher :lambda_or_proc?, '{lambda? proc?}'
453
+
454
+ def_matcher :class_constructor?, <<-PATTERN
455
+ { (send (const nil {:Class :Module}) :new ...)
456
+ (block (send (const nil {:Class :Module}) :new ...) ...)}
457
+ PATTERN
458
+
459
+ def_matcher :module_definition?, <<-PATTERN
460
+ {class module (casgn _ _ class_constructor?)}
461
+ PATTERN
462
+
463
+ # Some expressions are evaluated for their value, some for their side
464
+ # effects, and some for both
465
+ # If we know that an expression is useful only for its side effects, that
466
+ # means we can transform it in ways which preserve the side effects, but
467
+ # change the return value
468
+ # So, does the return value of this node matter? If we changed it to
469
+ # `(...; nil)`, might that affect anything?
470
+ #
471
+ # rubbycop:disable Metrics/MethodLength
472
+ def value_used?
473
+ # Be conservative and return true if we're not sure.
474
+ return false if parent.nil?
475
+
476
+ case parent.type
477
+ when :array, :defined?, :dstr, :dsym, :eflipflop, :erange, :float,
478
+ :hash, :iflipflop, :irange, :not, :pair, :regexp, :str, :sym,
479
+ :when, :xstr
480
+ parent.value_used?
481
+ when :begin, :kwbegin
482
+ begin_value_used?
483
+ when :for
484
+ for_value_used?
485
+ when :case, :if
486
+ case_if_value_used?
487
+ when :while, :until, :while_post, :until_post
488
+ while_until_value_used?
489
+ else
490
+ true
491
+ end
492
+ end
493
+ # rubbycop:enable Metrics/MethodLength
494
+
495
+ # Some expressions are evaluated for their value, some for their side
496
+ # effects, and some for both.
497
+ # If we know that expressions are useful only for their return values,
498
+ # and have no side effects, that means we can reorder them, change the
499
+ # number of times they are evaluated, or replace them with other
500
+ # expressions which are equivalent in value.
501
+ # So, is evaluation of this node free of side effects?
502
+ #
503
+ def pure?
504
+ # Be conservative and return false if we're not sure
505
+ case type
506
+ when :__FILE__, :__LINE__, :const, :cvar, :defined?, :false, :float,
507
+ :gvar, :int, :ivar, :lvar, :nil, :str, :sym, :true, :regopt
508
+ true
509
+ when :and, :array, :begin, :case, :dstr, :dsym, :eflipflop, :ensure,
510
+ :erange, :for, :hash, :if, :iflipflop, :irange, :kwbegin, :not,
511
+ :or, :pair, :regexp, :until, :until_post, :when, :while,
512
+ :while_post
513
+ child_nodes.all?(&:pure?)
514
+ else
515
+ false
516
+ end
517
+ end
518
+
519
+ protected
520
+
521
+ def visit_descendants(types, &block)
522
+ each_child_node do |child|
523
+ yield child if types.empty? || types.include?(child.type)
524
+ child.visit_descendants(types, &block)
525
+ end
526
+ end
527
+
528
+ private
529
+
530
+ def visit_ancestors(types)
531
+ last_node = self
532
+
533
+ while (current_node = last_node.parent)
534
+ yield current_node if types.empty? ||
535
+ types.include?(current_node.type)
536
+ last_node = current_node
537
+ end
538
+ end
539
+
540
+ def begin_value_used?
541
+ # the last child node determines the value of the parent
542
+ sibling_index == parent.children.size - 1 ? parent.value_used? : false
543
+ end
544
+
545
+ def for_value_used?
546
+ # `for var in enum; body; end`
547
+ # (for <var> <enum> <body>)
548
+ sibling_index == 2 ? parent.value_used? : true
549
+ end
550
+
551
+ def case_if_value_used?
552
+ # (case <condition> <when...>)
553
+ # (if <condition> <truebranch> <falsebranch>)
554
+ sibling_index.zero? ? true : parent.value_used?
555
+ end
556
+
557
+ def while_until_value_used?
558
+ # (while <condition> <body>) -> always evaluates to `nil`
559
+ sibling_index.zero?
560
+ end
561
+
562
+ def parent_module_name_part(node)
563
+ case node.type
564
+ when :class, :module, :casgn
565
+ # TODO: if constant name has cbase (leading ::), then we don't need
566
+ # to keep traversing up through nested classes/modules
567
+ node.defined_module_name
568
+ when :sclass
569
+ yield parent_module_name_for_sclass(node)
570
+ else # block
571
+ parent_module_name_for_block(node) { yield nil }
572
+ end
573
+ end
574
+
575
+ def parent_module_name_for_sclass(sclass_node)
576
+ # TODO: look for constant definition and see if it is nested
577
+ # inside a class or module
578
+ subject = sclass_node.children[0]
579
+
580
+ if subject.const_type?
581
+ "#<Class:#{subject.const_name}>"
582
+ elsif subject.self_type?
583
+ "#<Class:#{sclass_node.parent_module_name}>"
584
+ end
585
+ end
586
+
587
+ def parent_module_name_for_block(ancestor)
588
+ if ancestor.method_name == :class_eval
589
+ # `class_eval` with no receiver applies to whatever module or class
590
+ # we are currently in
591
+ return unless (receiver = ancestor.receiver)
592
+ yield unless receiver.const_type?
593
+ receiver.const_name
594
+ elsif !new_class_or_module_block?(ancestor)
595
+ yield
596
+ end
597
+ end
598
+
599
+ def new_class_or_module_block?(block_node)
600
+ receiver = block_node.receiver
601
+
602
+ block_node.method_name == :new &&
603
+ receiver && receiver.const_type? &&
604
+ (receiver.const_name == 'Class' || receiver.const_name == 'Module') &&
605
+ block_node.parent &&
606
+ block_node.parent.casgn_type?
607
+ end
608
+ end
609
+ end
610
+ end