rubocop 0.73.0 → 0.77.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/bin/console +1 -0
  4. data/config/default.yml +332 -295
  5. data/lib/rubocop.rb +46 -30
  6. data/lib/rubocop/ast/builder.rb +1 -0
  7. data/lib/rubocop/ast/node.rb +6 -8
  8. data/lib/rubocop/ast/node/block_node.rb +2 -0
  9. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +1 -12
  10. data/lib/rubocop/ast/node/return_node.rb +24 -0
  11. data/lib/rubocop/cli.rb +11 -227
  12. data/lib/rubocop/cli/command.rb +21 -0
  13. data/lib/rubocop/cli/command/auto_genenerate_config.rb +105 -0
  14. data/lib/rubocop/cli/command/base.rb +33 -0
  15. data/lib/rubocop/cli/command/execute_runner.rb +76 -0
  16. data/lib/rubocop/cli/command/init_dotfile.rb +45 -0
  17. data/lib/rubocop/cli/command/show_cops.rb +73 -0
  18. data/lib/rubocop/cli/command/version.rb +17 -0
  19. data/lib/rubocop/cli/environment.rb +21 -0
  20. data/lib/rubocop/comment_config.rb +5 -4
  21. data/lib/rubocop/config.rb +28 -537
  22. data/lib/rubocop/config_loader.rb +21 -3
  23. data/lib/rubocop/config_loader_resolver.rb +4 -3
  24. data/lib/rubocop/config_obsoletion.rb +275 -0
  25. data/lib/rubocop/config_validator.rb +246 -0
  26. data/lib/rubocop/cop/autocorrect_logic.rb +2 -2
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +4 -4
  28. data/lib/rubocop/cop/commissioner.rb +15 -7
  29. data/lib/rubocop/cop/cop.rb +33 -9
  30. data/lib/rubocop/cop/corrector.rb +8 -7
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +43 -17
  32. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
  33. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/space_corrector.rb +1 -2
  35. data/lib/rubocop/cop/generator.rb +3 -3
  36. data/lib/rubocop/cop/generator/configuration_injector.rb +9 -4
  37. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  39. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +59 -0
  40. data/lib/rubocop/cop/layout/{align_arguments.rb → argument_alignment.rb} +1 -1
  41. data/lib/rubocop/cop/layout/{align_array.rb → array_alignment.rb} +1 -1
  42. data/lib/rubocop/cop/layout/{indent_assignment.rb → assignment_indentation.rb} +11 -2
  43. data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
  44. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  45. data/lib/rubocop/cop/layout/comment_indentation.rb +10 -13
  46. data/lib/rubocop/cop/layout/empty_comment.rb +7 -16
  47. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +22 -7
  48. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +2 -2
  49. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +2 -2
  50. data/lib/rubocop/cop/layout/end_of_line.rb +8 -3
  51. data/lib/rubocop/cop/layout/extra_spacing.rb +15 -60
  52. data/lib/rubocop/cop/layout/{indent_first_argument.rb → first_argument_indentation.rb} +12 -10
  53. data/lib/rubocop/cop/layout/{indent_first_array_element.rb → first_array_element_indentation.rb} +4 -4
  54. data/lib/rubocop/cop/layout/{indent_first_hash_element.rb → first_hash_element_indentation.rb} +4 -4
  55. data/lib/rubocop/cop/layout/{indent_first_parameter.rb → first_parameter_indentation.rb} +3 -3
  56. data/lib/rubocop/cop/layout/{align_hash.rb → hash_alignment.rb} +8 -4
  57. data/lib/rubocop/cop/layout/{indent_heredoc.rb → heredoc_indentation.rb} +2 -2
  58. data/lib/rubocop/cop/layout/indentation_width.rb +19 -5
  59. data/lib/rubocop/cop/layout/{leading_blank_lines.rb → leading_empty_lines.rb} +1 -1
  60. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  61. data/lib/rubocop/cop/layout/multiline_block_layout.rb +24 -2
  62. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
  63. data/lib/rubocop/cop/layout/{align_parameters.rb → parameter_alignment.rb} +1 -1
  64. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -0
  65. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +5 -1
  66. data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
  67. data/lib/rubocop/cop/layout/space_around_operators.rb +43 -24
  68. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -7
  69. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +8 -5
  70. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +7 -0
  71. data/lib/rubocop/cop/layout/space_inside_parens.rb +6 -6
  72. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +24 -40
  73. data/lib/rubocop/cop/layout/{trailing_blank_lines.rb → trailing_empty_lines.rb} +1 -1
  74. data/lib/rubocop/cop/layout/trailing_whitespace.rb +18 -2
  75. data/lib/rubocop/cop/lint/assignment_in_condition.rb +17 -4
  76. data/lib/rubocop/cop/lint/debugger.rb +1 -3
  77. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +1 -1
  78. data/lib/rubocop/cop/lint/{duplicated_key.rb → duplicate_hash_key.rb} +1 -1
  79. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -4
  80. data/lib/rubocop/cop/lint/erb_new_arguments.rb +61 -4
  81. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +10 -36
  82. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
  83. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -8
  84. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +2 -2
  85. data/lib/rubocop/cop/lint/{multiple_compare.rb → multiple_comparison.rb} +1 -1
  86. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  87. data/lib/rubocop/cop/lint/{unneeded_cop_disable_directive.rb → redundant_cop_disable_directive.rb} +24 -24
  88. data/lib/rubocop/cop/lint/{unneeded_cop_enable_directive.rb → redundant_cop_enable_directive.rb} +6 -8
  89. data/lib/rubocop/cop/lint/{unneeded_require_statement.rb → redundant_require_statement.rb} +1 -1
  90. data/lib/rubocop/cop/lint/{unneeded_splat_expansion.rb → redundant_splat_expansion.rb} +12 -7
  91. data/lib/rubocop/cop/lint/{string_conversion_in_interpolation.rb → redundant_string_coercion.rb} +7 -7
  92. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
  93. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  94. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +5 -6
  95. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +91 -0
  96. data/lib/rubocop/cop/lint/{handle_exceptions.rb → suppressed_exception.rb} +1 -1
  97. data/lib/rubocop/cop/lint/unused_block_argument.rb +22 -6
  98. data/lib/rubocop/cop/lint/unused_method_argument.rb +23 -5
  99. data/lib/rubocop/cop/lint/useless_access_modifier.rb +57 -23
  100. data/lib/rubocop/cop/lint/useless_setter_call.rb +1 -1
  101. data/lib/rubocop/cop/lint/void.rb +7 -26
  102. data/lib/rubocop/cop/message_annotator.rb +16 -7
  103. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  104. data/lib/rubocop/cop/metrics/line_length.rb +48 -42
  105. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  106. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +23 -6
  107. data/lib/rubocop/cop/migration/department_name.rb +44 -0
  108. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  109. data/lib/rubocop/cop/mixin/documentation_comment.rb +0 -2
  110. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  111. data/lib/rubocop/cop/mixin/{hash_alignment.rb → hash_alignment_styles.rb} +1 -1
  112. data/lib/rubocop/cop/mixin/interpolation.rb +27 -0
  113. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  114. data/lib/rubocop/cop/mixin/nil_methods.rb +4 -4
  115. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +87 -0
  116. data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -2
  117. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -5
  118. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -6
  119. data/lib/rubocop/cop/naming/{uncommunicative_block_param_name.rb → block_parameter_name.rb} +3 -3
  120. data/lib/rubocop/cop/naming/file_name.rb +12 -5
  121. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -5
  122. data/lib/rubocop/cop/naming/method_name.rb +12 -1
  123. data/lib/rubocop/cop/naming/{uncommunicative_method_param_name.rb → method_parameter_name.rb} +3 -3
  124. data/lib/rubocop/cop/naming/predicate_name.rb +6 -6
  125. data/lib/rubocop/cop/naming/variable_name.rb +1 -0
  126. data/lib/rubocop/cop/offense.rb +18 -7
  127. data/lib/rubocop/cop/registry.rb +22 -1
  128. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -0
  129. data/lib/rubocop/cop/style/alias.rb +1 -1
  130. data/lib/rubocop/cop/style/array_join.rb +1 -1
  131. data/lib/rubocop/cop/style/attr.rb +2 -2
  132. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  133. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +35 -16
  134. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  135. data/lib/rubocop/cop/style/comment_annotation.rb +5 -5
  136. data/lib/rubocop/cop/style/commented_keyword.rb +16 -30
  137. data/lib/rubocop/cop/style/conditional_assignment.rb +5 -7
  138. data/lib/rubocop/cop/style/constant_visibility.rb +13 -2
  139. data/lib/rubocop/cop/style/copyright.rb +11 -7
  140. data/lib/rubocop/cop/style/documentation_method.rb +44 -0
  141. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +10 -4
  142. data/lib/rubocop/cop/style/empty_case_condition.rb +2 -2
  143. data/lib/rubocop/cop/style/empty_literal.rb +2 -2
  144. data/lib/rubocop/cop/style/empty_method.rb +5 -5
  145. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  146. data/lib/rubocop/cop/style/even_odd.rb +1 -1
  147. data/lib/rubocop/cop/style/expand_path_arguments.rb +1 -1
  148. data/lib/rubocop/cop/style/format_string.rb +10 -7
  149. data/lib/rubocop/cop/style/format_string_token.rb +19 -68
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +28 -33
  151. data/lib/rubocop/cop/style/guard_clause.rb +39 -10
  152. data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
  153. data/lib/rubocop/cop/style/if_unless_modifier.rb +58 -15
  154. data/lib/rubocop/cop/style/infinite_loop.rb +5 -4
  155. data/lib/rubocop/cop/style/inverse_methods.rb +19 -13
  156. data/lib/rubocop/cop/style/ip_addresses.rb +4 -4
  157. data/lib/rubocop/cop/style/lambda.rb +0 -2
  158. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -10
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -25
  160. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -9
  161. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  162. data/lib/rubocop/cop/style/mixin_usage.rb +11 -1
  163. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  164. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  165. data/lib/rubocop/cop/style/nested_modifier.rb +22 -4
  166. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +5 -5
  167. data/lib/rubocop/cop/style/next.rb +5 -5
  168. data/lib/rubocop/cop/style/non_nil_check.rb +21 -9
  169. data/lib/rubocop/cop/style/numeric_literals.rb +7 -3
  170. data/lib/rubocop/cop/style/option_hash.rb +3 -3
  171. data/lib/rubocop/cop/style/or_assignment.rb +6 -1
  172. data/lib/rubocop/cop/style/parentheses_around_condition.rb +14 -0
  173. data/lib/rubocop/cop/style/{unneeded_capital_w.rb → redundant_capital_w.rb} +1 -1
  174. data/lib/rubocop/cop/style/{unneeded_condition.rb → redundant_condition.rb} +3 -3
  175. data/lib/rubocop/cop/style/{unneeded_interpolation.rb → redundant_interpolation.rb} +1 -1
  176. data/lib/rubocop/cop/style/redundant_parentheses.rb +16 -7
  177. data/lib/rubocop/cop/style/{unneeded_percent_q.rb → redundant_percent_q.rb} +1 -1
  178. data/lib/rubocop/cop/style/redundant_return.rb +39 -29
  179. data/lib/rubocop/cop/style/redundant_self.rb +18 -1
  180. data/lib/rubocop/cop/style/{unneeded_sort.rb → redundant_sort.rb} +5 -5
  181. data/lib/rubocop/cop/style/rescue_modifier.rb +24 -0
  182. data/lib/rubocop/cop/style/safe_navigation.rb +23 -3
  183. data/lib/rubocop/cop/style/semicolon.rb +13 -2
  184. data/lib/rubocop/cop/style/single_line_methods.rb +8 -1
  185. data/lib/rubocop/cop/style/special_global_vars.rb +5 -7
  186. data/lib/rubocop/cop/style/ternary_parentheses.rb +19 -0
  187. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +4 -6
  188. data/lib/rubocop/cop/style/trivial_accessors.rb +5 -5
  189. data/lib/rubocop/cop/style/variable_interpolation.rb +6 -16
  190. data/lib/rubocop/cop/team.rb +5 -0
  191. data/lib/rubocop/cop/util.rb +1 -1
  192. data/lib/rubocop/cop/utils/format_string.rb +120 -0
  193. data/lib/rubocop/cop/variable_force.rb +7 -5
  194. data/lib/rubocop/cop/variable_force/variable.rb +15 -2
  195. data/lib/rubocop/core_ext/string.rb +0 -24
  196. data/lib/rubocop/formatter/clang_style_formatter.rb +9 -6
  197. data/lib/rubocop/formatter/emacs_style_formatter.rb +22 -9
  198. data/lib/rubocop/formatter/file_list_formatter.rb +1 -1
  199. data/lib/rubocop/formatter/formatter_set.rb +16 -15
  200. data/lib/rubocop/formatter/pacman_formatter.rb +80 -0
  201. data/lib/rubocop/formatter/simple_text_formatter.rb +16 -4
  202. data/lib/rubocop/formatter/tap_formatter.rb +18 -7
  203. data/lib/rubocop/magic_comment.rb +4 -0
  204. data/lib/rubocop/node_pattern.rb +3 -1
  205. data/lib/rubocop/options.rb +17 -22
  206. data/lib/rubocop/path_util.rb +1 -1
  207. data/lib/rubocop/processed_source.rb +5 -1
  208. data/lib/rubocop/rake_task.rb +1 -0
  209. data/lib/rubocop/result_cache.rb +22 -8
  210. data/lib/rubocop/rspec/expect_offense.rb +4 -1
  211. data/lib/rubocop/runner.rb +55 -32
  212. data/lib/rubocop/target_finder.rb +12 -6
  213. data/lib/rubocop/version.rb +1 -1
  214. metadata +47 -32
  215. data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +0 -19
  216. data/lib/rubocop/cop/mixin/safe_mode.rb +0 -22
