rubocop 1.65.0 → 1.66.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -67
  3. data/config/default.yml +18 -2
  4. data/exe/rubocop +4 -3
  5. data/lib/rubocop/comment_config.rb +1 -1
  6. data/lib/rubocop/config.rb +5 -1
  7. data/lib/rubocop/config_loader.rb +14 -8
  8. data/lib/rubocop/config_loader_resolver.rb +1 -2
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/base.rb +4 -0
  11. data/lib/rubocop/cop/cop.rb +2 -2
  12. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  13. data/lib/rubocop/cop/documentation.rb +18 -1
  14. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  15. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  16. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
  17. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  18. data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
  19. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  20. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  21. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +8 -3
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +0 -3
  23. data/lib/rubocop/cop/layout/line_length.rb +14 -14
  24. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +0 -2
  25. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  26. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  27. data/lib/rubocop/cop/lint/boolean_symbol.rb +0 -2
  28. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  29. data/lib/rubocop/cop/lint/debugger.rb +0 -4
  30. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  31. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +0 -4
  32. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +0 -4
  33. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -10
  34. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  35. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  36. data/lib/rubocop/cop/lint/empty_conditional_body.rb +27 -6
  37. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  38. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  39. data/lib/rubocop/cop/lint/empty_when.rb +0 -2
  40. data/lib/rubocop/cop/lint/ensure_return.rb +1 -6
  41. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  42. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  43. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +5 -7
  44. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  45. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  46. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  47. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +0 -4
  48. data/lib/rubocop/cop/lint/loop.rb +6 -12
  49. data/lib/rubocop/cop/lint/nested_method_definition.rb +0 -6
  50. data/lib/rubocop/cop/lint/next_without_accumulator.rb +0 -4
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  52. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  53. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  54. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  55. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  56. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  57. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +0 -4
  58. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  60. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  61. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +0 -4
  62. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +6 -10
  63. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  64. data/lib/rubocop/cop/lint/unreachable_code.rb +0 -5
  65. data/lib/rubocop/cop/lint/useless_assignment.rb +19 -16
  66. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  67. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
  68. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  69. data/lib/rubocop/cop/lint/void.rb +30 -8
  70. data/lib/rubocop/cop/metrics/block_length.rb +6 -5
  71. data/lib/rubocop/cop/metrics/class_length.rb +6 -5
  72. data/lib/rubocop/cop/metrics/method_length.rb +6 -5
  73. data/lib/rubocop/cop/metrics/module_length.rb +6 -5
  74. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  75. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -9
  76. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
  77. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  78. data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
  79. data/lib/rubocop/cop/naming/predicate_name.rb +52 -26
  80. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -1
  81. data/lib/rubocop/cop/style/alias.rb +1 -1
  82. data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -3
  83. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  84. data/lib/rubocop/cop/style/each_for_simple_loop.rb +0 -1
  85. data/lib/rubocop/cop/style/empty_else.rb +6 -5
  86. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  87. data/lib/rubocop/cop/style/empty_literal.rb +31 -22
  88. data/lib/rubocop/cop/style/eval_with_location.rb +12 -11
  89. data/lib/rubocop/cop/style/file_read.rb +2 -5
  90. data/lib/rubocop/cop/style/file_write.rb +2 -5
  91. data/lib/rubocop/cop/style/format_string_token.rb +2 -2
  92. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  93. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  94. data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
  95. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +0 -1
  96. data/lib/rubocop/cop/style/if_with_semicolon.rb +45 -6
  97. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  98. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  99. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  100. data/lib/rubocop/cop/style/map_into_array.rb +12 -5
  101. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  102. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -2
  103. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  104. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  105. data/lib/rubocop/cop/style/multiple_comparison.rb +3 -11
  106. data/lib/rubocop/cop/style/numeric_predicate.rb +2 -2
  107. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  108. data/lib/rubocop/cop/style/parallel_assignment.rb +5 -4
  109. data/lib/rubocop/cop/style/quoted_symbols.rb +0 -2
  110. data/lib/rubocop/cop/style/redundant_condition.rb +3 -3
  111. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  112. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -1
  113. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -24
  114. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  115. data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -2
  116. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  117. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  118. data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -1
  119. data/lib/rubocop/cop/team.rb +6 -2
  120. data/lib/rubocop/cop/variable_force.rb +13 -1
  121. data/lib/rubocop/core_ext/string.rb +2 -6
  122. data/lib/rubocop/ext/regexp_node.rb +9 -31
  123. data/lib/rubocop/formatter/junit_formatter.rb +70 -23
  124. data/lib/rubocop/lockfile.rb +6 -4
  125. data/lib/rubocop/options.rb +3 -1
  126. data/lib/rubocop/remote_config.rb +5 -1
  127. data/lib/rubocop/result_cache.rb +2 -8
  128. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  129. data/lib/rubocop/server/cache.rb +1 -1
  130. data/lib/rubocop/target_ruby.rb +7 -3
  131. data/lib/rubocop/version.rb +1 -1
  132. data/lib/rubocop/yaml_duplication_checker.rb +1 -0
  133. data/lib/rubocop.rb +7 -1
  134. metadata +8 -26
