rubocop 0.88.0 → 0.89.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 (239) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/rubocop-profile +1 -0
  4. data/config/default.yml +96 -16
  5. data/lib/rubocop.rb +16 -4
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  7. data/lib/rubocop/cli/command/base.rb +1 -0
  8. data/lib/rubocop/cli/command/execute_runner.rb +1 -1
  9. data/lib/rubocop/cli/command/show_cops.rb +1 -1
  10. data/lib/rubocop/cli/command/version.rb +2 -2
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +19 -2
  13. data/lib/rubocop/config_loader.rb +1 -1
  14. data/lib/rubocop/config_loader_resolver.rb +3 -3
  15. data/lib/rubocop/config_obsoletion.rb +6 -1
  16. data/lib/rubocop/config_validator.rb +1 -3
  17. data/lib/rubocop/cop/base.rb +2 -2
  18. data/lib/rubocop/cop/commissioner.rb +0 -1
  19. data/lib/rubocop/cop/correctors/line_break_corrector.rb +3 -3
  20. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  21. data/lib/rubocop/cop/correctors/punctuation_corrector.rb +1 -1
  22. data/lib/rubocop/cop/correctors/unused_arg_corrector.rb +15 -18
  23. data/lib/rubocop/cop/force.rb +1 -0
  24. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +32 -11
  25. data/lib/rubocop/cop/generator/configuration_injector.rb +2 -2
  26. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +4 -12
  27. data/lib/rubocop/cop/internal_affairs/node_destructuring.rb +1 -1
  28. data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +8 -8
  29. data/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +10 -7
  30. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +7 -8
  31. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -2
  32. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  33. data/lib/rubocop/cop/layout/empty_lines.rb +0 -2
  34. data/lib/rubocop/cop/layout/extra_spacing.rb +9 -16
  35. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -1
  36. data/lib/rubocop/cop/layout/heredoc_indentation.rb +2 -2
  37. data/lib/rubocop/cop/layout/indentation_style.rb +0 -2
  38. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
  39. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +0 -2
  40. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +9 -1
  41. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +7 -4
  42. data/lib/rubocop/cop/lint/ambiguous_operator.rb +15 -10
  43. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +11 -13
  44. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -2
  45. data/lib/rubocop/cop/lint/big_decimal_new.rb +10 -10
  46. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +49 -0
  47. data/lib/rubocop/cop/lint/boolean_symbol.rb +16 -11
  48. data/lib/rubocop/cop/lint/circular_argument_reference.rb +1 -1
  49. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  50. data/lib/rubocop/cop/lint/debugger.rb +7 -1
  51. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +9 -10
  52. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +17 -13
  53. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
  54. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +1 -1
  55. data/lib/rubocop/cop/lint/duplicate_methods.rb +7 -4
  56. data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +60 -0
  57. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  58. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  59. data/lib/rubocop/cop/lint/empty_conditional_body.rb +67 -0
  60. data/lib/rubocop/cop/lint/empty_ensure.rb +5 -5
  61. data/lib/rubocop/cop/lint/empty_expression.rb +2 -2
  62. data/lib/rubocop/cop/lint/empty_interpolation.rb +5 -6
  63. data/lib/rubocop/cop/lint/empty_when.rb +2 -2
  64. data/lib/rubocop/cop/lint/ensure_return.rb +27 -29
  65. data/lib/rubocop/cop/lint/erb_new_arguments.rb +11 -10
  66. data/lib/rubocop/cop/lint/flip_flop.rb +1 -1
  67. data/lib/rubocop/cop/lint/float_comparison.rb +93 -0
  68. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  69. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -4
  70. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +13 -14
  71. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +2 -2
  72. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +8 -8
  73. data/lib/rubocop/cop/lint/inherit_exception.rb +12 -7
  74. data/lib/rubocop/cop/lint/interpolation_check.rb +18 -15
  75. data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -2
  76. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -7
  77. data/lib/rubocop/cop/lint/loop.rb +23 -2
  78. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +6 -5
  79. data/lib/rubocop/cop/lint/missing_super.rb +99 -0
  80. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  81. data/lib/rubocop/cop/lint/multiple_comparison.rb +6 -9
  82. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  83. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  84. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  85. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +27 -23
  86. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
  87. data/lib/rubocop/cop/lint/number_conversion.rb +6 -9
  88. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +11 -13
  89. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +61 -0
  90. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +4 -10
  91. data/lib/rubocop/cop/lint/percent_string_array.rb +13 -12
  92. data/lib/rubocop/cop/lint/percent_symbol_array.rb +13 -12
  93. data/lib/rubocop/cop/lint/raise_exception.rb +12 -10
  94. data/lib/rubocop/cop/lint/rand_one.rb +2 -2
  95. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -2
  96. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +7 -11
  97. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -7
  98. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -9
  99. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +6 -13
  100. data/lib/rubocop/cop/lint/redundant_with_index.rb +11 -14
  101. data/lib/rubocop/cop/lint/redundant_with_object.rb +11 -14
  102. data/lib/rubocop/cop/lint/regexp_as_condition.rb +4 -6
  103. data/lib/rubocop/cop/lint/require_parentheses.rb +2 -2
  104. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  105. data/lib/rubocop/cop/lint/rescue_type.rb +8 -8
  106. data/lib/rubocop/cop/lint/return_in_void_context.rb +2 -4
  107. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -6
  108. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +14 -10
  109. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +7 -7
  110. data/lib/rubocop/cop/lint/script_permission.rb +10 -7
  111. data/lib/rubocop/cop/lint/self_assignment.rb +78 -0
  112. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -11
  113. data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -3
  114. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -2
  115. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +3 -3
  116. data/lib/rubocop/cop/lint/struct_new_override.rb +1 -1
  117. data/lib/rubocop/cop/lint/suppressed_exception.rb +4 -7
  118. data/lib/rubocop/cop/lint/to_json.rb +4 -6
  119. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +34 -0
  120. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +4 -4
  121. data/lib/rubocop/cop/lint/unified_integer.rb +4 -6
  122. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  123. data/lib/rubocop/cop/lint/unreachable_loop.rb +174 -0
  124. data/lib/rubocop/cop/lint/unused_block_argument.rb +8 -3
  125. data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -3
  126. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +1 -1
  127. data/lib/rubocop/cop/lint/uri_regexp.rb +11 -31
  128. data/lib/rubocop/cop/lint/useless_access_modifier.rb +25 -15
  129. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -4
  130. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +6 -15
  131. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -6
  132. data/lib/rubocop/cop/lint/void.rb +3 -7
  133. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  134. data/lib/rubocop/cop/metrics/block_length.rb +2 -2
  135. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  136. data/lib/rubocop/cop/metrics/class_length.rb +2 -2
  137. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +2 -1
  138. data/lib/rubocop/cop/metrics/method_length.rb +2 -2
  139. data/lib/rubocop/cop/metrics/module_length.rb +2 -2
  140. data/lib/rubocop/cop/metrics/parameter_lists.rb +2 -6
  141. data/lib/rubocop/cop/metrics/perceived_complexity.rb +7 -8
  142. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +48 -5
  143. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +52 -24
  144. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +37 -0
  145. data/lib/rubocop/cop/migration/department_name.rb +13 -15
  146. data/lib/rubocop/cop/mixin/array_min_size.rb +1 -1
  147. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  148. data/lib/rubocop/cop/mixin/code_length.rb +22 -5
  149. data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -0
  150. data/lib/rubocop/cop/mixin/method_complexity.rb +10 -2
  151. data/lib/rubocop/cop/mixin/statement_modifier.rb +35 -6
  152. data/lib/rubocop/cop/mixin/surrounding_space.rb +0 -25
  153. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +6 -13
  154. data/lib/rubocop/cop/mixin/unused_argument.rb +4 -6
  155. data/lib/rubocop/cop/naming/accessor_method_name.rb +4 -2
  156. data/lib/rubocop/cop/naming/ascii_identifiers.rb +3 -3
  157. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  158. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  159. data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -2
  160. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  161. data/lib/rubocop/cop/naming/file_name.rb +3 -3
  162. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +2 -2
  163. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +2 -2
  164. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  165. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  166. data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
  167. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -11
  168. data/lib/rubocop/cop/registry.rb +3 -3
  169. data/lib/rubocop/cop/security/eval.rb +2 -2
  170. data/lib/rubocop/cop/security/json_load.rb +6 -8
  171. data/lib/rubocop/cop/security/marshal_load.rb +2 -4
  172. data/lib/rubocop/cop/security/open.rb +2 -2
  173. data/lib/rubocop/cop/security/yaml_load.rb +6 -6
  174. data/lib/rubocop/cop/style/access_modifier_declarations.rb +11 -1
  175. data/lib/rubocop/cop/style/accessor_grouping.rb +9 -7
  176. data/lib/rubocop/cop/style/alias.rb +7 -3
  177. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -2
  178. data/lib/rubocop/cop/style/case_equality.rb +22 -3
  179. data/lib/rubocop/cop/style/case_like_if.rb +2 -2
  180. data/lib/rubocop/cop/style/colon_method_call.rb +3 -3
  181. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -2
  182. data/lib/rubocop/cop/style/documentation.rb +4 -4
  183. data/lib/rubocop/cop/style/each_with_object.rb +0 -2
  184. data/lib/rubocop/cop/style/empty_method.rb +5 -5
  185. data/lib/rubocop/cop/style/eval_with_location.rb +4 -0
  186. data/lib/rubocop/cop/style/expand_path_arguments.rb +4 -0
  187. data/lib/rubocop/cop/style/explicit_block_argument.rb +102 -0
  188. data/lib/rubocop/cop/style/format_string.rb +4 -0
  189. data/lib/rubocop/cop/style/format_string_token.rb +1 -0
  190. data/lib/rubocop/cop/style/global_std_stream.rb +65 -0
  191. data/lib/rubocop/cop/style/guard_clause.rb +2 -2
  192. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +8 -1
  193. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  194. data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
  195. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  196. data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -20
  197. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  198. data/lib/rubocop/cop/style/inverse_methods.rb +2 -3
  199. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -0
  200. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -1
  201. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +9 -2
  202. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  203. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  204. data/lib/rubocop/cop/style/numeric_predicate.rb +4 -0
  205. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +42 -0
  206. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  207. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -2
  208. data/lib/rubocop/cop/style/random_with_offset.rb +1 -0
  209. data/lib/rubocop/cop/style/redundant_condition.rb +15 -3
  210. data/lib/rubocop/cop/style/redundant_exception.rb +4 -0
  211. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +9 -9
  212. data/lib/rubocop/cop/style/redundant_sort.rb +25 -10
  213. data/lib/rubocop/cop/style/signal_exception.rb +2 -0
  214. data/lib/rubocop/cop/style/single_argument_dig.rb +54 -0
  215. data/lib/rubocop/cop/style/string_concatenation.rb +92 -0
  216. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  217. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  218. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  219. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -1
  220. data/lib/rubocop/cop/style/zero_length_predicate.rb +10 -6
  221. data/lib/rubocop/cop/team.rb +1 -1
  222. data/lib/rubocop/cop/tokens_util.rb +84 -0
  223. data/lib/rubocop/cop/util.rb +1 -13
  224. data/lib/rubocop/cop/variable_force.rb +0 -2
  225. data/lib/rubocop/cop/variable_force/branch.rb +1 -0
  226. data/lib/rubocop/cop/variable_force/variable.rb +2 -2
  227. data/lib/rubocop/cops_documentation_generator.rb +282 -0
  228. data/lib/rubocop/error.rb +1 -0
  229. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  230. data/lib/rubocop/path_util.rb +19 -4
  231. data/lib/rubocop/rake_task.rb +1 -0
  232. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  233. data/lib/rubocop/target_finder.rb +12 -9
  234. data/lib/rubocop/version.rb +2 -2
  235. metadata +19 -6
  236. data/lib/rubocop/cop/lint/useless_comparison.rb +0 -28
  237. data/lib/rubocop/cop/mixin/parser_diagnostic.rb +0 -37
  238. data/lib/rubocop/cop/mixin/too_many_lines.rb +0 -25
  239. data/lib/rubocop/cop/style/method_missing_super.rb +0 -34