@@ -68,16 +68,16 @@ module RuboCop
68
68
  private
69
69
 
70
70
  def expand_elsif(node, elsif_branches = [])
71
- return [] if node.nil? || !node.if_type?
71
+ return [] if node.nil? || !node.if_type? || !node.elsif?
72
72
 
73
73
  elsif_branches << node.if_branch
74
74
 
75
- if node.else_branch&.if_type?
76
- expand_elsif(node.else_branch, elsif_branches)
75
+ else_branch = node.else_branch
76
+ if else_branch&.if_type? && else_branch&.elsif?
77
+ expand_elsif(else_branch, elsif_branches)
77
78
  else
78
- elsif_branches << node.else_branch
79
+ elsif_branches << else_branch
79
80
  end
80
- elsif_branches
81
81
  end
82
82
 
83
83
  def lhs_for_send(node)
@@ -219,8 +219,6 @@ module RuboCop
219
219
  SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
220
220
  WIDTH = 'Width'
221
221
 
222
- def_node_matcher :condition?, '{if case}'
223
-
224
222
  # The shovel operator `<<` does not have its own type. It is a `send`
225
223
  # type.
226
224
  def_node_matcher :assignment_type?, <<~PATTERN
@@ -46,7 +46,14 @@ module RuboCop
46
46
  end
