rubbycop 0.49.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 (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