@@ -10,10 +10,11 @@ module RuboCop
10
10
  include Util
11
11
 
12
12
  FOLDABLE_TYPES = %i[array hash heredoc].freeze
13
- CLASSISH_TYPES = %i[class module].freeze
13
+ CLASSLIKE_TYPES = %i[class module].freeze
14
14
 
15
- def initialize(node, count_comments: false, foldable_types: [])
15
+ def initialize(node, processed_source, count_comments: false, foldable_types: [])
16
16
  @node = node
17
+ @processed_source = processed_source
17
18
  @count_comments = count_comments
18
19
  @foldable_checks = build_foldable_checks(foldable_types)
19
20
  @foldable_types = normalize_foldable_types(foldable_types)
@@ -21,13 +22,11 @@ module RuboCop
21
22
 
22
23
  def calculate
23
24
  length = code_length(@node)
25
+ return length if @foldable_types.empty?
24
26
 
25
- each_top_level_descendant(@node, *@foldable_types, *CLASSISH_TYPES) do |descendant|
26
- descendant_length = code_length(descendant)
27
-
28
- if classlike_node?(descendant)
29
- length -= (descendant_length + 2)
30
- elsif foldable_node?(descendant)
27
+ each_top_level_descendant(@node, @foldable_types) do |descendant|
28
+ if foldable_node?(descendant)
29
+ descendant_length = code_length(descendant)
31
30
  length = length - descendant_length + 1
