rubocop 1.20.0 → 1.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +19 -6
- data/lib/rubocop/cop/base.rb +2 -2
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +12 -11
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +107 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +7 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +11 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/collection_methods.rb +2 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +23 -8
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_unless.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
- data/lib/rubocop/cop/style/not.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +17 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -1
- data/lib/rubocop/cop/style/static_class.rb +1 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -7
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +1 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -1
- metadata +5 -3
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
|
52
52
|
def on_case_match(node)
|
53
53
|
node.in_pattern_branches.each do |branch|
|
54
|
-
next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
|
54
|
+
next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
|
55
55
|
|
56
56
|
add_offense(branch)
|
57
57
|
end
|
@@ -118,7 +118,7 @@ module RuboCop
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def correct_arguments?(arguments)
|
121
|
-
arguments.size == 1 || arguments.size == 2 && arguments[1].hash_type?
|
121
|
+
arguments.size == 1 || (arguments.size == 2 && arguments[1].hash_type?)
|
122
122
|
end
|
123
123
|
|
124
124
|
def build_kwargs(node)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
#
|
7
|
+
# This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# IO.select([io], [], [], timeout)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# io.wait_readable(timeout)
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# IO.select([], [io], [], timeout)
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# io.wait_writable(timeout)
|
22
|
+
#
|
23
|
+
class IncompatibleIoSelectWithFiberScheduler < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Use `%<preferred>s` instead of `%<current>s`.'
|
27
|
+
RESTRICT_ON_SEND = %i[select].freeze
|
28
|
+
|
29
|
+
# @!method io_select(node)
|
30
|
+
def_node_matcher :io_select, <<~PATTERN
|
31
|
+
(send
|
32
|
+
(const {nil? cbase} :IO) :select $_ $_ {(array) nil} $...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless (read, write, timeout = io_select(node))
|
37
|
+
return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
|
38
|
+
|
39
|
+
preferred = preferred_method(read, write, timeout)
|
40
|
+
message = format(MSG, preferred: preferred, current: node.source)
|
41
|
+
|
42
|
+
add_offense(node, message: message) do |corrector|
|
43
|
+
corrector.replace(node, preferred)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def scheduler_compatible?(io1, io2)
|
50
|
+
return false unless io1.array_type? && io1.values.size == 1
|
51
|
+
|
52
|
+
io2.array_type? ? io2.values.empty? : io2.nil_type?
|
53
|
+
end
|
54
|
+
|
55
|
+
def preferred_method(read, write, timeout)
|
56
|
+
timeout_argument = timeout.empty? ? '' : "(#{timeout[0].source})"
|
57
|
+
|
58
|
+
if read.array_type? && read.values[0]
|
59
|
+
"#{read.values[0].source}.wait_readable#{timeout_argument}"
|
60
|
+
else
|
61
|
+
"#{write.values[0].source}.wait_writable#{timeout_argument}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -60,6 +60,7 @@ module RuboCop
|
|
60
60
|
'class parsing, instead of using '\
|
61
61
|
'`%<current>s`, use stricter '\
|
62
62
|
'`%<corrected_method>s`.'
|
63
|
+
CONVERSION_METHODS = %i[Integer Float Complex to_i to_f to_c].freeze
|
63
64
|
METHODS = CONVERSION_METHOD_CLASS_MAPPING.keys.map(&:inspect).join(' ')
|
64
65
|
|
65
66
|
# @!method to_method(node)
|
@@ -127,7 +128,8 @@ module RuboCop
|
|
127
128
|
end
|
128
129
|
|
129
130
|
def ignore_receiver?(receiver)
|
130
|
-
if receiver.
|
131
|
+
if receiver.numeric_type? || (receiver.send_type? &&
|
132
|
+
(conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
|
131
133
|
true
|
132
134
|
elsif (receiver = top_receiver(receiver))
|
133
135
|
receiver.const_type? && ignored_class?(receiver.const_name)
|
@@ -142,6 +144,10 @@ module RuboCop
|
|
142
144
|
receiver
|
143
145
|
end
|
144
146
|
|
147
|
+
def conversion_method?(method_name)
|
148
|
+
CONVERSION_METHODS.include?(method_name)
|
149
|
+
end
|
150
|
+
|
145
151
|
def ignored_classes
|
146
152
|
cop_config.fetch('IgnoredClasses', [])
|
147
153
|
end
|
@@ -87,9 +87,8 @@ module RuboCop
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def ignored_method?(body)
|
90
|
-
cop_config['IgnoreEmptyMethods'] && body.nil? ||
|
91
|
-
cop_config['IgnoreNotImplementedMethods'] &&
|
92
|
-
not_implemented?(body)
|
90
|
+
(cop_config['IgnoreEmptyMethods'] && body.nil?) ||
|
91
|
+
(cop_config['IgnoreNotImplementedMethods'] && not_implemented?(body))
|
93
92
|
end
|
94
93
|
|
95
94
|
def message(variable)
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
visit_depth_last(@node) { |child| calculate_node(child) }
|
47
47
|
|
48
48
|
[
|
49
|
-
Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2),
|
49
|
+
Math.sqrt((@assignment**2) + (@branch**2) + (@condition**2)).round(2),
|
50
50
|
"<#{@assignment}, #{@branch}, #{@condition}>"
|
51
51
|
]
|
52
52
|
end
|
@@ -147,7 +147,7 @@ module RuboCop
|
|
147
147
|
|
148
148
|
# Returns true for lines that shall not be included in the count.
|
149
149
|
def irrelevant_line?(source_line)
|
150
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
150
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
151
151
|
end
|
152
152
|
|
153
153
|
def count_comments?
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
|
44
44
|
# Returns true for lines that shall not be included in the count.
|
45
45
|
def irrelevant_line(source_line)
|
46
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
46
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
47
47
|
end
|
48
48
|
|
49
49
|
def build_code_length_calculator(node)
|
@@ -9,9 +9,8 @@ module RuboCop
|
|
9
9
|
FROZEN_STRING_LITERAL = '# frozen_string_literal:'
|
10
10
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
11
11
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
12
|
-
FROZEN_STRING_LITERAL_TYPES_RUBY30 = %i[str].freeze
|
13
12
|
|
14
|
-
private_constant :FROZEN_STRING_LITERAL_TYPES_RUBY27
|
13
|
+
private_constant :FROZEN_STRING_LITERAL_TYPES_RUBY27
|
15
14
|
|
16
15
|
def frozen_string_literal_comment_exists?
|
17
16
|
leading_comment_lines.any? { |line| MagicComment.parse(line).valid_literal_value? }
|
@@ -20,13 +19,19 @@ module RuboCop
|
|
20
19
|
private
|
21
20
|
|
22
21
|
def frozen_string_literal?(node)
|
23
|
-
|
24
|
-
|
22
|
+
frozen_string = if target_ruby_version >= 3.0
|
23
|
+
node.str_type? || frozen_heredoc?(node)
|
25
24
|
else
|
26
|
-
FROZEN_STRING_LITERAL_TYPES_RUBY27
|
25
|
+
FROZEN_STRING_LITERAL_TYPES_RUBY27.include?(node.type)
|
27
26
|
end
|
28
27
|
|
29
|
-
|
28
|
+
frozen_string && frozen_string_literals_enabled?
|
29
|
+
end
|
30
|
+
|
31
|
+
def frozen_heredoc?(node)
|
32
|
+
return false unless node.dstr_type? && node.heredoc?
|
33
|
+
|
34
|
+
node.children.all?(&:str_type?)
|
30
35
|
end
|
31
36
|
|
32
37
|
def frozen_string_literals_enabled?
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
|
135
135
|
next if a.setter_method?
|
136
136
|
next unless kind == :with_or_without_parentheses ||
|
137
|
-
kind == :with_parentheses && parentheses?(a)
|
137
|
+
(kind == :with_parentheses && parentheses?(a))
|
138
138
|
|
139
139
|
a.arguments.any? { |arg| within_node?(node, arg) }
|
140
140
|
end
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
156
156
|
|
157
157
|
def disqualified_rhs?(candidate, ancestor)
|
158
158
|
UNALIGNED_RHS_TYPES.include?(ancestor.type) ||
|
159
|
-
ancestor.block_type? && part_of_block_body?(candidate, ancestor)
|
159
|
+
(ancestor.block_type? && part_of_block_body?(candidate, ancestor))
|
160
160
|
end
|
161
161
|
|
162
162
|
def valid_rhs?(candidate, ancestor)
|
@@ -93,7 +93,15 @@ module RuboCop
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def aligned_assignment?(range, line)
|
96
|
-
range.source[-1] == '=' && line[range.last_column - 1] == '='
|
96
|
+
(range.source[-1] == '=' && line[range.last_column - 1] == '=') ||
|
97
|
+
aligned_with_append_operator?(range, line)
|
98
|
+
end
|
99
|
+
|
100
|
+
def aligned_with_append_operator?(range, line)
|
101
|
+
last_column = range.last_column
|
102
|
+
|
103
|
+
(range.source == '<<' && line[last_column - 1] == '=') ||
|
104
|
+
(range.source[-1] == '=' && line[(last_column - 2)..(last_column - 1)] == '<<')
|
97
105
|
end
|
98
106
|
|
99
107
|
def aligned_identical?(range, line)
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def allowed_assignment?(value)
|
57
|
-
value && %i[block const casgn].include?(value.type) ||
|
57
|
+
(value && %i[block const casgn].include?(value.type)) ||
|
58
58
|
allowed_method_call_on_rhs?(value) ||
|
59
59
|
class_or_struct_return_method?(value) ||
|
60
60
|
allowed_conditional_expression_on_rhs?(value)
|
@@ -70,6 +70,8 @@ module RuboCop
|
|
70
70
|
include RangeHelp
|
71
71
|
|
72
72
|
EMPTY_ARRAY = [].freeze
|
73
|
+
MSG = "Consider replacing '%<term>s'%<suffix>s."
|
74
|
+
MSG_FOR_FILE_PATH = "Consider replacing '%<term>s' in file path%<suffix>s."
|
73
75
|
|
74
76
|
WordLocation = Struct.new(:word, :position)
|
75
77
|
|
@@ -197,12 +199,11 @@ module RuboCop
|
|
197
199
|
end
|
198
200
|
|
199
201
|
def create_single_word_message_for_file(word)
|
200
|
-
create_message(word
|
202
|
+
create_message(word, MSG_FOR_FILE_PATH)
|
201
203
|
end
|
202
204
|
|
203
205
|
def create_multiple_word_message_for_file(words)
|
204
|
-
|
205
|
-
"Consider replacing problematic terms #{quoted_words.join(', ')} in file path."
|
206
|
+
format(MSG_FOR_FILE_PATH, term: words.join("', '"), suffix: ' with other terms')
|
206
207
|
end
|
207
208
|
|
208
209
|
def scan_for_words(input)
|
@@ -223,9 +224,12 @@ module RuboCop
|
|
223
224
|
safe_str.gsub(@allowed_regex) { |match| '*' * match.size }
|
224
225
|
end
|
225
226
|
|
226
|
-
def create_message(word)
|
227
|
+
def create_message(word, message = MSG)
|
227
228
|
flagged_term = find_flagged_term(word)
|
228
|
-
|
229
|
+
suggestions = flagged_term['SuggestionString']
|
230
|
+
suggestions = ' with another term' if suggestions.blank?
|
231
|
+
|
232
|
+
format(message, term: word, suffix: suggestions)
|
229
233
|
end
|
230
234
|
|
231
235
|
def find_flagged_term(word)
|
@@ -235,10 +239,6 @@ module RuboCop
|
|
235
239
|
flagged_term
|
236
240
|
end
|
237
241
|
|
238
|
-
def create_message_for_file(word)
|
239
|
-
create_message(word).sub(/\.$/, ' in file path.')
|
240
|
-
end
|
241
|
-
|
242
242
|
def preprocess_suggestions(suggestions)
|
243
243
|
return '' if suggestions.nil? ||
|
244
244
|
(suggestions.is_a?(String) && suggestions.strip.empty?) || suggestions.empty?
|
@@ -59,8 +59,8 @@ module RuboCop
|
|
59
59
|
|
60
60
|
def check(send_node)
|
61
61
|
return if previous_line_comment?(send_node)
|
62
|
-
return unless grouped_style? && sibling_accessors(send_node).size > 1 ||
|
63
|
-
separated_style? && send_node.arguments.size > 1
|
62
|
+
return unless (grouped_style? && sibling_accessors(send_node).size > 1) ||
|
63
|
+
(separated_style? && send_node.arguments.size > 1)
|
64
64
|
|
65
65
|
message = message(send_node)
|
66
66
|
add_offense(send_node, message: message) do |corrector|
|
@@ -7,6 +7,10 @@ module RuboCop
|
|
7
7
|
# `||` instead. It can be configured to check only in conditions or in
|
8
8
|
# all contexts.
|
9
9
|
#
|
10
|
+
# It is marked as unsafe auto-correction because it may change the
|
11
|
+
# operator precedence between logical operators (`&&` and `||`) and
|
12
|
+
# semantic operators (`and` and `or`).
|
13
|
+
#
|
10
14
|
# @example EnforcedStyle: always
|
11
15
|
# # bad
|
12
16
|
# foo.save and return
|
@@ -5,9 +5,11 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for uses of the case equality operator(===).
|
7
7
|
#
|
8
|
+
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
9
|
+
# the case equality operator is a constant.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# # bad
|
10
|
-
# Array === something
|
11
13
|
# (1..100) === 7
|
12
14
|
# /something/ === some_string
|
13
15
|
#
|
@@ -16,18 +18,13 @@ module RuboCop
|
|
16
18
|
# (1..100).include?(7)
|
17
19
|
# /something/.match?(some_string)
|
18
20
|
#
|
19
|
-
# @example AllowOnConstant
|
20
|
-
# # Style/CaseEquality:
|
21
|
-
# # AllowOnConstant: true
|
22
|
-
#
|
21
|
+
# @example AllowOnConstant: false (default)
|
23
22
|
# # bad
|
24
|
-
#
|
25
|
-
# /something/ === some_string
|
23
|
+
# Array === something
|
26
24
|
#
|
25
|
+
# @example AllowOnConstant: true
|
27
26
|
# # good
|
28
27
|
# Array === something
|
29
|
-
# (1..100).include?(7)
|
30
|
-
# /something/.match?(some_string)
|
31
28
|
#
|
32
29
|
class CaseEquality < Base
|
33
30
|
extend AutoCorrector
|
@@ -68,7 +68,8 @@ module RuboCop
|
|
68
68
|
return false unless node.arguments.any?
|
69
69
|
|
70
70
|
node.last_argument.block_pass_type? ||
|
71
|
-
node.last_argument.sym_type? &&
|
71
|
+
(node.last_argument.sym_type? &&
|
72
|
+
methods_accepting_symbol.include?(node.method_name.to_s))
|
72
73
|
end
|
73
74
|
|
74
75
|
def message(node)
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
return unless arg_node&.dstr_type? && interpolated?(arg_node)
|
88
88
|
return if inline_comment_docs?(arg_node) ||
|
89
|
-
arg_node.heredoc? && comment_block_docs?(arg_node)
|
89
|
+
(arg_node.heredoc? && comment_block_docs?(arg_node))
|
90
90
|
|
91
91
|
add_offense(node.loc.selector)
|
92
92
|
end
|
@@ -71,8 +71,9 @@ module RuboCop
|
|
71
71
|
#
|
72
72
|
class Documentation < Base
|
73
73
|
include DocumentationComment
|
74
|
+
include RangeHelp
|
74
75
|
|
75
|
-
MSG = 'Missing top-level
|
76
|
+
MSG = 'Missing top-level documentation comment for `%<type>s %<identifier>s`.'
|
76
77
|
|
77
78
|
# @!method constant_definition?(node)
|
78
79
|
def_node_matcher :constant_definition?, '{class module casgn}'
|
@@ -88,33 +89,35 @@ module RuboCop
|
|
88
89
|
def on_class(node)
|
89
90
|
return unless node.body
|
90
91
|
|
91
|
-
check(node, node.body
|
92
|
+
check(node, node.body)
|
92
93
|
end
|
93
94
|
|
94
95
|
def on_module(node)
|
95
|
-
check(node, node.body
|
96
|
+
check(node, node.body)
|
96
97
|
end
|
97
98
|
|
98
99
|
private
|
99
100
|
|
100
|
-
def check(node, body
|
101
|
+
def check(node, body)
|
101
102
|
return if namespace?(body)
|
102
103
|
return if documentation_comment?(node)
|
103
104
|
return if constant_allowed?(node)
|
104
105
|
return if nodoc_self_or_outer_module?(node)
|
105
106
|
return if macro_only?(body)
|
106
107
|
|
107
|
-
|
108
|
+
range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
|
109
|
+
message = format(MSG, type: node.type, identifier: identifier(node))
|
110
|
+
add_offense(range, message: message)
|
108
111
|
end
|
109
112
|
|
110
113
|
def nodoc_self_or_outer_module?(node)
|
111
114
|
nodoc_comment?(node) ||
|
112
|
-
compact_namespace?(node) && nodoc_comment?(outer_module(node).first)
|
115
|
+
(compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
|
113
116
|
end
|
114
117
|
|
115
118
|
def macro_only?(body)
|
116
|
-
body.respond_to?(:macro?) && body.macro? ||
|
117
|
-
body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
|
119
|
+
(body.respond_to?(:macro?) && body.macro?) ||
|
120
|
+
(body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) })
|
118
121
|
end
|
119
122
|
|
120
123
|
def namespace?(node)
|
@@ -165,6 +168,18 @@ module RuboCop
|
|
165
168
|
def allowed_constants
|
166
169
|
@allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
|
167
170
|
end
|
171
|
+
|
172
|
+
def identifier(node)
|
173
|
+
# Get the fully qualified identifier for a class/module
|
174
|
+
nodes = [node, *node.each_ancestor(:class, :module)]
|
175
|
+
nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
|
176
|
+
end
|
177
|
+
|
178
|
+
def qualify_const(node)
|
179
|
+
return if node.nil?
|
180
|
+
|
181
|
+
[qualify_const(node.namespace), node.short_name].compact
|
182
|
+
end
|
168
183
|
end
|
169
184
|
end
|
170
185
|
end
|