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,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tmpdir'
4
+ require 'fileutils'
5
+
6
+ shared_context 'isolated environment', :isolated_environment do
7
+ around do |example|
8
+ Dir.mktmpdir do |tmpdir|
9
+ original_home = ENV['HOME']
10
+
11
+ # Make sure to expand all symlinks in the path first. Otherwise we may
12
+ # get mismatched pathnames when loading config files later on.
13
+ tmpdir = File.realpath(tmpdir)
14
+
15
+ # Make upwards search for .rubbycop.yml files stop at this directory.
16
+ RubbyCop::ConfigLoader.root_level = tmpdir
17
+
18
+ begin
19
+ virtual_home = File.expand_path(File.join(tmpdir, 'home'))
20
+ Dir.mkdir(virtual_home)
21
+ ENV['HOME'] = virtual_home
22
+
23
+ working_dir = File.join(tmpdir, 'work')
24
+ Dir.mkdir(working_dir)
25
+
26
+ Dir.chdir(working_dir) do
27
+ example.run
28
+ end
29
+ ensure
30
+ ENV['HOME'] = original_home
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # `cop_config` must be declared with #let.
37
+ shared_context 'config', :config do
38
+ let(:config) do
39
+ # Module#<
40
+ unless described_class < RubbyCop::Cop::Cop
41
+ raise '`config` must be used in `describe SomeCopClass do .. end`'
42
+ end
43
+
44
+ hash = { 'AllCops' => { 'TargetRubyVersion' => ruby_version } }
45
+ hash['Rails'] = { 'Enabled' => true } if enabled_rails
46
+ hash['AllCops']['TargetRailsVersion'] = rails_version if rails_version
47
+ if respond_to?(:cop_config)
48
+ cop_name = described_class.cop_name
49
+ hash[cop_name] = RubbyCop::ConfigLoader
50
+ .default_configuration[cop_name]
51
+ .merge(cop_config)
52
+ end
53
+
54
+ hash = other_cops.merge hash if respond_to?(:other_cops)
55
+
56
+ RubbyCop::Config.new(hash, "#{Dir.pwd}/.rubbycop.yml")
57
+ end
58
+ end
59
+
60
+ shared_context 'ruby 1.9', :ruby19 do
61
+ let(:ruby_version) { 1.9 }
62
+ end
63
+
64
+ shared_context 'ruby 2.0', :ruby20 do
65
+ let(:ruby_version) { 2.0 }
66
+ end
67
+
68
+ shared_context 'ruby 2.1', :ruby21 do
69
+ let(:ruby_version) { 2.1 }
70
+ end
71
+
72
+ shared_context 'ruby 2.2', :ruby22 do
73
+ let(:ruby_version) { 2.2 }
74
+ end
75
+
76
+ shared_context 'ruby 2.3', :ruby23 do
77
+ let(:ruby_version) { 2.3 }
78
+ end
79
+
80
+ shared_context 'ruby 2.4', :ruby24 do
81
+ let(:ruby_version) { 2.4 }
82
+ end
83
+
84
+ shared_context 'with Rails', :enabled_rails do
85
+ let(:enabled_rails) { true }
86
+ end
87
+
88
+ shared_context 'with Rails 3', :rails3 do
89
+ let(:rails_version) { 3.0 }
90
+ end
91
+
92
+ shared_context 'with Rails 4', :rails4 do
93
+ let(:rails_version) { 4.0 }
94
+ end
95
+
96
+ shared_context 'with Rails 5', :rails5 do
97
+ let(:rails_version) { 5.0 }
98
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ # `cop` and `source` must be declared with #let.
4
+
5
+ shared_examples_for 'accepts' do
6
+ it 'accepts' do
7
+ inspect_source(cop, source)
8
+ expect(cop.offenses).to be_empty
9
+ end
10
+ end
11
+
12
+ shared_examples_for 'mimics MRI 2.1' do |grep_mri_warning|
13
+ if RUBY_ENGINE == 'ruby' && RUBY_VERSION.start_with?('2.1')
14
+ it "mimics MRI #{RUBY_VERSION} built-in syntax checking" do
15
+ inspect_source(cop, source)
16
+ offenses_by_mri = MRISyntaxChecker.offenses_for_source(
17
+ source, cop.name, grep_mri_warning
18
+ )
19
+
20
+ # Compare objects before comparing counts for clear failure output.
21
+ cop.offenses.each_with_index do |offense_by_cop, index|
22
+ offense_by_mri = offenses_by_mri[index]
23
+ # Exclude column attribute since MRI does not
24
+ # output column number.
25
+ %i[severity line cop_name].each do |a|
26
+ expect(offense_by_cop.send(a)).to eq(offense_by_mri.send(a))
27
+ end
28
+ end
29
+
30
+ expect(cop.offenses.count).to eq(offenses_by_mri.count)
31
+ end
32
+ end
33
+ end
34
+
35
+ shared_examples_for 'misaligned' do |prefix, alignment_base, arg, end_kw, name|
36
+ name ||= alignment_base
37
+ source = ["#{prefix}#{alignment_base} #{arg}",
38
+ end_kw]
39
+
40
+ it "registers an offense for mismatched #{name} ... end" do
41
+ inspect_source(cop, source)
42
+ expect(cop.offenses.size).to eq(1)
43
+ base_regexp = Regexp.escape(alignment_base)
44
+ regexp = /`end` at 2, \d+ is not aligned with `#{base_regexp}` at 1,/
45
+ expect(cop.messages.first).to match(regexp)
46
+ expect(cop.highlights.first).to eq('end')
47
+
48
+ other_styles = (cop.supported_styles - [cop.style]).map(&:to_s)
49
+ # In some cases, the code under test will happen to match an alternative
50
+ # style. In other cases, it won't match any style at all
51
+ expect(cop.config_to_allow_offenses).to(
52
+ eq('Enabled' => false).or(
53
+ satisfy { |h| other_styles.include?(h['EnforcedStyleAlignWith']) }
54
+ )
55
+ )
56
+ end
57
+
58
+ it "auto-corrects mismatched #{name} ... end" do
59
+ aligned_source = ["#{prefix}#{alignment_base} #{arg}",
60
+ "#{' ' * prefix.length}#{end_kw.strip}"].join("\n")
61
+ corrected = autocorrect_source(cop, source)
62
+ expect(corrected).to eq(aligned_source)
63
+ end
64
+ end
65
+
66
+ shared_examples_for 'aligned' do |alignment_base, arg, end_kw, name|
67
+ name ||= alignment_base
68
+ name = name.gsub(/\n/, ' <newline>')
69
+ it "accepts matching #{name} ... end" do
70
+ inspect_source(cop, ["#{alignment_base} #{arg}",
71
+ end_kw])
72
+ expect(cop.offenses).to be_empty
73
+ end
74
+ end
75
+
76
+ shared_examples_for 'debugger' do |name, src|
77
+ it "reports an offense for a #{name} call" do
78
+ inspect_source(cop, src)
79
+ src = [src] if src.is_a? String
80
+ expect(cop.offenses.size).to eq(src.size)
81
+ expect(cop.messages)
82
+ .to eq(src.map { |s| "Remove debugger entry point `#{s}`." })
83
+ expect(cop.highlights).to eq(src)
84
+ end
85
+ end
86
+
87
+ shared_examples_for 'non-debugger' do |name, src|
88
+ it "does not report an offense for #{name}" do
89
+ inspect_source(cop, src)
90
+ expect(cop.offenses).to be_empty
91
+ end
92
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Require this file to load code that supports testing using RSpec.
4
+
5
+ require 'rubbycop/rspec/cop_helper'
6
+ require 'rubbycop/rspec/host_environment_simulation_helper'
7
+ require 'rubbycop/rspec/shared_contexts'
8
+ require 'rubbycop/rspec/shared_examples'
@@ -0,0 +1,338 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parallel'
4
+
5
+ module RubbyCop
6
+ # This class handles the processing of files, which includes dealing with
7
+ # formatters and letting cops inspect the files.
8
+ class Runner # rubbycop:disable Metrics/ClassLength
9
+ # An exception indicating that the inspection loop got stuck correcting
10
+ # offenses back and forth.
11
+ class InfiniteCorrectionLoop < RuntimeError
12
+ attr_reader :offenses
13
+
14
+ def initialize(path, offenses)
15
+ super "Infinite loop detected in #{path}."
16
+ @offenses = offenses
17
+ end
18
+ end
19
+
20
+ MAX_ITERATIONS = 200
21
+
22
+ attr_reader :errors, :warnings, :aborting
23
+ alias aborting? aborting
24
+
25
+ def initialize(options, config_store)
26
+ @options = options
27
+ @config_store = config_store
28
+ @errors = []
29
+ @warnings = []
30
+ @aborting = false
31
+ end
32
+
33
+ def run(paths)
34
+ target_files = find_target_files(paths)
35
+ if @options[:list_target_files]
36
+ list_files(target_files)
37
+ else
38
+ warm_cache(target_files) if @options[:parallel]
39
+ inspect_files(target_files)
40
+ end
41
+ end
42
+
43
+ def abort
44
+ @aborting = true
45
+ end
46
+
47
+ private
48
+
49
+ # Warms up the RubbyCop cache by forking a suitable number of rubbycop
50
+ # instances that each inspects its alotted group of files.
51
+ def warm_cache(target_files)
52
+ puts 'Running parallel inspection'
53
+ Parallel.each(target_files, &method(:file_offenses))
54
+ end
55
+
56
+ def find_target_files(paths)
57
+ target_finder = TargetFinder.new(@config_store, @options)
58
+ target_files = target_finder.find(paths)
59
+ target_files.each(&:freeze).freeze
60
+ end
61
+
62
+ def inspect_files(files)
63
+ inspected_files = []
64
+
65
+ formatter_set.started(files)
66
+
67
+ each_inspected_file(files) { |file| inspected_files << file }
68
+ ensure
69
+ ResultCache.cleanup(@config_store, @options[:debug]) if cached_run?
70
+ formatter_set.finished(inspected_files.freeze)
71
+ formatter_set.close_output_files
72
+ end
73
+
74
+ def each_inspected_file(files)
75
+ files.reduce(true) do |all_passed, file|
76
+ break false if aborting?
77
+
78
+ offenses = process_file(file)
79
+ yield file
80
+
81
+ if offenses.any? { |o| considered_failure?(o) }
82
+ break false if @options[:fail_fast]
83
+ next false
84
+ end
85
+
86
+ all_passed
87
+ end
88
+ end
89
+
90
+ def list_files(paths)
91
+ paths.each do |path|
92
+ puts PathUtil.relative_path(path)
93
+ end
94
+ end
95
+
96
+ def process_file(file)
97
+ puts "Scanning #{file}" if @options[:debug]
98
+ file_started(file)
99
+
100
+ offenses = file_offenses(file)
101
+ formatter_set.file_finished(file, offenses)
102
+ offenses
103
+ rescue InfiniteCorrectionLoop => e
104
+ formatter_set.file_finished(file, e.offenses.compact.sort.freeze)
105
+ raise
106
+ end
107
+
108
+ def file_offenses(file)
109
+ file_offense_cache(file) do
110
+ source = get_processed_source(file)
111
+ source, offenses = do_inspection_loop(file, source)
112
+ add_unneeded_disables(file, offenses.compact.sort, source)
113
+ end
114
+ end
115
+
116
+ def file_offense_cache(file)
117
+ cache = ResultCache.new(file, @options, @config_store) if cached_run?
118
+ if cache && cache.valid?
119
+ offenses = cache.load
120
+ else
121
+ offenses = yield
122
+ save_in_cache(cache, offenses)
123
+ end
124
+
125
+ offenses
126
+ end
127
+
128
+ def add_unneeded_disables(file, offenses, source)
129
+ if check_for_unneded_disables?(source)
130
+ config = @config_store.for(file)
131
+ if config.for_cop(Cop::Lint::UnneededDisable).fetch('Enabled')
132
+ cop = Cop::Lint::UnneededDisable.new(config, @options)
133
+ if cop.relevant_file?(file)
134
+ cop.check(offenses, source.disabled_line_ranges, source.comments)
135
+ offenses += cop.offenses
136
+ autocorrect_unneeded_disables(source, cop)
137
+ end
138
+ end
139
+ offenses
140
+ end
141
+
142
+ offenses.sort.reject(&:disabled?).freeze
143
+ end
144
+
145
+ def check_for_unneded_disables?(source)
146
+ !source.disabled_line_ranges.empty? && !filtered_run?
147
+ end
148
+
149
+ def filtered_run?
150
+ @options[:except] || @options[:only]
151
+ end
152
+
153
+ def autocorrect_unneeded_disables(source, cop)
154
+ cop.processed_source = source
155
+
156
+ Cop::Team.new(
157
+ RubbyCop::Cop::Registry.new,
158
+ nil,
159
+ @options
160
+ ).autocorrect(source.buffer, [cop])
161
+ end
162
+
163
+ def file_started(file)
164
+ formatter_set.file_started(file,
165
+ cli_options: @options,
166
+ config_store: @config_store)
167
+ end
168
+
169
+ def cached_run?
170
+ @cached_run ||=
171
+ (@options[:cache] == 'true' ||
172
+ @options[:cache] != 'false' &&
173
+ @config_store.for(Dir.pwd).for_all_cops['UseCache']) &&
174
+ # When running --auto-gen-config, there's some processing done in the
175
+ # cops related to calculating the Max parameters for Metrics cops. We
176
+ # need to do that processing and can not use caching.
177
+ !@options[:auto_gen_config] &&
178
+ # Auto-correction needs a full run. It can not use cached results.
179
+ !@options[:auto_correct] &&
180
+ # We can't cache results from code which is piped in to stdin
181
+ !@options[:stdin]
182
+ end
183
+
184
+ def save_in_cache(cache, offenses)
185
+ return unless cache
186
+ # Caching results when a cop has crashed would prevent the crash in the
187
+ # next run, since the cop would not be called then. We want crashes to
188
+ # show up the same in each run.
189
+ return if errors.any? || warnings.any?
190
+
191
+ cache.save(offenses)
192
+ end
193
+
194
+ def do_inspection_loop(file, processed_source)
195
+ offenses = []
196
+
197
+ # When running with --auto-correct, we need to inspect the file (which
198
+ # includes writing a corrected version of it) until no more corrections
199
+ # are made. This is because automatic corrections can introduce new
200
+ # offenses. In the normal case the loop is only executed once.
201
+ iterate_until_no_changes(processed_source, offenses) do
202
+ # The offenses that couldn't be corrected will be found again so we
203
+ # only keep the corrected ones in order to avoid duplicate reporting.
204
+ offenses.select!(&:corrected?)
205
+ new_offenses, updated_source_file = inspect_file(processed_source)
206
+ offenses.concat(new_offenses).uniq!
207
+
208
+ # We have to reprocess the source to pickup the changes. Since the
209
+ # change could (theoretically) introduce parsing errors, we break the
210
+ # loop if we find any.
211
+ break unless updated_source_file
212
+
213
+ processed_source = get_processed_source(file)
214
+ end
215
+
216
+ [processed_source, offenses]
217
+ end
218
+
219
+ def iterate_until_no_changes(source, offenses)
220
+ # Keep track of the state of the source. If a cop modifies the source
221
+ # and another cop undoes it producing identical source we have an
222
+ # infinite loop.
223
+ @processed_sources = []
224
+
225
+ # It is also possible for a cop to keep adding indefinitely to a file,
226
+ # making it bigger and bigger. If the inspection loop runs for an
227
+ # excessively high number of iterations, this is likely happening.
228
+ iterations = 0
229
+
230
+ loop do
231
+ check_for_infinite_loop(source, offenses)
232
+
233
+ if (iterations += 1) > MAX_ITERATIONS
234
+ raise InfiniteCorrectionLoop.new(source.path, offenses)
235
+ end
236
+
237
+ source = yield
238
+ break unless source
239
+ end
240
+ end
241
+
242
+ # Check whether a run created source identical to a previous run, which
243
+ # means that we definitely have an infinite loop.
244
+ def check_for_infinite_loop(processed_source, offenses)
245
+ checksum = processed_source.checksum
246
+
247
+ if @processed_sources.include?(checksum)
248
+ raise InfiniteCorrectionLoop.new(processed_source.path, offenses)
249
+ end
250
+
251
+ @processed_sources << checksum
252
+ end
253
+
254
+ def inspect_file(processed_source)
255
+ config = @config_store.for(processed_source.path)
256
+ enable_rails_cops(config) if @options[:rails]
257
+ team = Cop::Team.new(mobilized_cop_classes(config), config, @options)
258
+ offenses = team.inspect_file(processed_source)
259
+ @errors.concat(team.errors)
260
+ @warnings.concat(team.warnings)
261
+ [offenses, team.updated_source_file?]
262
+ end
263
+
264
+ def enable_rails_cops(config)
265
+ config['Rails'] ||= {}
266
+ config['Rails']['Enabled'] = true
267
+ end
268
+
269
+ def mobilized_cop_classes(config)
270
+ @mobilized_cop_classes ||= {}
271
+ @mobilized_cop_classes[config.object_id] ||= begin
272
+ cop_classes = Cop::Cop.all
273
+
274
+ %i[only except].each do |opt|
275
+ OptionsValidator.validate_cop_list(@options[opt])
276
+ end
277
+
278
+ if @options[:only]
279
+ cop_classes.select! { |c| c.match?(@options[:only]) }
280
+ else
281
+ filter_cop_classes(cop_classes, config)
282
+ end
283
+
284
+ cop_classes.reject! { |c| c.match?(@options[:except]) }
285
+
286
+ Cop::Registry.new(cop_classes)
287
+ end
288
+ end
289
+
290
+ def filter_cop_classes(cop_classes, config)
291
+ # use only cops that link to a style guide if requested
292
+ return unless style_guide_cops_only?(config)
293
+
294
+ cop_classes.select! { |cop| config.for_cop(cop)['StyleGuide'] }
295
+ end
296
+
297
+ def style_guide_cops_only?(config)
298
+ @options[:only_guide_cops] || config.for_all_cops['StyleGuideCopsOnly']
299
+ end
300
+
301
+ def formatter_set
302
+ @formatter_set ||= begin
303
+ set = Formatter::FormatterSet.new(@options)
304
+ pairs = @options[:formatters] || [['progress']]
305
+ pairs.each do |formatter_key, output_path|
306
+ set.add_formatter(formatter_key, output_path)
307
+ end
308
+ set
309
+ end
310
+ end
311
+
312
+ def considered_failure?(offense)
313
+ # For :autocorrect level, any offense - corrected or not - is a failure.
314
+ return false if offense.disabled?
315
+
316
+ return true if @options[:fail_level] == :autocorrect
317
+
318
+ !offense.corrected? && offense.severity >= minimum_severity_to_fail
319
+ end
320
+
321
+ def minimum_severity_to_fail
322
+ @minimum_severity_to_fail ||= begin
323
+ name = @options[:fail_level] || :refactor
324
+ RubbyCop::Cop::Severity.new(name)
325
+ end
326
+ end
327
+
328
+ def get_processed_source(file)
329
+ ruby_version = @config_store.for(file).target_ruby_version
330
+
331
+ if @options[:stdin]
332
+ ProcessedSource.new(@options[:stdin], ruby_version, file)
333
+ else
334
+ ProcessedSource.from_file(file, ruby_version)
335
+ end
336
+ end
337
+ end
338
+ end