@@ -8,10 +8,11 @@ module RuboCop
8
8
  # The maximum allowed length is configurable.
9
9
  #
10
10
  # You can set constructs you want to fold with `CountAsOne`.
11
- # Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
12
- # will be counted as one line regardless of its actual size.
13
11
  #
14
- # @example CountAsOne: ['array', 'heredoc', 'method_call']
12
+ # Available are: 'array', 'hash', 'heredoc', and 'method_call'.
13
+ # Each construct will be counted as one line regardless of its actual size.
14
+ #
15
+ # @example CountAsOne: ['array', 'hash', 'heredoc', 'method_call']
15
16
  #
16
17
  # module M
17
18
  # ARRAY = [ # +1
@@ -19,7 +20,7 @@ module RuboCop
19
20
  # 2
20
21
  # ]
21
22
  #
22
- # HASH = { # +3
23
+ # HASH = { # +1
23
24
  # key: 'value'
24
25
  # }
25
26
  #
@@ -32,7 +33,7 @@ module RuboCop
32
33
  # 1,
33
34
  # 2
34
35
  # )
35
- # end # 6 points
36
+ # end # 4 points
36
37
  #
37
38
  class ModuleLength < Base
38
39
  include CodeLength
@@ -4,8 +4,6 @@ module RuboCop
4
4
  module Cop
5
5
  # Representation of an annotation comment in source code (eg. `# TODO: blah blah blah`).
6
6
  class AnnotationComment
7
- extend Forwardable
8
-
9
7
  attr_reader :comment, :margin, :keyword, :colon, :space, :note
10
8
 
11
9
  # @param [Parser::Source::Comment] comment
@@ -20,7 +20,7 @@ module RuboCop
20
20
 
21
21
  def frozen_string_literal?(node)
22
22
  frozen_string = if target_ruby_version >= 3.0
23
- uninterpolated_string?(node) || frozen_heredoc?(node)
23
+ uninterpolated_string?(node) || uninterpolated_heredoc?(node)
24
24
  else
25
25
  FROZEN_STRING_LITERAL_TYPES_RUBY27.include?(node.type)
26
26
  end
@@ -32,29 +32,39 @@ module RuboCop
32
32
  node.str_type? || (node.dstr_type? && node.each_descendant(:begin).none?)
33
33
  end
34
34
 
35
- def frozen_heredoc?(node)
35
+ def uninterpolated_heredoc?(node)
36
36
  return false unless node.dstr_type? && node.heredoc?
37
37
 
38
38
  node.children.all?(&:str_type?)
39
39
  end
40
+ alias frozen_heredoc? uninterpolated_heredoc?
40
41
 