32
31
  end
33
32
  end
@@ -37,14 +36,6 @@ module RuboCop
37
36
 
38
37
  private
39
38
 
40
- def_node_matcher :class_definition?, <<~PATTERN
41
- (casgn nil? _ (block (send (const nil? :Class) :new) ...))
42
- PATTERN
43
-
44
- def_node_matcher :module_definition?, <<~PATTERN
45
- (casgn nil? _ (block (send (const nil? :Module) :new) ...))
46
- PATTERN
47
-
48
39
  def build_foldable_checks(types)
49
40
  types.map do |type|
50
41
  case type
@@ -67,35 +58,72 @@ module RuboCop
67
58
  end
68
59
 
69
60
  def code_length(node)
70
- return heredoc_length(node) if heredoc_node?(node)
61
+ if classlike_node?(node)
62
+ classlike_code_length(node)
63
+ elsif heredoc_node?(node)
64
+ heredoc_length(node)
65
+ else
66
+ body = extract_body(node)
67
+ return 0 unless body
71
68
 
72
- body = extract_body(node)
73
- lines = body&.source&.lines || []
74
- lines.count { |line| !irrelevant_line?(line) }
69
+ body.source.each_line.count { |line| !irrelevant_line?(line) }
70
+ end
75
71
  end
76
72
 
