rubocop 1.65.0 → 1.66.1

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 (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
  #