rubocop 1.52.1 → 1.53.1
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 +38 -1
- data/lib/rubocop/cli/command/lsp.rb +19 -0
- data/lib/rubocop/cli.rb +3 -0
- data/lib/rubocop/config_loader_resolver.rb +4 -3
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
- data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +3 -3
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +31 -5
- data/lib/rubocop/cop/lint/mixed_case_range.rb +109 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +5 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +120 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +8 -3
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +2 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +3 -3
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +3 -3
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +6 -2
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +38 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +97 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +3 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -0
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +81 -0
- data/lib/rubocop/cop/style/signal_exception.rb +1 -1
- data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/regexp_ranges.rb +100 -0
- data/lib/rubocop/cops_documentation_generator.rb +1 -1
- data/lib/rubocop/ext/regexp_parser.rb +4 -1
- data/lib/rubocop/lsp/logger.rb +22 -0
- data/lib/rubocop/lsp/routes.rb +223 -0
- data/lib/rubocop/lsp/runtime.rb +79 -0
- data/lib/rubocop/lsp/server.rb +62 -0
- data/lib/rubocop/lsp/severity.rb +27 -0
- data/lib/rubocop/options.rb +11 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +8 -0
- metadata +30 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7b38b9b2471ab2c5972c061427da41ddf9820f91b21e7fa5d89330b2647eaa5
|
4
|
+
data.tar.gz: 1a48aaee106f9e6c0459c8c5ef0a98dc39455bf06a68174d6b52ac2ea74abb0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 181bd1ac83ae045a457b3b5b73bf8e18e964f7413cabfa843d594a10cc7435403827e0b001ef4d5574c0065944e942adb908b0e4bfac8766486f2c58dd10e8e1
|
7
|
+
data.tar.gz: b14fad843c6eb6ba3aa2e521133fe63da2abfed97fb79b1e45893c055c273180d1f0d0ed25cf53c53885d41859637c4469a2527617bb1c84125331a4eaf24fa3
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.53', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -467,7 +467,9 @@ Layout/ClassStructure:
|
|
467
467
|
Description: 'Enforces a configured order of definitions within a class body.'
|
468
468
|
StyleGuide: '#consistent-classes'
|
469
469
|
Enabled: false
|
470
|
+
SafeAutoCorrect: false
|
470
471
|
VersionAdded: '0.52'
|
472
|
+
VersionChanged: '1.53'
|
471
473
|
Categories:
|
472
474
|
module_inclusion:
|
473
475
|
- include
|
@@ -1530,7 +1532,6 @@ Lint/AmbiguousBlockAssociation:
|
|
1530
1532
|
Description: >-
|
1531
1533
|
Checks for ambiguous block association with method when param passed without
|
1532
1534
|
parentheses.
|
1533
|
-
StyleGuide: '#syntax'
|
1534
1535
|
Enabled: true
|
1535
1536
|
VersionAdded: '0.48'
|
1536
1537
|
VersionChanged: '1.13'
|
@@ -1988,9 +1989,16 @@ Lint/MissingSuper:
|
|
1988
1989
|
Checks for the presence of constructors and lifecycle callbacks
|
1989
1990
|
without calls to `super`.
|
1990
1991
|
Enabled: true
|
1992
|
+
AllowedParentClasses: []
|
1991
1993
|
VersionAdded: '0.89'
|
1992
1994
|
VersionChanged: '1.4'
|
1993
1995
|
|
1996
|
+
Lint/MixedCaseRange:
|
1997
|
+
Description: 'Checks for mixed-case character ranges since they include likely unintended characters.'
|
1998
|
+
Enabled: pending
|
1999
|
+
SafeAutoCorrect: false
|
2000
|
+
VersionAdded: '1.53'
|
2001
|
+
|
1994
2002
|
Lint/MixedRegexpCaptureTypes:
|
1995
2003
|
Description: 'Do not mix named captures and numbered captures in a Regexp literal.'
|
1996
2004
|
Enabled: true
|
@@ -2140,6 +2148,11 @@ Lint/RedundantDirGlobSort:
|
|
2140
2148
|
VersionChanged: '1.26'
|
2141
2149
|
SafeAutoCorrect: false
|
2142
2150
|
|
2151
|
+
Lint/RedundantRegexpQuantifiers:
|
2152
|
+
Description: 'Checks for redundant quantifiers in Regexps.'
|
2153
|
+
Enabled: pending
|
2154
|
+
VersionAdded: '1.53'
|
2155
|
+
|
2143
2156
|
Lint/RedundantRequireStatement:
|
2144
2157
|
Description: 'Checks for unnecessary `require` statement.'
|
2145
2158
|
Enabled: true
|
@@ -4843,6 +4856,11 @@ Style/RedundantConstantBase:
|
|
4843
4856
|
Enabled: pending
|
4844
4857
|
VersionAdded: '1.40'
|
4845
4858
|
|
4859
|
+
Style/RedundantCurrentDirectoryInPath:
|
4860
|
+
Description: 'Checks for uses a redundant current directory in path.'
|
4861
|
+
Enabled: pending
|
4862
|
+
VersionAdded: '1.53'
|
4863
|
+
|
4846
4864
|
Style/RedundantDoubleSplatHashBraces:
|
4847
4865
|
Description: 'Checks for redundant uses of double splat hash braces.'
|
4848
4866
|
Enabled: pending
|
@@ -4931,6 +4949,11 @@ Style/RedundantPercentQ:
|
|
4931
4949
|
Enabled: true
|
4932
4950
|
VersionAdded: '0.76'
|
4933
4951
|
|
4952
|
+
Style/RedundantRegexpArgument:
|
4953
|
+
Description: 'Identifies places where argument can be replaced from a deterministic regexp to a string.'
|
4954
|
+
Enabled: pending
|
4955
|
+
VersionAdded: '1.53'
|
4956
|
+
|
4934
4957
|
Style/RedundantRegexpCharacterClass:
|
4935
4958
|
Description: 'Checks for unnecessary single-element Regexp character classes.'
|
4936
4959
|
Enabled: true
|
@@ -5043,6 +5066,15 @@ Style/ReturnNil:
|
|
5043
5066
|
- return_nil
|
5044
5067
|
VersionAdded: '0.50'
|
5045
5068
|
|
5069
|
+
Style/ReturnNilInPredicateMethodDefinition:
|
5070
|
+
Description: 'Checks if uses of `return` or `return nil` in predicate method definition.'
|
5071
|
+
StyleGuide: '#bool-methods-qmark'
|
5072
|
+
Enabled: pending
|
5073
|
+
SafeAutoCorrect: false
|
5074
|
+
AllowedMethods: []
|
5075
|
+
AllowedPatterns: []
|
5076
|
+
VersionAdded: '1.53'
|
5077
|
+
|
5046
5078
|
Style/SafeNavigation:
|
5047
5079
|
Description: >-
|
5048
5080
|
Transforms usages of a method call safeguarded by
|
@@ -5527,6 +5559,11 @@ Style/WordArray:
|
|
5527
5559
|
# The regular expression `WordRegex` decides what is considered a word.
|
5528
5560
|
WordRegex: !ruby/regexp '/\A(?:\p{Word}|\p{Word}-\p{Word}|\n|\t)+\z/'
|
5529
5561
|
|
5562
|
+
Style/YAMLFileRead:
|
5563
|
+
Description: 'Checks for the use of `YAML.load`, `YAML.safe_load`, and `YAML.parse` with `File.read` argument.'
|
5564
|
+
Enabled: pending
|
5565
|
+
VersionAdded: '1.53'
|
5566
|
+
|
5530
5567
|
Style/YodaCondition:
|
5531
5568
|
Description: 'Forbid or enforce yoda conditions.'
|
5532
5569
|
Reference: 'https://en.wikipedia.org/wiki/Yoda_conditions'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../lsp/server'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
class CLI
|
7
|
+
module Command
|
8
|
+
# Start Language Server Protocol of RuboCop.
|
9
|
+
# @api private
|
10
|
+
class Lsp < Base
|
11
|
+
self.command_name = :lsp
|
12
|
+
|
13
|
+
def run
|
14
|
+
RuboCop::Lsp::Server.new(@config_store).start
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rubocop/cli.rb
CHANGED
@@ -174,14 +174,17 @@ module RuboCop
|
|
174
174
|
ConfigLoader.ignore_unrecognized_cops = @options[:ignore_unrecognized_cops]
|
175
175
|
end
|
176
176
|
|
177
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
177
178
|
def handle_exiting_options
|
178
179
|
return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
|
179
180
|
|
180
181
|
run_command(:version) if @options[:version] || @options[:verbose_version]
|
181
182
|
run_command(:show_cops) if @options[:show_cops]
|
182
183
|
run_command(:show_docs_url) if @options[:show_docs_url]
|
184
|
+
run_command(:lsp) if @options[:lsp]
|
183
185
|
raise Finished
|
184
186
|
end
|
187
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
185
188
|
|
186
189
|
def apply_default_formatter
|
187
190
|
# This must be done after the options have already been processed,
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
inherit_mode: determine_inherit_mode(hash, k))
|
34
34
|
end
|
35
35
|
hash[k] = v
|
36
|
-
fix_include_paths(base_config.loaded_path, hash, k, v) if v.key?('Include')
|
36
|
+
fix_include_paths(base_config.loaded_path, hash, path, k, v) if v.key?('Include')
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -42,12 +42,13 @@ module RuboCop
|
|
42
42
|
# base configuration are relative to the directory where the base configuration file is. For the
|
43
43
|
# derived configuration, we need to make those paths relative to where the derived configuration
|
44
44
|
# file is.
|
45
|
-
def fix_include_paths(base_config_path, hash, key, value)
|
45
|
+
def fix_include_paths(base_config_path, hash, path, key, value)
|
46
46
|
return unless File.basename(base_config_path).start_with?('.rubocop')
|
47
47
|
|
48
48
|
base_dir = File.dirname(base_config_path)
|
49
|
+
derived_dir = File.dirname(path)
|
49
50
|
hash[key]['Include'] = value['Include'].map do |include_path|
|
50
|
-
PathUtil.relative_path(File.join(base_dir, include_path),
|
51
|
+
PathUtil.relative_path(File.join(base_dir, include_path), derived_dir)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
150
150
|
# Version specifications that restrict all updates going forward. This excludes versions
|
151
151
|
# like ">= 1.0" or "!= 2.0.3".
|
152
152
|
def restrictive_version_specified_gem?(node)
|
153
|
-
return unless version_specified_gem?(node)
|
153
|
+
return false unless version_specified_gem?(node)
|
154
154
|
|
155
155
|
node.arguments[1..]
|
156
156
|
.any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) }
|
@@ -105,13 +105,13 @@ module RuboCop
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def required_offense?(node)
|
108
|
-
return unless required_style?
|
108
|
+
return false unless required_style?
|
109
109
|
|
110
110
|
!includes_version_specification?(node) && !includes_commit_reference?(node)
|
111
111
|
end
|
112
112
|
|
113
113
|
def forbidden_offense?(node)
|
114
|
-
return unless forbidden_style?
|
114
|
+
return false unless forbidden_style?
|
115
115
|
|
116
116
|
includes_version_specification?(node) || includes_commit_reference?(node)
|
117
117
|
end
|
@@ -126,13 +126,13 @@ module RuboCop
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def required_offense?(node)
|
129
|
-
return unless required_style?
|
129
|
+
return false unless required_style?
|
130
130
|
|
131
131
|
!includes_version_specification?(node) && !includes_commit_reference?(node)
|
132
132
|
end
|
133
133
|
|
134
134
|
def forbidden_offense?(node)
|
135
|
-
return unless forbidden_style?
|
135
|
+
return false unless forbidden_style?
|
136
136
|
|
137
137
|
includes_version_specification?(node) || includes_commit_reference?(node)
|
138
138
|
end
|
@@ -117,11 +117,11 @@ module RuboCop
|
|
117
117
|
def add_newline?(node)
|
118
118
|
# Determine if a blank line should be inserted before the new directive
|
119
119
|
# in order to spread out pattern matchers
|
120
|
-
return if node.sibling_index&.zero?
|
121
|
-
return unless node.parent
|
120
|
+
return false if node.sibling_index&.zero?
|
121
|
+
return false unless node.parent
|
122
122
|
|
123
123
|
prev_sibling = node.parent.child_nodes[node.sibling_index - 1]
|
124
|
-
return unless prev_sibling && pattern_matcher?(prev_sibling)
|
124
|
+
return false unless prev_sibling && pattern_matcher?(prev_sibling)
|
125
125
|
|
126
126
|
node.loc.line == last_line(prev_sibling) + 1
|
127
127
|
end
|
@@ -68,6 +68,13 @@ module RuboCop
|
|
68
68
|
# - extend
|
69
69
|
# ----
|
70
70
|
#
|
71
|
+
# @safety
|
72
|
+
# Autocorrection is unsafe because class methods and module inclusion
|
73
|
+
# can behave differently, based on which methods or constants have
|
74
|
+
# already been defined.
|
75
|
+
#
|
76
|
+
# Constants will only be moved when they are assigned with literals.
|
77
|
+
#
|
71
78
|
# @example
|
72
79
|
# # bad
|
73
80
|
# # Expect extend be before constant
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
|
77
77
|
def autocorrect_lambda_for_tabs(corrector, range)
|
78
78
|
spaces = ' ' * configured_indentation_width
|
79
|
-
corrector.replace(range, range.source.gsub(
|
79
|
+
corrector.replace(range, range.source.gsub("\t", spaces))
|
80
80
|
end
|
81
81
|
|
82
82
|
def autocorrect_lambda_for_spaces(corrector, range)
|
@@ -366,10 +366,10 @@ module RuboCop
|
|
366
366
|
end
|
367
367
|
|
368
368
|
def starts_with_access_modifier?(body_node)
|
369
|
-
return unless body_node.begin_type?
|
369
|
+
return false unless body_node.begin_type?
|
370
370
|
|
371
371
|
starting_node = body_node.children.first
|
372
|
-
return unless starting_node
|
372
|
+
return false unless starting_node
|
373
373
|
|
374
374
|
starting_node.send_type? && starting_node.bare_access_modifier?
|
375
375
|
end
|
@@ -99,7 +99,7 @@ module RuboCop
|
|
99
99
|
def suitable_as_single_line?(node)
|
100
100
|
!comment_within?(node) &&
|
101
101
|
node.each_descendant(:if, :case, :kwbegin, :def).none? &&
|
102
|
-
node.each_descendant(:dstr, :str).none?
|
102
|
+
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
103
103
|
node.each_descendant(:begin).none? { |b| !b.single_line? }
|
104
104
|
end
|
105
105
|
|
@@ -90,7 +90,7 @@ module RuboCop
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def debugger_method?(send_node)
|
93
|
-
return if send_node.parent&.send_type? && send_node.parent.receiver == send_node
|
93
|
+
return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
|
94
94
|
|
95
95
|
debugger_methods.include?(chained_method_name(send_node))
|
96
96
|
end
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for duplicated keys in hash literals.
|
7
|
+
# This cop considers both primitive types and constants for the hash keys.
|
7
8
|
#
|
8
9
|
# This cop mirrors a warning in Ruby 2.2.
|
9
10
|
#
|
@@ -24,7 +25,7 @@ module RuboCop
|
|
24
25
|
MSG = 'Duplicated key in hash literal.'
|
25
26
|
|
26
27
|
def on_hash(node)
|
27
|
-
keys = node.keys.select
|
28
|
+
keys = node.keys.select { |key| key.recursive_basic_literal? || key.const_type? }
|
28
29
|
|
29
30
|
return unless duplicates?(keys)
|
30
31
|
|
@@ -24,6 +24,8 @@ module RuboCop
|
|
24
24
|
|
25
25
|
MSG_REPEATED_ELEMENT = 'Duplicate element inside regexp character class'
|
26
26
|
|
27
|
+
OCTAL_DIGITS_AFTER_ESCAPE = 2
|
28
|
+
|
27
29
|
def on_regexp(node)
|
28
30
|
each_repeated_character_class_element_loc(node) do |loc|
|
29
31
|
add_offense(loc, message: MSG_REPEATED_ELEMENT) do |corrector|
|
@@ -32,35 +34,57 @@ module RuboCop
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
36
37
|
def each_repeated_character_class_element_loc(node)
|
37
38
|
node.parsed_tree&.each_expression do |expr|
|
38
39
|
next if skip_expression?(expr)
|
39
40
|
|
40
41
|
seen = Set.new
|
41
|
-
|
42
|
-
|
42
|
+
group_expressions(node, expr.expressions) do |group|
|
43
|
+
group_source = group.map(&:to_s).join
|
43
44
|
|
44
|
-
|
45
|
-
current_child = enum.next
|
46
|
-
next if within_interpolation?(node, current_child)
|
45
|
+
yield source_range(group) if seen.include?(group_source)
|
47
46
|
|
48
|
-
|
49
|
-
|
47
|
+
seen << group_source
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
next if start_with_escaped_zero_number?(current_child_source, next_child.to_s)
|
52
|
+
private
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
def group_expressions(node, expressions)
|
55
|
+
# Create a mutable list to simplify state tracking while we iterate.
|
56
|
+
expressions = expressions.to_a
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
until expressions.empty?
|
59
|
+
# With we may need to compose a group of multiple expressions.
|
60
|
+
group = [expressions.shift]
|
61
|
+
next if within_interpolation?(node, group.first)
|
62
|
+
|
63
|
+
# With regexp_parser < 2.7 escaped octal sequences may be up to 3
|
64
|
+
# separate expressions ("\\0", "0", "1").
|
65
|
+
pop_octal_digits(group, expressions) if escaped_octal?(group.first.to_s)
|
66
|
+
|
67
|
+
yield(group)
|
59
68
|
end
|
60
69
|
end
|
61
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
62
70
|
|
63
|
-
|
71
|
+
def pop_octal_digits(current_child, expressions)
|
72
|
+
OCTAL_DIGITS_AFTER_ESCAPE.times do
|
73
|
+
next_child = expressions.first
|
74
|
+
break unless octal?(next_child.to_s)
|
75
|
+
|
76
|
+
current_child << expressions.shift
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def source_range(children)
|
81
|
+
return children.first.expression if children.size == 1
|
82
|
+
|
83
|
+
range_between(
|
84
|
+
children.first.expression.begin_pos,
|
85
|
+
children.last.expression.begin_pos + children.last.to_s.length
|
86
|
+
)
|
87
|
+
end
|
64
88
|
|
65
89
|
def skip_expression?(expr)
|
66
90
|
expr.type != :set || expr.token == :intersection
|
@@ -75,9 +99,12 @@ module RuboCop
|
|
75
99
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
76
100
|
end
|
77
101
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
102
|
+
def escaped_octal?(string)
|
103
|
+
string.length == 2 && string[0] == '\\' && octal?(string[1])
|
104
|
+
end
|
105
|
+
|
106
|
+
def octal?(char)
|
107
|
+
('0'..'7').cover?(char)
|
81
108
|
end
|
82
109
|
|
83
110
|
def interpolation_locs(node)
|
@@ -14,6 +14,13 @@ module RuboCop
|
|
14
14
|
# Autocorrection is not supported because the position of `super` cannot be
|
15
15
|
# determined automatically.
|
16
16
|
#
|
17
|
+
# `Object` and `BasicObject` are allowed by this cop because of their
|
18
|
+
# stateless nature. However, sometimes you might want to allow other parent
|
19
|
+
# classes from this cop, for example in the case of an abstract class that is
|
20
|
+
# not meant to be called with `super`. In those cases, you can use the
|
21
|
+
# `AllowedParentClasses` option to specify which classes should be allowed
|
22
|
+
# *in addition to* `Object` and `BasicObject`.
|
23
|
+
#
|
17
24
|
# @example
|
18
25
|
# # bad
|
19
26
|
# class Employee < Person
|
@@ -60,6 +67,21 @@ module RuboCop
|
|
60
67
|
# end
|
61
68
|
# end
|
62
69
|
#
|
70
|
+
# # good
|
71
|
+
# class ClassWithNoParent
|
72
|
+
# def initialize
|
73
|
+
# do_something
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# @example AllowedParentClasses: [MyAbstractClass]
|
78
|
+
# # good
|
79
|
+
# class MyConcreteClass < MyAbstractClass
|
80
|
+
# def initialize
|
81
|
+
# do_something
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
63
85
|
class MissingSuper < Base
|
64
86
|
CONSTRUCTOR_MSG = 'Call `super` to initialize state of the parent class.'
|
65
87
|
CALLBACK_MSG = 'Call `super` to invoke callback defined in the parent class.'
|
@@ -103,7 +125,7 @@ module RuboCop
|
|
103
125
|
end
|
104
126
|
|
105
127
|
def callback_method_def?(node)
|
106
|
-
return unless CALLBACKS.include?(node.method_name)
|
128
|
+
return false unless CALLBACKS.include?(node.method_name)
|
107
129
|
|
108
130
|
node.each_ancestor(:class, :sclass, :module).first
|
109
131
|
end
|
@@ -116,16 +138,20 @@ module RuboCop
|
|
116
138
|
if (block_node = node.each_ancestor(:block, :numblock).first)
|
117
139
|
return false unless (super_class = class_new_block(block_node))
|
118
140
|
|
119
|
-
!
|
141
|
+
!allowed_class?(super_class)
|
120
142
|
elsif (class_node = node.each_ancestor(:class).first)
|
121
|
-
class_node.parent_class && !
|
143
|
+
class_node.parent_class && !allowed_class?(class_node.parent_class)
|
122
144
|
else
|
123
145
|
false
|
124
146
|
end
|
125
147
|
end
|
126
148
|
|
127
|
-
def
|
128
|
-
|
149
|
+
def allowed_class?(node)
|
150
|
+
allowed_classes.include?(node.const_name)
|
151
|
+
end
|
152
|
+
|
153
|
+
def allowed_classes
|
154
|
+
@allowed_classes ||= STATELESS_CLASSES + cop_config.fetch('AllowedParentClasses', [])
|
129
155
|
end
|
130
156
|
end
|
131
157
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for mixed-case character ranges since they include likely unintended characters.
|
7
|
+
#
|
8
|
+
# Offenses are registered for regexp character classes like `/[A-z]/`
|
9
|
+
# as well as range objects like `('A'..'z')`.
|
10
|
+
#
|
11
|
+
# NOTE: Range objects cannot be autocorrected.
|
12
|
+
#
|
13
|
+
# @safety
|
14
|
+
# The cop autocorrects regexp character classes
|
15
|
+
# by replacing one character range with two: `A-z` becomes `A-Za-z`.
|
16
|
+
# In most cases this is probably what was originally intended
|
17
|
+
# but it changes the regexp to no longer match symbols it used to include.
|
18
|
+
# For this reason, this cop's autocorrect is unsafe (it will
|
19
|
+
# change the behavior of the code).
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
#
|
23
|
+
# # bad
|
24
|
+
# r = /[A-z]/
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# r = /[A-Za-z]/
|
28
|
+
class MixedCaseRange < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
include RangeHelp
|
31
|
+
|
32
|
+
MSG = 'Ranges from upper to lower case ASCII letters may include unintended ' \
|
33
|
+
'characters. Instead of `A-z` (which also includes several symbols) ' \
|
34
|
+
'specify each range individually: `A-Za-z` and individually specify any symbols.'
|
35
|
+
RANGES = [('a'..'z').freeze, ('A'..'Z').freeze].freeze
|
36
|
+
|
37
|
+
def on_irange(node)
|
38
|
+
return unless node.children.compact.all?(&:str_type?)
|
39
|
+
|
40
|
+
range_start, range_end = node.children
|
41
|
+
|
42
|
+
return if range_start.nil? || range_end.nil?
|
43
|
+
|
44
|
+
add_offense(node) if unsafe_range?(range_start.value, range_end.value)
|
45
|
+
end
|
46
|
+
alias on_erange on_irange
|
47
|
+
|
48
|
+
def on_regexp(node)
|
49
|
+
each_unsafe_regexp_range(node) do |loc|
|
50
|
+
add_offense(loc) do |corrector|
|
51
|
+
corrector.replace(loc, rewrite_regexp_range(loc.source))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def each_unsafe_regexp_range(node)
|
57
|
+
node.parsed_tree&.each_expression do |expr|
|
58
|
+
next if skip_expression?(expr)
|
59
|
+
|
60
|
+
range_pairs(expr).reject do |range_start, range_end|
|
61
|
+
next if skip_range?(range_start, range_end)
|
62
|
+
|
63
|
+
next unless unsafe_range?(range_start.text, range_end.text)
|
64
|
+
|
65
|
+
yield(build_source_range(range_start, range_end))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def build_source_range(range_start, range_end)
|
73
|
+
range_between(range_start.expression.begin_pos, range_end.expression.end_pos)
|
74
|
+
end
|
75
|
+
|
76
|
+
def range_for(char)
|
77
|
+
RANGES.detect do |range|
|
78
|
+
range.include?(char)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def range_pairs(expr)
|
83
|
+
RuboCop::Cop::Utils::RegexpRanges.new(expr).pairs
|
84
|
+
end
|
85
|
+
|
86
|
+
def unsafe_range?(range_start, range_end)
|
87
|
+
range_for(range_start) != range_for(range_end)
|
88
|
+
end
|
89
|
+
|
90
|
+
def skip_expression?(expr)
|
91
|
+
!(expr.type == :set && expr.token == :character)
|
92
|
+
end
|
93
|
+
|
94
|
+
def skip_range?(range_start, range_end)
|
95
|
+
[range_start, range_end].any? do |bound|
|
96
|
+
bound.type == :escape
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def rewrite_regexp_range(source)
|
101
|
+
open, close = source.split('-')
|
102
|
+
first = [open, range_for(open).end]
|
103
|
+
second = [range_for(close).begin, close]
|
104
|
+
"#{first.uniq.join('-')}#{second.uniq.join('-')}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -74,6 +74,7 @@ module RuboCop
|
|
74
74
|
extend AutoCorrector
|
75
75
|
include AllowedMethods
|
76
76
|
include AllowedPattern
|
77
|
+
include IgnoredNode
|
77
78
|
|
78
79
|
CONVERSION_METHOD_CLASS_MAPPING = {
|
79
80
|
to_i: "#{Integer.name}(%<number_object>s, 10)",
|
@@ -116,7 +117,11 @@ module RuboCop
|
|
116
117
|
corrected_method: correct_method(node, receiver)
|
117
118
|
)
|
118
119
|
add_offense(node, message: message) do |corrector|
|
120
|
+
next if part_of_ignored_node?(node)
|
121
|
+
|
119
122
|
corrector.replace(node, correct_method(node, node.receiver))
|
123
|
+
|
124
|
+
ignore_node(node)
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|