77
73
  def heredoc_node?(node)
78
74
  node.respond_to?(:heredoc?) && node.heredoc?
79
75
  end
80
76
 
77
+ def classlike_code_length(node)
78
+ return 0 if namespace_module?(node)
79
+
80
+ body_line_numbers = line_range(node).to_a[1...-1]
81
+
82
+ target_line_numbers = body_line_numbers -
83
+ line_numbers_of_inner_nodes(node, :module, :class)
84
+
85
+ target_line_numbers.reduce(0) do |length, line_number|
86
+ source_line = @processed_source[line_number]
87
+ next length if irrelevant_line?(source_line)
88
+
89
+ length + 1
90
+ end
91
+ end
92
+
93
+ def namespace_module?(node)
94
+ classlike_node?(node.body)
95
+ end
96
+
97
+ def line_numbers_of_inner_nodes(node, *types)
98
+ line_numbers = Set.new
99
+
100
+ node.each_descendant(*types) do |inner_node|
101
+ line_range = line_range(inner_node)
102
+ line_numbers.merge(line_range)
103
+ end
104
+
105
+ line_numbers.to_a
106
+ end
107
+
81
108
  def heredoc_length(node)
82
109
  lines = node.loc.heredoc_body.source.lines
83
110
  lines.count { |line| !irrelevant_line?(line) } + 2
84
111
  end
85
112
 
86
- def each_top_level_descendant(node, *types, &block)
113
+ def each_top_level_descendant(node, types, &block)
87
114
  node.each_child_node do |child|
115
+ next if classlike_node?(child)
116
+
88
117
  if types.include?(child.type)
89
118
  yield child
90
119
  else