41
42
  def frozen_string_literals_enabled?
42
43
  ruby_version = processed_source.ruby_version
43
44
  return false unless ruby_version
44
45
 
46
+ # Check if a magic string literal comment specifies what to do
47
+ magic_comments = leading_comment_lines.filter_map { |line| MagicComment.parse(line) }
48
+ if (literal_magic_comment = magic_comments.find(&:frozen_string_literal_specified?))
49
+ return literal_magic_comment.frozen_string_literal?
50
+ end
51
+
45
52
  # TODO: Ruby officially abandon making frozen string literals default
46
53
  # for Ruby 3.0.
47
54
  # https://bugs.ruby-lang.org/issues/11473#note-53
48
- # Whether frozen string literals will be the default after Ruby 3.0
49
- # or not is still unclear as of January 2019.
55
+ # Whether frozen string literals will be the default after Ruby 4.0
56
+ # or not is still unclear as of July 2024.
50
57
  # It may be necessary to add this code in the future.
51
58
  #
52
- # return true if ruby_version >= 3.1
59
+ # return ruby_version >= 4.0 if string_literals_frozen_by_default?.nil?
53
60
  #
54
- # And the above `ruby_version >= 3.1` is undecided whether it will be
55
- # Ruby 3.1, 3.2, 4.0 or others.
56
- # See https://bugs.ruby-lang.org/issues/8976#note-41 for details.
57
- leading_comment_lines.any? { |line| MagicComment.parse(line).frozen_string_literal? }
61
+ # And the above `ruby_version >= 4.0` is undecided whether it will be
62
+ # Ruby 4.0 or others.
63
+ # See https://bugs.ruby-lang.org/issues/20205 for details.
64
+ # For now, offer a configuration value to override behavior is using RUBYOPT.
65
+ return false if string_literals_frozen_by_default?.nil?
66
+
67
+ string_literals_frozen_by_default?
58
68
  end
59
69
 
60
70
  def frozen_string_literals_disabled?
@@ -91,8 +91,13 @@ module RuboCop
91
91
  end
92
92
 
93
93
  def uri_regexp
94
- @uri_regexp ||=
95
- URI::DEFAULT_PARSER.make_regexp(config.for_cop('Layout/LineLength')['URISchemes'])
94
+ @uri_regexp ||= begin
95
+ # Ruby 3.4 changes the default parser to RFC3986 which warns on make_regexp.
96
+ # Additionally, the RFC2396_PARSER alias is only available on 3.4 for now.
97
+ # Extra info at https://github.com/ruby/uri/issues/118
98
+ parser = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
99
+ parser.make_regexp(config.for_cop('Layout/LineLength')['URISchemes'])
100
+ end
96
101
  end
97
102
 
98
103
  def valid_uri?(uri_ish_string)
@@ -16,6 +16,18 @@ module RuboCop
16
16
  !/" | \\[^'\\] | \#[@{$]/x.match?(src)
17
17
  end
18
18
  end
19
+
20
+ def preferred_string_literal
21
+ enforce_double_quotes? ? '""' : "''"
22
+ end
23
+
24
+ def enforce_double_quotes?
25
+ string_literals_config['EnforcedStyle'] == 'double_quotes'
26
+ end
27
+
28
+ def string_literals_config
29
+ config.for_cop('Style/StringLiterals')
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -40,6 +40,7 @@ module RuboCop
40
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
41
41
 
42
42
  def on_def(node)
43
+ return unless proper_attribute_name?(node)
43
44
  return unless bad_reader_name?(node) || bad_writer_name?(node)
44
45
 
45
46
  message = message(node)
@@ -58,6 +59,10 @@ module RuboCop
58
59
  end
59
60
  end
60
61
 
62
+ def proper_attribute_name?(node)
63
+ !node.method_name.to_s.end_with?('!', '?', '=')
64
+ end
65
+
61
66
  def bad_reader_name?(node)
