rubocop 1.75.8 → 1.79.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.
- checksums.yaml +4 -4
- data/README.md +20 -16
- data/config/default.yml +107 -26
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -5
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +127 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +306 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +53 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +35 -5
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +18 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -4
- data/lib/rubocop/lsp/routes.rb +4 -4
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +11 -1
- data/lib/ruby_lsp/rubocop/addon.rb +2 -2
- metadata +21 -8
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for useless OR (`||` and `or`) expressions.
|
7
|
+
#
|
8
|
+
# Some methods always return a truthy value, even when called
|
9
|
+
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
10
|
+
# appended after these methods will never evaluate.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# x.to_a || fallback
|
16
|
+
# x.to_c || fallback
|
17
|
+
# x.to_d || fallback
|
18
|
+
# x.to_i || fallback
|
19
|
+
# x.to_f || fallback
|
20
|
+
# x.to_h || fallback
|
21
|
+
# x.to_r || fallback
|
22
|
+
# x.to_s || fallback
|
23
|
+
# x.to_sym || fallback
|
24
|
+
# x.intern || fallback
|
25
|
+
# x.inspect || fallback
|
26
|
+
# x.hash || fallback
|
27
|
+
# x.object_id || fallback
|
28
|
+
# x.__id__ || fallback
|
29
|
+
#
|
30
|
+
# x.to_s or fallback
|
31
|
+
#
|
32
|
+
# # good - if fallback is same as return value of method called on nil
|
33
|
+
# x.to_a # nil.to_a returns []
|
34
|
+
# x.to_c # nil.to_c returns (0+0i)
|
35
|
+
# x.to_d # nil.to_d returns 0.0
|
36
|
+
# x.to_i # nil.to_i returns 0
|
37
|
+
# x.to_f # nil.to_f returns 0.0
|
38
|
+
# x.to_h # nil.to_h returns {}
|
39
|
+
# x.to_r # nil.to_r returns (0/1)
|
40
|
+
# x.to_s # nil.to_s returns ''
|
41
|
+
# x.to_sym # nil.to_sym raises an error
|
42
|
+
# x.intern # nil.intern raises an error
|
43
|
+
# x.inspect # nil.inspect returns "nil"
|
44
|
+
# x.hash # nil.hash returns an Integer
|
45
|
+
# x.object_id # nil.object_id returns an Integer
|
46
|
+
# x.__id__ # nil.object_id returns an Integer
|
47
|
+
#
|
48
|
+
# # good - if the intention is not to call the method on nil
|
49
|
+
# x&.to_a || fallback
|
50
|
+
# x&.to_c || fallback
|
51
|
+
# x&.to_d || fallback
|
52
|
+
# x&.to_i || fallback
|
53
|
+
# x&.to_f || fallback
|
54
|
+
# x&.to_h || fallback
|
55
|
+
# x&.to_r || fallback
|
56
|
+
# x&.to_s || fallback
|
57
|
+
# x&.to_sym || fallback
|
58
|
+
# x&.intern || fallback
|
59
|
+
# x&.inspect || fallback
|
60
|
+
# x&.hash || fallback
|
61
|
+
# x&.object_id || fallback
|
62
|
+
# x&.__id__ || fallback
|
63
|
+
#
|
64
|
+
# x&.to_s or fallback
|
65
|
+
#
|
66
|
+
class UselessOr < Base
|
67
|
+
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
68
|
+
|
69
|
+
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
70
|
+
:to_s, :to_sym, :intern, :inspect, :hash, :object_id,
|
71
|
+
:__id__].freeze
|
72
|
+
|
73
|
+
# @!method truthy_return_value_method?(node)
|
74
|
+
def_node_matcher :truthy_return_value_method?, <<~PATTERN
|
75
|
+
(send _ %TRUTHY_RETURN_VALUE_METHODS)
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def on_or(node)
|
79
|
+
if truthy_return_value_method?(node.lhs)
|
80
|
+
report_offense(node, node.lhs)
|
81
|
+
elsif truthy_return_value_method?(node.rhs)
|
82
|
+
parent = node.parent
|
83
|
+
parent = parent.parent if parent&.begin_type?
|
84
|
+
|
85
|
+
report_offense(parent, node.rhs) if parent&.or_type?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def report_offense(or_node, truthy_node)
|
92
|
+
add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
|
93
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
89
89
|
private
|
90
90
|
|
91
91
|
def inspect_def(node, def_node)
|
92
|
-
return if allowed_arguments(def_node.arguments)
|
92
|
+
return if allowed_arguments?(def_node.arguments)
|
93
93
|
|
94
94
|
add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
|
95
95
|
end
|
@@ -101,7 +101,7 @@ module RuboCop
|
|
101
101
|
definition = find_method_definition(node, method_name)
|
102
102
|
|
103
103
|
return unless definition
|
104
|
-
return if allowed_arguments(definition.arguments)
|
104
|
+
return if allowed_arguments?(definition.arguments)
|
105
105
|
|
106
106
|
add_offense(node, message: format(MSG, method_name: method_name))
|
107
107
|
end
|
@@ -115,7 +115,7 @@ module RuboCop
|
|
115
115
|
end
|
116
116
|
|
117
117
|
# `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
|
118
|
-
def allowed_arguments(arguments)
|
118
|
+
def allowed_arguments?(arguments)
|
119
119
|
return false if arguments.empty?
|
120
120
|
|
121
121
|
arguments.each_child_node(:restarg).any? &&
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
module Utils
|
7
|
+
# Utility class that checks if the receiver can't be nil.
|
8
|
+
class NilReceiverChecker
|
9
|
+
NIL_METHODS = (nil.methods + %i[!]).to_set.freeze
|
10
|
+
|
11
|
+
def initialize(receiver, additional_nil_methods)
|
12
|
+
@receiver = receiver
|
13
|
+
@additional_nil_methods = additional_nil_methods
|
14
|
+
@checked_nodes = {}.compare_by_identity
|
15
|
+
end
|
16
|
+
|
17
|
+
def cant_be_nil?
|
18
|
+
sole_condition_of_parent_if?(@receiver) || _cant_be_nil?(@receiver.parent, @receiver)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# rubocop:disable Metrics
|
24
|
+
def _cant_be_nil?(node, receiver)
|
25
|
+
return false unless node
|
26
|
+
|
27
|
+
# For some nodes, we check their parent and then some children for these parents.
|
28
|
+
# This is added to avoid infinite loops.
|
29
|
+
return false if @checked_nodes.key?(node)
|
30
|
+
|
31
|
+
@checked_nodes[node] = true
|
32
|
+
|
33
|
+
case node.type
|
34
|
+
when :def, :class, :module, :sclass
|
35
|
+
return false
|
36
|
+
when :send
|
37
|
+
return non_nil_method?(node.method_name) if node.receiver == receiver
|
38
|
+
|
39
|
+
node.arguments.each do |argument|
|
40
|
+
return true if _cant_be_nil?(argument, receiver)
|
41
|
+
end
|
42
|
+
|
43
|
+
return true if _cant_be_nil?(node.receiver, receiver)
|
44
|
+
when :begin
|
45
|
+
return true if _cant_be_nil?(node.children.first, receiver)
|
46
|
+
when :if, :case
|
47
|
+
return true if _cant_be_nil?(node.condition, receiver)
|
48
|
+
when :and, :or
|
49
|
+
return true if _cant_be_nil?(node.lhs, receiver)
|
50
|
+
when :pair
|
51
|
+
if _cant_be_nil?(node.key, receiver) ||
|
52
|
+
_cant_be_nil?(node.value, receiver)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
when :when
|
56
|
+
node.each_condition do |condition|
|
57
|
+
return true if _cant_be_nil?(condition, receiver)
|
58
|
+
end
|
59
|
+
when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
|
60
|
+
return true if _cant_be_nil?(node.expression, receiver)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
|
64
|
+
# using left_siblings will not work correctly for them.
|
65
|
+
if !else_branch?(node) || (node.if_type? && !node.elsif?)
|
66
|
+
node.left_siblings.reverse_each do |sibling|
|
67
|
+
next unless sibling.is_a?(AST::Node)
|
68
|
+
|
69
|
+
return true if _cant_be_nil?(sibling, receiver)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if node.parent
|
74
|
+
_cant_be_nil?(node.parent, receiver)
|
75
|
+
else
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
# rubocop:enable Metrics
|
80
|
+
|
81
|
+
def non_nil_method?(method_name)
|
82
|
+
!NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
def sole_condition_of_parent_if?(node)
|
87
|
+
parent = node.parent
|
88
|
+
|
89
|
+
while parent
|
90
|
+
if parent.if_type?
|
91
|
+
if parent.condition == node
|
92
|
+
return true
|
93
|
+
elsif parent.elsif?
|
94
|
+
parent = find_top_if(parent)
|
95
|
+
end
|
96
|
+
elsif else_branch?(parent)
|
97
|
+
# Find the top `if` for `else`.
|
98
|
+
parent = parent.parent
|
99
|
+
end
|
100
|
+
|
101
|
+
parent = parent&.parent
|
102
|
+
end
|
103
|
+
|
104
|
+
false
|
105
|
+
end
|
106
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
107
|
+
|
108
|
+
def else_branch?(node)
|
109
|
+
node.parent&.if_type? && node.parent.else_branch == node
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_top_if(node)
|
113
|
+
node = node.parent while node.elsif?
|
114
|
+
|
115
|
+
node
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
end
|
67
67
|
|
68
68
|
# @deprecated Use processed_source.line_with_comment?(line)
|
69
|
-
def end_of_line_comment(line)
|
69
|
+
def end_of_line_comment(line) # rubocop:disable Naming/PredicateMethod
|
70
70
|
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
71
71
|
`end_of_line_comment` is deprecated. Use `processed_source.line_with_comment?` instead.
|
72
72
|
WARNING
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
89
89
|
|
90
90
|
if first_non_comment_token
|
91
91
|
# `line` is 1-indexed so we need to subtract 1 to get the array index
|
92
|
-
processed_source.lines[0...first_non_comment_token.line - 1]
|
92
|
+
processed_source.lines[0...(first_non_comment_token.line - 1)]
|
93
93
|
else
|
94
94
|
processed_source.lines
|
95
95
|
end
|
@@ -25,6 +25,28 @@ module RuboCop
|
|
25
25
|
(args
|
26
26
|
(arg $_)) ...)
|
27
27
|
PATTERN
|
28
|
+
|
29
|
+
# @!method assignment_method_declarations(node)
|
30
|
+
def_node_search :assignment_method_declarations, <<~PATTERN
|
31
|
+
(send
|
32
|
+
(lvar {#match_block_variable_name? :_1 :it}) _ ...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
# @!method indexed_assignment_method_declarations(node)
|
36
|
+
def_node_search :indexed_assignment_method_declarations, <<~PATTERN
|
37
|
+
(send
|
38
|
+
(send (lvar {#match_block_variable_name? :_1 :it}) _)
|
39
|
+
:[]=
|
40
|
+
literal?
|
41
|
+
_
|
42
|
+
)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def match_block_variable_name?(receiver_name)
|
46
|
+
gem_specification(processed_source.ast) do |block_variable_name|
|
47
|
+
return block_variable_name == receiver_name
|
48
|
+
end
|
49
|
+
end
|
28
50
|
end
|
29
51
|
end
|
30
52
|
end
|
@@ -25,20 +25,24 @@ module RuboCop
|
|
25
25
|
config.for_cop('Layout/LineLength')['AllowURI']
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
|
28
|
+
def allow_qualified_name?
|
29
|
+
config.for_cop('Layout/LineLength')['AllowQualifiedName']
|
30
|
+
end
|
31
|
+
|
32
|
+
def allowed_position?(line, range)
|
33
|
+
range.begin < max_line_length && range.end == line_length(line)
|
30
34
|
end
|
31
35
|
|
32
36
|
def line_length(line)
|
33
37
|
line.length + indentation_difference(line)
|
34
38
|
end
|
35
39
|
|
36
|
-
def
|
37
|
-
|
38
|
-
return nil unless
|
40
|
+
def find_excessive_range(line, type)
|
41
|
+
last_match = (type == :uri ? match_uris(line) : match_qualified_names(line)).last
|
42
|
+
return nil unless last_match
|
39
43
|
|
40
|
-
begin_position, end_position =
|
41
|
-
end_position =
|
44
|
+
begin_position, end_position = last_match.offset(0)
|
45
|
+
end_position = extend_end_position(line, end_position)
|
42
46
|
|
43
47
|
line_indentation_difference = indentation_difference(line)
|
44
48
|
begin_position += line_indentation_difference
|
@@ -57,6 +61,14 @@ module RuboCop
|
|
57
61
|
matches
|
58
62
|
end
|
59
63
|
|
64
|
+
def match_qualified_names(string)
|
65
|
+
matches = []
|
66
|
+
string.scan(qualified_name_regexp) do
|
67
|
+
matches << $LAST_MATCH_INFO
|
68
|
+
end
|
69
|
+
matches
|
70
|
+
end
|
71
|
+
|
60
72
|
def indentation_difference(line)
|
61
73
|
return 0 unless tab_indentation_width
|
62
74
|
|
@@ -70,7 +82,7 @@ module RuboCop
|
|
70
82
|
index * (tab_indentation_width - 1)
|
71
83
|
end
|
72
84
|
|
73
|
-
def
|
85
|
+
def extend_end_position(line, end_position)
|
74
86
|
# Extend the end position YARD comments with linked URLs of the form {<uri> <title>}
|
75
87
|
if line&.match(/{(\s|\S)*}$/)
|
76
88
|
match = line[end_position..line_length(line)]&.match(/(\s|\S)*}/)
|
@@ -101,6 +113,10 @@ module RuboCop
|
|
101
113
|
end
|
102
114
|
end
|
103
115
|
|
116
|
+
def qualified_name_regexp
|
117
|
+
/\b(?:[A-Z][A-Za-z0-9_]*::)+[A-Za-z_][A-Za-z0-9_]*\b/
|
118
|
+
end
|
119
|
+
|
104
120
|
def valid_uri?(uri_ish_string)
|
105
121
|
URI.parse(uri_ish_string)
|
106
122
|
true
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
gem_canonical_name(string_a) < gem_canonical_name(string_b)
|
25
25
|
end
|
26
26
|
|
27
|
-
def consecutive_lines(previous, current)
|
27
|
+
def consecutive_lines?(previous, current)
|
28
28
|
first_line = get_source_range(current, treat_comments_as_separators).first_line
|
29
29
|
previous.source_range.last_line == first_line - 1
|
30
30
|
end
|
@@ -152,7 +152,7 @@ module RuboCop
|
|
152
152
|
|
153
153
|
const_namespace, const_name = *const
|
154
154
|
next if name != const_name && !match_acronym?(name, const_name)
|
155
|
-
next unless namespace.empty? ||
|
155
|
+
next unless namespace.empty? || namespace_matches?(child, const_namespace, namespace)
|
156
156
|
|
157
157
|
return node
|
158
158
|
end
|
@@ -169,7 +169,7 @@ module RuboCop
|
|
169
169
|
s(:const, namespace, name) if name
|
170
170
|
end
|
171
171
|
|
172
|
-
def
|
172
|
+
def namespace_matches?(node, namespace, expected)
|
173
173
|
match_partial = partial_matcher!(expected)
|
174
174
|
|
175
175
|
match_partial.call(namespace)
|
@@ -39,6 +39,26 @@ module RuboCop
|
|
39
39
|
# # good
|
40
40
|
# def foo_bar; end
|
41
41
|
#
|
42
|
+
# # bad
|
43
|
+
# define_method :fooBar do
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# define_method :foo_bar do
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# # bad
|
51
|
+
# Struct.new(:fooBar)
|
52
|
+
#
|
53
|
+
# # good
|
54
|
+
# Struct.new(:foo_bar)
|
55
|
+
#
|
56
|
+
# # bad
|
57
|
+
# alias_method :fooBar, :some_method
|
58
|
+
#
|
59
|
+
# # good
|
60
|
+
# alias_method :foo_bar, :some_method
|
61
|
+
#
|
42
62
|
# @example EnforcedStyle: camelCase
|
43
63
|
# # bad
|
44
64
|
# def foo_bar; end
|
@@ -46,6 +66,26 @@ module RuboCop
|
|
46
66
|
# # good
|
47
67
|
# def fooBar; end
|
48
68
|
#
|
69
|
+
# # bad
|
70
|
+
# define_method :foo_bar do
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# # good
|
74
|
+
# define_method :fooBar do
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# # bad
|
78
|
+
# Struct.new(:foo_bar)
|
79
|
+
#
|
80
|
+
# # good
|
81
|
+
# Struct.new(:fooBar)
|
82
|
+
#
|
83
|
+
# # bad
|
84
|
+
# alias_method :foo_bar, :some_method
|
85
|
+
#
|
86
|
+
# # good
|
87
|
+
# alias_method :fooBar, :some_method
|
88
|
+
#
|
49
89
|
# @example ForbiddenIdentifiers: ['def', 'super']
|
50
90
|
# # bad
|
51
91
|
# def def; end
|
@@ -66,13 +106,79 @@ module RuboCop
|
|
66
106
|
MSG = 'Use %<style>s for method names.'
|
67
107
|
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another method name instead.'
|
68
108
|
|
109
|
+
OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * /
|
110
|
+
% ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].to_set.freeze
|
111
|
+
|
69
112
|
# @!method sym_name(node)
|
70
113
|
def_node_matcher :sym_name, '(sym $_name)'
|
71
114
|
|
72
115
|
# @!method str_name(node)
|
73
116
|
def_node_matcher :str_name, '(str $_name)'
|
74
117
|
|
118
|
+
# @!method new_struct?(node)
|
119
|
+
def_node_matcher :new_struct?, '(send (const {nil? cbase} :Struct) :new ...)'
|
120
|
+
|
121
|
+
# @!method define_data?(node)
|
122
|
+
def_node_matcher :define_data?, '(send (const {nil? cbase} :Data) :define ...)'
|
123
|
+
|
75
124
|
def on_send(node)
|
125
|
+
if node.method?(:define_method) || node.method?(:define_singleton_method)
|
126
|
+
handle_define_method(node)
|
127
|
+
elsif new_struct?(node)
|
128
|
+
handle_new_struct(node)
|
129
|
+
elsif define_data?(node)
|
130
|
+
handle_define_data(node)
|
131
|
+
elsif node.method?(:alias_method)
|
132
|
+
handle_alias_method(node)
|
133
|
+
else
|
134
|
+
handle_attr_accessor(node)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def on_def(node)
|
139
|
+
return if node.operator_method? || matches_allowed_pattern?(node.method_name)
|
140
|
+
|
141
|
+
if forbidden_name?(node.method_name.to_s)
|
142
|
+
register_forbidden_name(node)
|
143
|
+
else
|
144
|
+
check_name(node, node.method_name, node.loc.name)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
alias on_defs on_def
|
148
|
+
|
149
|
+
def on_alias(node)
|
150
|
+
handle_method_name(node.new_identifier, node.new_identifier.value)
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def handle_define_method(node)
|
156
|
+
return unless node.first_argument&.type?(:str, :sym)
|
157
|
+
|
158
|
+
handle_method_name(node, node.first_argument.value)
|
159
|
+
end
|
160
|
+
|
161
|
+
def handle_new_struct(node)
|
162
|
+
arguments = node.first_argument&.str_type? ? node.arguments[1..] : node.arguments
|
163
|
+
arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
|
164
|
+
handle_method_name(name, name.value)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def handle_define_data(node)
|
169
|
+
node.arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
|
170
|
+
handle_method_name(name, name.value)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def handle_alias_method(node)
|
175
|
+
return unless node.arguments.size == 2
|
176
|
+
return unless node.first_argument.type?(:str, :sym)
|
177
|
+
|
178
|
+
handle_method_name(node.first_argument, node.first_argument.value)
|
179
|
+
end
|
180
|
+
|
181
|
+
def handle_attr_accessor(node)
|
76
182
|
return unless (attrs = node.attribute_accessor?)
|
77
183
|
|
78
184
|
attrs.last.each do |name_item|
|
@@ -87,45 +193,53 @@ module RuboCop
|
|
87
193
|
end
|
88
194
|
end
|
89
195
|
|
90
|
-
def
|
91
|
-
return if
|
196
|
+
def handle_method_name(node, name)
|
197
|
+
return if !name || matches_allowed_pattern?(name)
|
92
198
|
|
93
|
-
if forbidden_name?(
|
199
|
+
if forbidden_name?(name.to_s)
|
94
200
|
register_forbidden_name(node)
|
95
|
-
|
96
|
-
check_name(node,
|
201
|
+
elsif !OPERATOR_METHODS.include?(name)
|
202
|
+
check_name(node, name, range_position(node))
|
97
203
|
end
|
98
204
|
end
|
99
|
-
alias on_defs on_def
|
100
|
-
|
101
|
-
private
|
102
205
|
|
103
206
|
def forbidden_name?(name)
|
104
207
|
forbidden_identifier?(name) || forbidden_pattern?(name)
|
105
208
|
end
|
106
209
|
|
210
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
107
211
|
def register_forbidden_name(node)
|
108
212
|
if node.any_def_type?
|
109
213
|
name_node = node.loc.name
|
110
214
|
method_name = node.method_name
|
111
|
-
|
112
|
-
|
215
|
+
elsif node.literal?
|
216
|
+
name_node = node
|
217
|
+
method_name = node.value
|
218
|
+
elsif (attrs = node.attribute_accessor?)
|
113
219
|
name_node = attrs.last.last
|
114
220
|
method_name = attr_name(name_node)
|
221
|
+
else
|
222
|
+
name_node = node.first_argument
|
223
|
+
method_name = node.first_argument.value
|
115
224
|
end
|
116
225
|
message = format(MSG_FORBIDDEN, identifier: method_name)
|
117
226
|
add_offense(name_node, message: message)
|
118
227
|
end
|
228
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
119
229
|
|
120
230
|
def attr_name(name_item)
|
121
231
|
sym_name(name_item) || str_name(name_item)
|
122
232
|
end
|
123
233
|
|
124
234
|
def range_position(node)
|
125
|
-
|
126
|
-
|
235
|
+
if node.loc.respond_to?(:selector)
|
236
|
+
selector_end_pos = node.loc.selector.end_pos + 1
|
237
|
+
expr_end_pos = node.source_range.end_pos
|
127
238
|
|
128
|
-
|
239
|
+
range_between(selector_end_pos, expr_end_pos)
|
240
|
+
else
|
241
|
+
node.source_range
|
242
|
+
end
|
129
243
|
end
|
130
244
|
|
131
245
|
def message(style)
|