91
- each_top_level_descendant(child, *types, &block)
120
+ each_top_level_descendant(child, types, &block)
92
121
  end
93
122
  end
94
123
  end
95
124
 
96
125
  def classlike_node?(node)
97
- CLASSISH_TYPES.include?(node.type) ||
98
- (node.casgn_type? && (class_definition?(node) || module_definition?(node)))
126
+ CLASSLIKE_TYPES.include?(node.type)
99
127
  end
100
128
 
101
129
  def foldable_node?(node)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Metrics
6
+ module Utils
7
+ # @api private
8
+ #
9
+ # Helps to calculate code length for the provided node.
10
+ module RepeatedCsendDiscount
11
+ def reset_repeated_csend
12
+ @repeated_csend = {}
13
+ end
14
+
15
+ def discount_for_repeated_csend?(csend_node)
16
+ receiver = csend_node.receiver
17
+
18
+ return false unless receiver.lvar_type?
19
+
20
+ var_name = receiver.children.first
21
+ seen = @repeated_csend.fetch(var_name) do
22
+ @repeated_csend[var_name] = csend_node
23
+ return false
24
+ end
25
+
26
+ !seen.equal?(csend_node)
27
+ end
28
+
29
+ def reset_on_lvasgn(node)
30
+ var_name = node.children.first
31
+ @repeated_csend.delete(var_name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -5,8 +5,9 @@ module RuboCop
5
5
  module Migration
6
6
  # Check that cop names in rubocop:disable comments are given with
7
7
  # department name.
8
- class DepartmentName < Cop
8
+ class DepartmentName < Base
9
9
  include RangeHelp
10
+ extend AutoCorrector
10
11
 
11
12
  MSG = 'Department name is missing.'
12
13
 
@@ -18,7 +19,7 @@ module RuboCop
18
19
  # `DepartmentName/CopName` or` all`.
19
20
  DISABLING_COPS_CONTENT_TOKEN = %r{[A-z]+/[A-z]+|all}.freeze
20
21
 
21
- def investigate(processed_source)
22
+ def on_new_investigation
22
23
  processed_source.each_comment do |comment|
23
24
  next if comment.text !~ DISABLE_COMMENT_FORMAT
24
25
 
@@ -38,18 +39,6 @@ module RuboCop
38
39
  end
39
40
  end
40
41
 
41
- def autocorrect(range)
42
- shall_warn = false
43
- cop_name = range.source
44
- qualified_cop_name = Cop.registry.qualified_cop_name(cop_name,
45
- nil, shall_warn)
46
- unless qualified_cop_name.include?('/')
47
- qualified_cop_name = qualified_legacy_cop_name(cop_name)
48
- end
49
-
50
- ->(corrector) { corrector.replace(range, qualified_cop_name) }
51
- end
52
-
53
42
  private
54
43
 
55
44
  def disable_comment_offset
@@ -60,7 +49,16 @@ module RuboCop
60
49
  start = comment.location.expression.begin_pos + offset
61
50
  range = range_between(start, start + name.length)
62
51
 
63
- add_offense(range, location: range)
52
+ add_offense(range) do |corrector|
53
+ cop_name = range.source
54
+ qualified_cop_name = Cop.registry.qualified_cop_name(cop_name, nil, warn: false)
55
+
56
+ unless qualified_cop_name.include?('/')
57
+ qualified_cop_name = qualified_legacy_cop_name(cop_name)
58
+ end
59
+
60
+ corrector.replace(range, qualified_cop_name)
61
+ end
64
62
  end
65
63
 
66
64
  def valid_content_token?(content_token)
@@ -16,7 +16,7 @@ module RuboCop
16
16
  cop_config['MinSize']
17
17
  end
18
18
 
19
- def array_style_detected(style, ary_size)
19
+ def array_style_detected(style, ary_size) # rubocop:todo Metrics/AbcSize
20
20
  cfg = config_to_allow_offenses
21
21
  return if cfg['Enabled'] == false
22
22
 
@@ -171,7 +171,7 @@ module RuboCop
171
171
  # ...then each key/value pair is treated as a method 'argument'
172
172
  # when determining where line breaks should appear.
173
173
  if (last_arg = args.last)
174
- args = args.concat(args.pop.children) if last_arg.hash_type? && !last_arg.braces?
174
+ args = args[0...-1] + last_arg.children if last_arg.hash_type? && !last_arg.braces?
175
175
  end
176
176
  args
177
177
  end
@@ -6,8 +6,14 @@ module RuboCop
6
6
  module CodeLength
7
7
  include ConfigurableMax
8
8
 
9
+ MSG = '%<label>s has too many lines. [%<length>d/%<max>d]'
10
+
9
11
  private
10
12
 
13
+ def message(length, max_length)
14
+ format(MSG, label: cop_label, length: length, max: max_length)
15
+ end
16
+
11
17
  def max_length
12
18
  cop_config['Max']
13
19
  end
@@ -21,14 +27,16 @@ module RuboCop
21
27
  end
22
28
 
23
29
  def check_code_length(node)
24
- length = code_length(node)
30
+ # Skip costly calculation when definitely not needed
31
+ return if node.line_count <= max_length
25
32
 
26
- return unless length > max_length
33
+ calculator = build_code_length_calculator(node)
34
+ length = calculator.calculate
35
+ return if length <= max_length
27
36
 
28
- location = node.casgn_type? ? :name : :expression
37
+ location = node.casgn_type? ? node.loc.name : node.loc.expression
29
38
 
30
- add_offense(node, location: location,
31
- message: message(length, max_length)) do
39
+ add_offense(location, message: message(length, max_length)) do
32
40
  self.max = length
33
41
  end
34
42
  end
@@ -37,6 +45,15 @@ module RuboCop
37
45
  def irrelevant_line(source_line)
38
46
  source_line.blank? || !count_comments? && comment_line?(source_line)
39
47
  end
48
+
49
+ def build_code_length_calculator(node)
50
+ Metrics::Utils::CodeLengthCalculator.new(
51
+ node,
52
+ processed_source,
53
+ count_comments: count_comments?,
54
+ foldable_types: count_as_one
55
+ )
56
+ end
40
57
  end
41
58
  end
42
59
  end
@@ -5,6 +5,8 @@ module RuboCop
5
5
  # Common functionality for enforcing a specific superclass
6
6
  module EnforceSuperclass
7
7
  def self.included(base)
8
+ super
9
+
8
10
  base.def_node_matcher :class_definition, <<~PATTERN
9
11
  (class (const _ !:#{base::SUPERCLASS}) #{base::BASE_PATTERN} ...)
10
12
  PATTERN
@@ -2,10 +2,13 @@
2
2
 
3
3
  module RuboCop
4
4
  module Cop
5
+ # @api private
6
+ #
5
7
  # This module handles measurement and reporting of complexity in methods.
6
8
  module MethodComplexity
7
9
  include ConfigurableMax
8
10
  include IgnoredMethods
11
+ include Metrics::Utils::RepeatedCsendDiscount
9
12
  extend NodePattern::Macros
10
13
 
11
14
  def on_def(node)
@@ -37,6 +40,7 @@ module RuboCop
37
40
  return unless node.body
38
41
 
39
42
  max = cop_config['Max']
43
+ reset_repeated_csend
40
44
  complexity, abc_vector = complexity(node.body)
41
45
 
42
46
  return unless complexity > max
@@ -53,8 +57,12 @@ module RuboCop
53
57
  end
54
58
 
55
59
  def complexity(body)
56
- body.each_node(*self.class::COUNTED_NODES).reduce(1) do |score, n|
57
- score + complexity_score_for(n)
60
+ body.each_node(:lvasgn, *self.class::COUNTED_NODES).reduce(1) do |score, node|
61
+ if node.lvasgn_type?
62
+ reset_on_lvasgn(node)
63
+ next score
64
+ end
65
+ score + complexity_score_for(node)
58
66
  end
59
67
  end
60
68
  end
@@ -36,14 +36,43 @@ module RuboCop
36
36
  def modifier_fits_on_single_line?(node)
37
37
  return true unless max_line_length
38
38
 
39
- length_in_modifier_form(node, node.condition) <= max_line_length
39
+ length_in_modifier_form(node) <= max_line_length
40
40
  end
41
41
 
42
- def length_in_modifier_form(node, cond)
43
- keyword = node.loc.keyword
44
- indentation = keyword.source_line[/^\s*/]
45
- line_length("#{indentation}#{node.body.source} #{keyword.source} " \
46
- "#{cond.source}")
42
+ def length_in_modifier_form(node)
43
+ keyword_element = node.loc.keyword
44
+ end_element = node.loc.end
45
+ code_before = keyword_element.source_line[0...keyword_element.column]
46
+ code_after = end_element.source_line[end_element.last_column..-1]
47
+ expression = to_modifier_form(node)
48
+ line_length("#{code_before}#{expression}#{code_after}")
49
+ end
50
+
51
+ def to_modifier_form(node)
52
+ expression = [node.body.source,
53
+ node.keyword,
54
+ node.condition.source].compact.join(' ')
55
+ parenthesized = parenthesize?(node) ? "(#{expression})" : expression
56
+ [parenthesized, first_line_comment(node)].compact.join(' ')
57
+ end
58
+
59
+ def first_line_comment(node)
60
+ comment =
61
+ processed_source.find_comment { |c| c.loc.line == node.loc.line }
62
+
63
+ comment ? comment.loc.expression.source : nil
64
+ end
65
+
66
+ def parenthesize?(node)
67
+ # Parenthesize corrected expression if changing to modifier-if form
68
+ # would change the meaning of the parent expression
69
+ # (due to the low operator precedence of modifier-if)
70
+ parent = node.parent
71
+ return false if parent.nil?
72
+ return true if parent.assignment? || parent.operator_keyword?
73
+ return true if %i[array pair].include?(parent.type)
74
+
75
+ node.parent.send_type? && !node.parent.parenthesized?
47
76
  end
48
77
 
49
78
  def max_line_length
@@ -30,31 +30,6 @@ module RuboCop
30
30
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
31
31
  end
32
32
 
33
- def index_of_first_token(node)
34
- range = node.source_range
35
- token_table[range.line][range.column]
36
- end
37
-
38
- def index_of_last_token(node)
39
- range = node.source_range
40
- table_row = token_table[range.last_line]
41
- (0...range.last_column).reverse_each do |c|
42
- ix = table_row[c]
43
- return ix if ix
44
- end
45
- end
46
-
47
- def token_table
48
- @token_table ||= begin
49
- table = {}
50
- processed_source.tokens.each_with_index do |t, ix|
51
- table[t.line] ||= {}
52
- table[t.line][t.column] = ix
53
- end
54
- table
55
- end
56
- end
57
-
58
33
  def on_new_investigation
59
34
  @token_table = nil
60
35
  super
@@ -41,8 +41,7 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def case_offense(node, range)
44
- add_offense(node, location: range,
45
- message: format(CASE_MSG, name_type: name_type(node)))
44
+ add_offense(range, message: format(CASE_MSG, name_type: name_type(node)))
46
45
  end
47
46
 
48
47
  def uppercase?(name)
@@ -59,8 +58,7 @@ module RuboCop
59
58
  end
60
59
 
61
60
  def num_offense(node, range)
62
- add_offense(node, location: range,
63
- message: format(NUM_MSG, name_type: name_type(node)))
61
+ add_offense(range, message: format(NUM_MSG, name_type: name_type(node)))
64
62
  end
65
63
 
66
64
  def ends_with_num?(name)
@@ -68,10 +66,9 @@ module RuboCop
68
66
  end
69
67
 
70
68
  def length_offense(node, range)
71
- add_offense(node, location: range,
72
- message: format(LENGTH_MSG,
73
- name_type: name_type(node).capitalize,
74
- min: min_length))
69
+ message = format(LENGTH_MSG, name_type: name_type(node).capitalize, min: min_length)
70
+
71
+ add_offense(range, message: message)
75
72
  end
76
73
 
77
74
  def long_enough?(name)
@@ -86,11 +83,7 @@ module RuboCop
86
83
  end
87
84
 
88
85
  def forbidden_offense(node, range, name)
89
- add_offense(
90
- node,
91
- location: range,
92
- message: format(FORBIDDEN_MSG, name: name, name_type: name_type(node))
93
- )
86
+ add_offense(range, message: format(FORBIDDEN_MSG, name: name, name_type: name_type(node)))
94
87
  end
95
88
 
96
89
  def allowed_names