62
67
  node.method_name.to_s.start_with?('get_') && !node.arguments?
63
68
  end
@@ -3,59 +3,75 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # Checks that predicate methods names end with a question mark and
6
+ # Checks that predicate method names end with a question mark and
7
7
  # do not start with a forbidden prefix.
8
8
  #
9
- # A method is determined to be a predicate method if its name starts
10
- # with one of the prefixes defined in the `NamePrefix` configuration.
11
- # You can change what prefixes are considered by changing this option.
12
- # Any method name that starts with one of these prefixes is required by
13
- # the cop to end with a `?`. Other methods can be allowed by adding to
14
- # the `AllowedMethods` configuration.
9
+ # A method is determined to be a predicate method if its name starts with
10
+ # one of the prefixes listed in the `NamePrefix` configuration. The list
11
+ # defaults to `is_`, `has_`, and `have_` but may be overridden.
15
12
  #
16
- # NOTE: The `is_a?` method is allowed by default.
13
+ # Predicate methods must end with a question mark.
17
14
  #
18
- # If `ForbiddenPrefixes` is set, methods that start with the configured
19
- # prefixes will not be allowed and will be removed by autocorrection.
15
+ # When `ForbiddenPrefixes` is also set (as it is by default), predicate
16
+ # methods which begin with a forbidden prefix are not allowed, even if
17
+ # they end with a `?`. These methods should be changed to remove the
18
+ # prefix.
20
19
  #
21
- # In other words, if `ForbiddenPrefixes` is empty, a method named `is_foo`
22
- # will register an offense only due to the lack of question mark (and will be
23
- # autocorrected to `is_foo?`). If `ForbiddenPrefixes` contains `is_`,
24
- # `is_foo` will register an offense both because the ? is missing and because of
25
- # the `is_` prefix, and will be corrected to `foo?`.
26
- #
27
- # NOTE: `ForbiddenPrefixes` is only applied to prefixes in `NamePrefix`;
28
- # a prefix in the former but not the latter will not be considered by
29
- # this cop.
30
- #
31
- # @example
20
+ # @example NamePrefix: ['is_', 'has_', 'have_'] (default)
32
21
  # # bad
33
22
  # def is_even(value)
34
23
  # end
35
24
  #
36
- # def is_even?(value)
25
+ # # When ForbiddenPrefixes: ['is_', 'has_', 'have_'] (default)
26
+ # # good
27
+ # def even?(value)
37
28
  # end
38
29
  #
30
+ # # When ForbiddenPrefixes: []
39
31
  # # good
40
- # def even?(value)
32
+ # def is_even?(value)
41
33
  # end
42
34
  #
35
+ # @example NamePrefix: ['seems_to_be_']
43
36
  # # bad
44
- # def has_value
37
+ # def seems_to_be_even(value)
45
38
  # end
46
39
  #
47
- # def has_value?
40
+ # # When ForbiddenPrefixes: ['seems_to_be_']
41
+ # # good
42
+ # def even?(value)
48
43
  # end
49
44
  #
45
+ # # When ForbiddenPrefixes: []
50
46
  # # good
51
- # def value?
47
+ # def seems_to_be_even?(value)
52
48
  # end
53
49
  #
54
50
  # @example AllowedMethods: ['is_a?'] (default)
51
+ # # Despite starting with the `is_` prefix, this method is allowed
55
52
  # # good
56
53
  # def is_a?(value)
57
54
  # end
58
55
  #
56
+ # @example AllowedMethods: ['is_even?']
57
+ # # good
58
+ # def is_even?(value)
59
+ # end
60
+ #
61
+ # @example MethodDefinitionMacros: ['define_method', 'define_singleton_method'] (default)
62
+ # # bad
63
+ # define_method(:is_even) { |value| }
64
+ #
65
+ # # good
66
+ # define_method(:even?) { |value| }
67
+ #
68
+ # @example MethodDefinitionMacros: ['def_node_matcher']
69
+ # # bad
70
+ # def_node_matcher(:is_even) { |value| }
71
+ #
72
+ # # good
73
+ # def_node_matcher(:even?) { |value| }
74
+ #
59
75
  class PredicateName < Base