47
47
 
48
48
  def class_or_module_scope?(node)
49
- node.parent && %i[class module].include?(node.parent.type)
49
+ return false unless node.parent
50
+
51
+ case node.parent.type
52
+ when :begin
53
+ class_or_module_scope?(node.parent)
54
+ when :class, :module
55
+ true
56
+ end
50
57
  end
51
58
 
52
59
  def visibility_declaration?(node)
@@ -58,8 +65,12 @@ module RuboCop
58
65
  end
59
66
 
60
67
  def_node_matcher :visibility_declaration_for?, <<~PATTERN
61
- (send nil? {:public_constant :private_constant} ({sym str} %1))
68
+ (send nil? {:public_constant :private_constant} ({sym str} #match_name?(%1)))
62
69
  PATTERN
70
+
71
+ def match_name?(name, constant_name)
72
+ name.to_sym == constant_name.to_sym
73
+ end
63
74
  end
64
75
  end
65
76
  end
@@ -33,13 +33,7 @@ module RuboCop
33
33
  end
34
34
 
35
35
  def autocorrect(token)
36
- raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
37
-
38
- regex = Regexp.new(notice)
39
- unless autocorrect_notice =~ regex
40
- raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must " \
41
- "match Notice /#{notice}/"
42
- end
36
+ verify_autocorrect_notice!
43
37
 
44
38
  lambda do |corrector|
45
39
  range = token.nil? ? range_between(0, 0) : token.pos
@@ -57,6 +51,16 @@ module RuboCop
57
51
  cop_config['AutocorrectNotice']
58
52
  end
59
53
 
54
+ def verify_autocorrect_notice!
55
+ raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
56
+
57
+ regex = Regexp.new(notice)
58
+ return if autocorrect_notice =~ regex
59
+
60
+ raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must " \
61
+ "match Notice /#{notice}/"
62
+ end
63
+
60
64
  def insert_notice_before(processed_source)
61
65
  token_index = 0
62
66
  token_index += 1 if shebang_token?(processed_source, token_index)
@@ -47,6 +47,50 @@ module RuboCop
47
47
  # def foo.bar
48
48
  # puts baz
49
49
  # end
50
+ #
51
+ # @example RequireForNonPublicMethods: false (default)
52
+ # # good
53
+ # class Foo
54
+ # protected
55
+ # def do_something
56
+ # end
57
+ # end
58
+ #
59
+ # class Foo
60
+ # private
61
+ # def do_something
62
+ # end
63
+ # end
64
+ #
65
+ # @example RequireForNonPublicMethods: true
66
+ # # bad
67
+ # class Foo
68
+ # protected
69
+ # def do_something
70
+ # end
71
+ # end
72
+ #
73
+ # class Foo
74
+ # private
75
+ # def do_something
76
+ # end
77
+ # end
78
+ #
79
+ # # good
80
+ # class Foo
81
+ # protected
82
+ # # Documentation
83
+ # def do_something
84
+ # end
85
+ # end
86
+ #
87
+ # class Foo
88
+ # private
89
+ # # Documentation
90
+ # def do_something
91
+ # end
92
+ # end
93
+ #
50
94
  class DocumentationMethod < Cop
51
95
  include DocumentationComment
52
96
  include DefNode
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Lint/UnneededCopDisableDirective
3
+ # rubocop:disable Lint/RedundantCopDisableDirective
4
4
  # rubocop:disable Style/DoubleCopDisableDirective
5
5
 
6
6
  module RuboCop
@@ -26,21 +26,27 @@ module RuboCop
26
26
  #
27
27
  class DoubleCopDisableDirective < Cop
28
28
  # rubocop:enable Style/For, Style/DoubleCopDisableDirective
29
- # rubocop:enable Lint/UnneededCopDisableDirective, Metrics/AbcSize
29
+ # rubocop:enable Lint/RedundantCopDisableDirective, Metrics/AbcSize
30
30
  MSG = 'More than one disable comment on one line.'
31
31
 
32
32
  def investigate(processed_source)
33
33
  processed_source.comments.each do |comment|
34
- next unless comment.text.scan('# rubocop:disable').size > 1
34
+ next unless comment.text.scan(/# rubocop:(?:disable|todo)/).size > 1
35
35
 
36
36
  add_offense(comment)
37
37
  end
38
38
  end
39
39
 
40
40
  def autocorrect(comment)
41
+ prefix = if comment.text.start_with?('# rubocop:disable')
42
+ '# rubocop:disable'
43
+ else
44
+ '# rubocop:todo'
45
+ end
46
+
41
47
  lambda do |corrector|
42
48
  corrector.replace(comment.loc.expression,
43
- comment.text[/# rubocop:disable \S+/])
49
+ comment.text[/#{prefix} \S+/])
44
50
  end
45
51
  end
46
52
  end
@@ -84,8 +84,8 @@ module RuboCop
84
84
 
85
85
  next unless conditions.size > 1
86
86
 
87
- range = range_between(conditions.first.loc.expression.begin_pos,
88
- conditions.last.loc.expression.end_pos)
87
+ range = range_between(conditions.first.source_range.begin_pos,
88
+ conditions.last.source_range.end_pos)
89
89
 
90
90
  corrector.replace(range, conditions.map(&:source).join(' || '))
91
91
  end
@@ -84,8 +84,8 @@ module RuboCop
84
84
  # to rewrite the arguments to wrap them in parenthesis.
85
85
  args = node.parent.arguments
86
86
 
87
- range_between(args[0].loc.expression.begin_pos - 1,
88
- args[-1].loc.expression.end_pos)
87
+ range_between(args[0].source_range.begin_pos - 1,
88
+ args[-1].source_range.end_pos)
89
89
  else
90
90
  node.source_range
91
91
  end
@@ -73,11 +73,11 @@ module RuboCop
73
73
  end
74
74
 
75
75
  def corrected(node)
76
- has_parentheses = parentheses?(node.arguments)
77
-
78
- arguments = node.arguments? ? node.arguments.source : ''
79
- extra_space = node.arguments? && !has_parentheses ? ' ' : ''
80
- scope = node.receiver ? "#{node.receiver.source}." : ''
76
+ if node.arguments?
77
+ arguments = node.arguments.source
78
+ extra_space = ' ' unless parentheses?(node.arguments)
79
+ end
80
+ scope = node.receiver ? "#{node.receiver.source}." : ''
81
81
 
82
82
  signature = [scope, node.method_name, extra_space, arguments].join
83
83
 
@@ -85,7 +85,7 @@ module RuboCop
85
85
  # FIXME: It's a Style/ConditionalAssignment's false positive.
86
86
  # rubocop:disable Style/ConditionalAssignment
87
87
  def with_lineno?(node)
88
- if node.method_name == :eval
88
+ if node.method?(:eval)
89
89
  node.arguments.size == 4
90
90
  else
91
91
  node.arguments.size == 3
@@ -23,7 +23,7 @@ module RuboCop
23
23
  {(send $_ :% (int 2))
24
24
  (begin (send $_ :% (int 2)))}
25
25
  ${:== :!=}
26
- (int ${0 1 2}))
26
+ (int ${0 1}))
27
27
  PATTERN
28
28
 
29
29
  def on_send(node)
@@ -160,7 +160,7 @@ module RuboCop
160
160
  def depth(current_path)
161
161
  paths = current_path.split(File::SEPARATOR)
162
162
 
163
- paths.reject { |path| path == '.' }.count
163
+ paths.count { |path| path != '.' }
164
164
  end
165
165
 
166
166
  def parent_path(current_path)
@@ -94,10 +94,12 @@ module RuboCop
94
94
  private
95
95
 
96
96
  def autocorrect_from_percent(corrector, node)
97
- args = if %i[array hash].include?(node.first_argument.type)
98
- node.first_argument.children.map(&:source).join(', ')
97
+ percent_rhs = node.first_argument
98
+ args = case percent_rhs.type
99
+ when :array, :hash
100
+ percent_rhs.children.map(&:source).join(', ')
99
101
  else
100
- node.first_argument.source
102
+ percent_rhs.source
101
103
  end
102
104
 
103
105
  corrected = "#{style}(#{node.receiver.source}, #{args})"
@@ -106,14 +108,15 @@ module RuboCop
106
108
  end
107
109
 
108
110
  def autocorrect_to_percent(corrector, node)
109
- format = node.first_argument.source
111
+ format_arg, *param_args = node.arguments
112
+ format = format_arg.source
110
113
 
111
- args = if node.arguments.size == 2
112
- arg = node.arguments.last
114
+ args = if param_args.one?
115
+ arg = param_args.last
113
116
 
114
117
  arg.hash_type? ? "{ #{arg.source} }" : arg.source
115
118
  else
116
- "[#{node.arguments[1..-1].map(&:source).join(', ')}]"
119
+ "[#{param_args.map(&:source).join(', ')}]"
117
120
  end
118
121
 
119
122
  corrector.replace(node.loc.expression, "#{format} % #{args}")
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # **Note:**
9
9
  # `unannotated` style cop only works for strings
10
10
  # which are passed as arguments to those methods:
11
- # `sprintf`, `format`, `%`.
11
+ # `printf`, `sprintf`, `format`, `%`.
12
12
  # The reason is that *unannotated* format is very similar
13
13
  # to encoded URLs or Date/Time formatting strings.
14
14
  #
@@ -41,17 +41,7 @@ module RuboCop
41
41
  class FormatStringToken < Cop
42
42
  include ConfigurableEnforcedStyle
43
43
 
44
- FIELD_CHARACTERS = Regexp.union(%w[A B E G X a b c d e f g i o p s u x])
45
- FORMAT_STRING_METHODS = %i[sprintf format %].freeze
46
-
47
- STYLE_PATTERNS = {
48
- annotated: /(?<token>%<[^>]+>#{FIELD_CHARACTERS})/,
49
- template: /(?<token>%\{[^\}]+\})/,
50
- unannotated: /(?<token>%#{FIELD_CHARACTERS})/
51
- }.freeze
52
-
53
44
  def on_str(node)
54
- return if placeholder_argument?(node)
55
45
  return if node.each_ancestor(:xstr, :regexp).any?
56
46
 
57
47
  tokens(node) do |detected_style, token_range|
@@ -68,14 +58,16 @@ module RuboCop
68
58
 
69
59
  private
70
60
 
71
- def includes_format_methods?(node)
72
- node.each_ancestor(:send).any? do |ancestor|
73
- FORMAT_STRING_METHODS.include?(ancestor.method_name)
74
- end
75
- end
61
+ def_node_matcher :format_string_in_typical_context?, <<~PATTERN
62
+ {
63
+ ^(send _ {:format :sprintf :printf} %0 ...)
64
+ ^(send %0 :% _)
65
+ }
66
+ PATTERN
76
67
 
77
68
  def unannotated_format?(node, detected_style)
78
- detected_style == :unannotated && !includes_format_methods?(node)
69
+ detected_style == :unannotated &&
70
+ !format_string_in_typical_context?(node)
79
71
  end
80
72
 
81
73
  def message(detected_style)
@@ -102,67 +94,26 @@ module RuboCop
102
94
  if source_map.is_a?(Parser::Source::Map::Heredoc)
103
95
  source_map.heredoc_body
104
96
  elsif source_map.begin
105
- slice_source(
106
- source_map.expression,
107
- source_map.expression.begin_pos + 1,
108
- source_map.expression.end_pos - 1
109
- )
97
+ source_map.expression.adjust(begin_pos: +1, end_pos: -1)
110
98
  else
111
99
  source_map.expression
112
100
  end
113
101
  end
114
102
 
115
103
  def token_ranges(contents)
116
- while (offending_match = match_token(contents))
117
- detected_style, *range = *offending_match
118
- token, contents = split_token(contents, *range)
119
- yield(detected_style, token)
120
- end
121
- end
104
+ format_string = RuboCop::Cop::Utils::FormatString.new(contents.source)
122
105
 
123
- def match_token(source_range)
124
- supported_styles.each do |style_name|
125
- pattern = STYLE_PATTERNS.fetch(style_name)
126
- match = source_range.source.match(pattern)
127
- next unless match
106
+ format_string.format_sequences.each do |seq|
107
+ next if seq.percent?
128
108
 
129
- return [style_name, match.begin(:token), match.end(:token)]
130
- end
131
-
132
- nil
133
- end
134
-
135
- def split_token(source_range, match_begin, match_end)
136
- token =
137
- slice_source(
138
- source_range,
139
- source_range.begin_pos + match_begin,
140
- source_range.begin_pos + match_end
141
- )
142
-
143
- remainder =
144
- slice_source(
145
- source_range,
146
- source_range.begin_pos + match_end,
147
- source_range.end_pos
109
+ detected_style = seq.style
110
+ token = contents.begin.adjust(
111
+ begin_pos: seq.begin_pos,
112
+ end_pos: seq.end_pos
148
113
  )
149
114
 
150
- [token, remainder]
151
- end
152
-
153
- def slice_source(source_range, new_begin, new_end)
154
- Parser::Source::Range.new(
155
- source_range.source_buffer,
156
- new_begin,
157
- new_end
158
- )
159
- end
160
-
161
- def placeholder_argument?(node)
162
- return false unless node.parent
163
- return true if node.parent.pair_type?
164
-
165
- placeholder_argument?(node.parent)
115
+ yield(detected_style, token)
116
+ end
166
117
  end
167
118
  end
168
119
  end
@@ -3,11 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop is designed to help upgrade to after Ruby 3.0. It will add the
7
- # comment `# frozen_string_literal: true` to the top of files to
8
- # enable frozen string literals. Frozen string literals may be default
9
- # after Ruby 3.0. The comment will be added below a shebang and encoding
10
- # comment. The frozen string literal comment is only valid in Ruby 2.3+.
6
+ # This cop is designed to help you transition from mutable string literals
7
+ # to frozen string literals.
8
+ # It will add the comment `# frozen_string_literal: true` to the top of
9
+ # files to enable frozen string literals. Frozen string literals may be
10
+ # default in future Ruby. The comment will be added below a shebang and
11
+ # encoding comment. The frozen string literal comment is only valid in
12
+ # Ruby 2.3+.
13
+ #
14
+ # Note that the cop will ignore files where the comment exists but is set
15
+ # to `false` instead of `true`.
11
16
  #
12
17
  # @example EnforcedStyle: always (default)
13
18
  # # The `always` style will always add the frozen string literal comment
@@ -25,6 +30,13 @@ module RuboCop
25
30
  # # ...
26
31
  # end
27
32
  #
33
+ # # good
34
+ # # frozen_string_literal: false
35
+ #
36
+ # module Bar
37
+ # # ...
38
+ # end
39
+ #
28
40
  # @example EnforcedStyle: never
29
41
  # # The `never` will enforce that the frozen string literal comment does
30
42
  # # not exist in a file.
@@ -121,42 +133,25 @@ module RuboCop
121
133
  end
122
134
 
123
135
  def insert_comment(corrector)
124
- last_special_comment = last_special_comment(processed_source)
125
- if last_special_comment.nil?
126
- corrector.insert_before(correction_range, preceding_comment)
127
- else
128
- corrector.insert_after(correction_range, proceeding_comment)
129
- end
130
- end
136
+ comment = last_special_comment(processed_source)
131
137
 
132
- def preceding_comment
133
- if processed_source.tokens[0].space_before?
134
- "#{FROZEN_STRING_LITERAL_ENABLED}\n"
138
+ if comment
139
+ corrector.insert_after(line_range(comment.line), following_comment)
135
140
  else
136
- "#{FROZEN_STRING_LITERAL_ENABLED}\n\n"
141
+ corrector.insert_before(line_range(1), preceding_comment)
137
142
  end
138
143
  end
139
144
 
140
- def proceeding_comment
141
- last_special_comment = last_special_comment(processed_source)
142
- following_line = processed_source.following_line(last_special_comment)
143
-
144
- if following_line&.empty?
145
- "\n#{FROZEN_STRING_LITERAL_ENABLED}"
146
- else
147
- "\n#{FROZEN_STRING_LITERAL_ENABLED}\n"
148
- end
145
+ def line_range(line)
146
+ processed_source.buffer.line_range(line)
149
147
  end
150
148
 
151
- def correction_range
152
- last_special_comment = last_special_comment(processed_source)
149
+ def preceding_comment
150
+ "#{FROZEN_STRING_LITERAL_ENABLED}\n"
151
+ end
153
152
 
154
- if last_special_comment.nil?
155
- range_with_surrounding_space(range: processed_source.tokens[0],
156
- side: :left)
157
- else
158
- last_special_comment.pos
159
- end
153
+ def following_comment
154
+ "\n#{FROZEN_STRING_LITERAL_ENABLED}"
160
155
  end
161
156
  end
162
157
  end