60
76
  include AllowedMethods
61
77
 
@@ -93,6 +109,16 @@ module RuboCop
93
109
  end
94
110
  alias on_defs on_def
95
111
 
112
+ def validate_config
113
+ forbidden_prefixes.each do |forbidden_prefix|
114
+ next if predicate_prefixes.include?(forbidden_prefix)
115
+
116
+ raise ValidationError, <<~MSG.chomp
117
+ The `Naming/PredicateName` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
118
+ MSG
119
+ end
120
+ end
121
+
96
122
  private
97
123
 
98
124
  def allowed_method_name?(method_name, prefix)
@@ -113,13 +113,21 @@ module RuboCop
113
113
  end
114
114
  end
115
115
 
116
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
116
117
  def correct_node(corrector, node, offending_name, preferred_name)
117
118
  return unless node
118
119
 
119
120
  node.each_node(:lvar, :lvasgn, :masgn) do |child_node|
120
121
  next unless variable_name_matches?(child_node, offending_name)
121
122
 
122
- corrector.replace(child_node, preferred_name) if child_node.lvar_type?
123
+ if child_node.lvar_type?
124
+ parent_node = child_node.parent
125
+ if parent_node.respond_to?(:value_omission?) && parent_node.value_omission?
126
+ corrector.insert_after(parent_node.loc.operator, " #{preferred_name}")
127
+ else
128
+ corrector.replace(child_node, preferred_name)
129
+ end
130
+ end
123
131
 
124
132
  if child_node.masgn_type? || child_node.lvasgn_type?
125
133
  correct_reassignment(corrector, child_node, offending_name, preferred_name)
@@ -127,6 +135,7 @@ module RuboCop
127
135
  end
128
136
  end
129
137
  end
138
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
130
139
 
131
140
  # If the exception variable is reassigned, that assignment needs to be corrected.
132
141
  # Further `lvar` nodes will not be corrected though since they now refer to a
@@ -80,7 +80,7 @@ module RuboCop
80
80
  def alias_method_possible?(node)
81
81
  scope_type(node) != :instance_eval &&
82
82
  node.children.none?(&:gvar_type?) &&
83
- node&.parent&.type != :def
83
+ node.each_ancestor(:def).none?
84
84
  end
85
85
 
86
86
  def add_offense_for_args(node, &block)
@@ -334,13 +334,18 @@ module RuboCop
334
334
  end
335
335
  end
336
336
 
337
+ # rubocop:disable Metrics/AbcSize
337
338
  def arguments_range(node, first_node)
338
- arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
339
+ arguments = node.arguments.reject do |arg|
340
+ next true if ADDITIONAL_ARG_TYPES.include?(arg.type) || arg.variable? || arg.call_type?
339
341
 
340
- start_node = first_node || arguments.first
342
+ arg.literal? && arg.each_descendant(:kwsplat).none?
343
+ end
341
344
 
342
- range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
345
+ start_node = first_node || arguments.first
346
+ start_node.source_range.begin.join(arguments.last.source_range.end)
343
347
  end
348
+ # rubocop:enable Metrics/AbcSize
344
349
 
345
350
  def allow_only_rest_arguments?
346
351
  cop_config.fetch('AllowOnlyRestArgument', true)
@@ -28,8 +28,6 @@ module RuboCop
28
28
  # # good (without parentheses it's a syntax error)
29
29
  # def foo() do_something end
30
30
  #
31
- # @example
32
- #
33
31
  # # bad
34
32
  # def Baz.foo()
35
33
  # do_something
@@ -16,7 +16,6 @@ module RuboCop
16
16
  # # good
17
17
  # 5.times { }
18
18
  #
19
- # @example
20
19
  # # bad
21
20
  # (0...10).each {}
22
21
  #
@@ -143,7 +143,7 @@ module RuboCop
143
143
  private
144
144
 
145
145
  def check(node)
146
- return if cop_config['AllowComments'] && comment_in_else?(node.loc)
146
+ return if cop_config['AllowComments'] && comment_in_else?(node)
147
147
 
148
148
  empty_check(node) if empty_style?
149
149
  nil_check(node) if nil_style?
@@ -171,16 +171,17 @@ module RuboCop
171
171
 
172
172
  def autocorrect(corrector, node)
173
173
  return false if autocorrect_forbidden?(node.type.to_s)
174
- return false if comment_in_else?(node.loc)
174
+ return false if comment_in_else?(node)
175
175
 
176
176
  end_pos = base_node(node).loc.end.begin_pos
177
177
  corrector.remove(range_between(node.loc.else.begin_pos, end_pos))
178
178
  end
179
179
 
180
- def comment_in_else?(loc)
181
- return false if loc.else.nil? || loc.end.nil?
180
+ def comment_in_else?(node)
181
+ node = node.parent while node.if_type? && node.elsif?
182
+ return false unless node.else?
182
183
 
183
- processed_source.contains_comment?(loc.else.join(loc.end))
184
+ processed_source.contains_comment?(node.loc.else.join(node.source_range.end))
184
185
  end
185
186
 
186
187
  def base_node(node)
@@ -36,6 +36,7 @@ module RuboCop
36
36
  class EmptyHeredoc < Base
37
37
  include Heredoc
38
38
  include RangeHelp
39
+ include StringLiteralsHelp
39
40
  extend AutoCorrector
40
41
 
41
42
  MSG = 'Use an empty string literal instead of heredoc.'
@@ -53,20 +54,6 @@ module RuboCop
53
54
  corrector.remove(range_by_whole_lines(heredoc_end, include_final_newline: true))
54
55
  end
55
56
  end
56
-
57
- private
58
-
59
- def preferred_string_literal
60
- enforce_double_quotes? ? '""' : "''"
61
- end
62
-
63
- def enforce_double_quotes?
64
- string_literals_config['EnforcedStyle'] == 'double_quotes'
65
- end
66
-
67
- def string_literals_config
68
- config.for_cop('Style/StringLiterals')
69
- end
70
57
  end
71
58
  end
72
59
  end
@@ -9,7 +9,9 @@ module RuboCop
9
9
  # @example
10
10
  # # bad
11
11
  # a = Array.new
12
+ # a = Array[]
12
13
  # h = Hash.new
14
+ # h = Hash[]
13
15
  # s = String.new
14
16
  #
15
17
  # # good
@@ -19,16 +21,17 @@ module RuboCop
19
21
  class EmptyLiteral < Base
20
22
  include FrozenStringLiteral
21
23
  include RangeHelp
24
+ include StringLiteralsHelp
22
25
  extend AutoCorrector
23
26
 
24
- ARR_MSG = 'Use array literal `[]` instead of `Array.new`.'
25
- HASH_MSG = 'Use hash literal `{}` instead of `Hash.new`.'
27
+ ARR_MSG = 'Use array literal `[]` instead of `%<current>s`.'
28
+ HASH_MSG = 'Use hash literal `{}` instead of `%<current>s`.'
26
29
  STR_MSG = 'Use string literal `%<prefer>s` instead of `String.new`.'
27
30
 
28
- RESTRICT_ON_SEND = %i[new].freeze
31
+ RESTRICT_ON_SEND = %i[new [] Array Hash].freeze
29
32
 
30
33
  # @!method array_node(node)
31
- def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new)'
34
+ def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new (array)?)'
32
35
 
33
36
  # @!method hash_node(node)
34
37
  def_node_matcher :hash_node, '(send (const {nil? cbase} :Hash) :new)'
@@ -47,6 +50,22 @@ module RuboCop
47
50
  }
48
51
  PATTERN
49
52
 
53
+ # @!method array_with_index(node)
54
+ def_node_matcher :array_with_index, <<~PATTERN
55
+ {
56
+ (send (const {nil? cbase} :Array) :[])
57
+ (send nil? :Array (array))
58
+ }
59
+ PATTERN
60
+
61
+ # @!method hash_with_index(node)
62
+ def_node_matcher :hash_with_index, <<~PATTERN
63
+ {
64
+ (send (const {nil? cbase} :Hash) :[])
65
+ (send nil? :Hash (array))
66
+ }
67
+ PATTERN
68
+
50
69
  def on_send(node)
51
70
  return unless (message = offense_message(node))
52
71
 
@@ -59,26 +78,14 @@ module RuboCop
59
78
 
60
79
  def offense_message(node)
61
80
  if offense_array_node?(node)
62
- ARR_MSG
81
+ format(ARR_MSG, current: node.source)
63
82
  elsif offense_hash_node?(node)
64
- HASH_MSG
83
+ format(HASH_MSG, current: node.source)
65
84
  elsif str_node(node) && !frozen_strings?
66
85
  format(STR_MSG, prefer: preferred_string_literal)
67
86
  end
68
87
  end
69
88
 
70
- def preferred_string_literal
71
- enforce_double_quotes? ? '""' : "''"
72
- end
73
-
74
- def enforce_double_quotes?
75
- string_literals_config['EnforcedStyle'] == 'double_quotes'
76
- end
77
-
78
- def string_literals_config
79
- config.for_cop('Style/StringLiterals')
80
- end
81
-
82
89
  def first_argument_unparenthesized?(node)
83
90
  parent = node.parent
84
91
  return false unless parent && %i[send super zsuper].include?(parent.type)
@@ -100,12 +107,12 @@ module RuboCop
100
107
  end
101
108
 
102
109
  def offense_array_node?(node)
103
- array_node(node) && !array_with_block(node.parent)
110
+ (array_node(node) && !array_with_block(node.parent)) || array_with_index(node)
104
111
  end
105
112
 
106
113
  def offense_hash_node?(node)
107
114
  # If Hash.new takes a block, it can't be changed to {}.
108
- hash_node(node) && !hash_with_block(node.parent)
115
+ (hash_node(node) && !hash_with_block(node.parent)) || hash_with_index(node)
109
116
  end
110
117
 
111
118
  def correction(node)
@@ -129,8 +136,10 @@ module RuboCop
129
136
  def frozen_strings?
130
137
  return true if frozen_string_literals_enabled?
131
138
 
132
- frozen_string_cop_enabled = config.for_cop('Style/FrozenStringLiteral')['Enabled']
133
- frozen_string_cop_enabled && !frozen_string_literals_disabled?
139
+ frozen_string_cop_enabled = config.for_cop('Style/FrozenStringLiteralComment')['Enabled']
140
+ frozen_string_cop_enabled &&
141
+ !frozen_string_literals_disabled? &&
142
+ string_literals_frozen_by_default?.nil?
134
143
  end
135
144
  end
136
145
  end
@@ -17,6 +17,18 @@ module RuboCop
17
17
  # will not attempt to automatically add a binding, or add filename and
18
18
  # line values.
19
19
  #
20
+ # NOTE: This cop works only when a string literal is given as a code string.
21
+ # No offense is reported if a string variable is given as below:
22
+ #
23
+ # [source,ruby]
24
+ # ----
25
+ # code = <<-RUBY
26
+ # def do_something
27
+ # end
28
+ # RUBY
29
+ # eval code # not checked.
30
+ # ----
31
+ #
20
32
  # @example
21
33
  # # bad
22
34
  # eval <<-RUBY
@@ -42,17 +54,6 @@ module RuboCop
42
54
  # end
43
55
  # RUBY
44
56
  #
45
- # This cop works only when a string literal is given as a code string.
46
- # No offense is reported if a string variable is given as below:
47
- #
48
- # @example
49
- # # not checked
50
- # code = <<-RUBY
51
- # def do_something
52
- # end
53
- # RUBY
54
- # eval code
55
- #
56
57
  class EvalWithLocation < Base
57
58
  extend AutoCorrector
58
59
 
@@ -6,8 +6,7 @@ module RuboCop
6
6
  # Favor `File.(bin)read` convenience methods.
7
7
  #
8
8
  # @example
9
- # ## text mode
10
- # # bad
9
+ # # bad - text mode
11
10
  # File.open(filename).read
12
11
  # File.open(filename, &:read)
13
12
  # File.open(filename) { |f| f.read }
@@ -23,9 +22,7 @@ module RuboCop
23
22
  # # good
24
23
  # File.read(filename)
25
24
  #
26
- # @example
27
- # ## binary mode
28
- # # bad
25
+ # # bad - binary mode
29
26
  # File.open(filename, 'rb').read
30
27
  # File.open(filename, 'rb', &:read)
31
28
  # File.open(filename, 'rb') do |f|
@@ -17,8 +17,7 @@ module RuboCop
17
17
  # ----
18
18
  #
19
19
  # @example
20
- # ## text mode
21
- # # bad
20
+ # # bad - text mode
22
21
  # File.open(filename, 'w').write(content)
23
22
  # File.open(filename, 'w') do |f|
24
23
  # f.write(content)
@@ -27,9 +26,7 @@ module RuboCop
27
26
  # # good
28
27
  # File.write(filename, content)
29
28
  #
30
- # @example
31
- # ## binary mode
32
- # # bad
29
+ # # bad - binary mode
33
30
  # File.open(filename, 'wb').write(content)
34
31
  # File.open(filename, 'wb') do |f|
35
32
  # f.write(content)
@@ -11,8 +11,8 @@ module RuboCop
11
11
  # The reason is that _unannotated_ format is very similar
12
12
  # to encoded URLs or Date/Time formatting strings.
13
13
  #
14
- # This cop can be customized allowed methods with `AllowedMethods`.
15
- # By default, there are no methods to allowed.
14
+ # This cop's allowed methods can be customized with `AllowedMethods`.
15
+ # By default, there are no allowed methods.
16
16
  #
17
17
  # @example EnforcedStyle: annotated (default)
18
18
  #
@@ -44,7 +44,9 @@ module RuboCop
44
44
  PATTERN
45
45
 
46
46
  def on_const(node)
47
- const_name = node.children[1]
47
+ return if namespaced?(node)
48
+
49
+ const_name = node.short_name
48
50
  return unless STD_STREAMS.include?(const_name)
49
51
 
50
52
  gvar_name = gvar_name(const_name).to_sym
@@ -61,6 +63,10 @@ module RuboCop
61
63
  format(MSG, gvar_name: gvar_name(const_name), const_name: const_name)
62
64
  end
63
65
 
66
+ def namespaced?(node)
67
+ !node.namespace.nil? && (node.relative? || !node.namespace.cbase_type?)
68
+ end
69
+
64
70
  def gvar_name(const_name)
65
71
  "$#{const_name.to_s.downcase}"
66
72
  end
@@ -277,6 +277,8 @@ module RuboCop
277
277
  end
278
278
 
279
279
  def trivial?(node)
280
+ return false unless node.if_branch
281
+
280
282
  node.branches.one? && !node.if_branch.if_type? && !node.if_branch.begin_type?
281
283
  end
282
284
 
@@ -155,7 +155,7 @@ module RuboCop
155
155
  condition_variable = assignable_condition_value(node)
156
156
 
157
157
  head = heads.first
158
- if head.assignment?
158
+ if head.respond_to?(:assignment?) && head.assignment?
159
159
  # The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
160
160
  # https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
161
161
  #