rubocop-sorbet 0.7.0 → 0.7.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/.github/workflows/ci.yml +1 -1
- data/.rubocop.yml +12 -1
- data/.yardopts +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +23 -17
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/bin/rspec +4 -2
- data/bin/rubocop +4 -2
- data/config/default.yml +23 -2
- data/lib/rubocop/cop/sorbet/binding_constant_without_type_alias.rb +105 -0
- data/lib/rubocop/cop/sorbet/callback_conditionals_binding.rb +39 -11
- data/lib/rubocop/cop/sorbet/constants_from_strings.rb +5 -3
- data/lib/rubocop/cop/sorbet/forbid_include_const_literal.rb +27 -23
- data/lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb +26 -27
- data/lib/rubocop/cop/sorbet/forbid_t_unsafe.rb +7 -3
- data/lib/rubocop/cop/sorbet/forbid_t_untyped.rb +7 -3
- data/lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb +13 -11
- data/lib/rubocop/cop/sorbet/implicit_conversion_method.rb +56 -0
- data/lib/rubocop/cop/sorbet/mixin/target_sorbet_version.rb +49 -0
- data/lib/rubocop/cop/sorbet/mutable_constant_sorbet_aware_behaviour.rb +8 -5
- data/lib/rubocop/cop/sorbet/obsolete_strict_memoization.rb +92 -0
- data/lib/rubocop/cop/sorbet/one_ancestor_per_line.rb +8 -3
- data/lib/rubocop/cop/sorbet/rbi/forbid_extend_t_sig_helpers_in_shims.rb +12 -18
- data/lib/rubocop/cop/sorbet/rbi/forbid_rbi_outside_of_allowed_paths.rb +8 -7
- data/lib/rubocop/cop/sorbet/rbi/single_line_rbi_class_module_definitions.rb +12 -18
- data/lib/rubocop/cop/sorbet/redundant_extend_t_sig.rb +5 -6
- data/lib/rubocop/cop/sorbet/sigils/enforce_sigil_order.rb +3 -2
- data/lib/rubocop/cop/sorbet/sigils/enforce_single_sigil.rb +6 -5
- data/lib/rubocop/cop/sorbet/sigils/false_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/has_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/ignore_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/strict_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/strong_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/true_sigil.rb +1 -1
- data/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb +50 -25
- data/lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb +19 -30
- data/lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb +3 -2
- data/lib/rubocop/cop/sorbet/signatures/empty_line_after_sig.rb +3 -3
- data/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb +8 -4
- data/lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb +5 -4
- data/lib/rubocop/cop/sorbet/signatures/signature_build_order.rb +8 -3
- data/lib/rubocop/cop/sorbet/signatures/signature_cop.rb +6 -1
- data/lib/rubocop/cop/sorbet/type_alias_name.rb +10 -17
- data/lib/rubocop/cop/sorbet_cops.rb +6 -1
- data/lib/rubocop/sorbet/inject.rb +9 -7
- data/lib/rubocop/sorbet/version.rb +2 -1
- data/lib/rubocop/sorbet.rb +1 -0
- data/manual/cops.md +2 -0
- data/manual/cops_sorbet.md +137 -31
- data/rubocop-sorbet.gemspec +1 -0
- data/tasks/cops_documentation.rake +16 -5
- metadata +8 -4
- data/lib/rubocop/cop/sorbet/binding_constants_without_type_alias.rb +0 -127
@@ -5,7 +5,7 @@ require "rubocop"
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module Sorbet
|
8
|
-
#
|
8
|
+
# Checks that every Ruby file contains a valid Sorbet sigil.
|
9
9
|
# Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
|
10
10
|
#
|
11
11
|
# Options:
|
@@ -13,9 +13,11 @@ module RuboCop
|
|
13
13
|
# * `RequireSigilOnAllFiles`: make offense if the Sorbet typed is not found in the file (default: false)
|
14
14
|
# * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
|
15
15
|
# * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
|
16
|
+
# * `ExactStrictness`: If set, make offense if the strictness level in the file is different than this one
|
16
17
|
#
|
17
|
-
# If
|
18
|
-
|
18
|
+
# If an `ExactStrictness` level is specified, it will be used in offense messages and autocorrect.
|
19
|
+
# Otherwise, if a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
20
|
+
class ValidSigil < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
|
19
21
|
@registry = Cop.registry # So we can properly subclass this cop
|
20
22
|
|
21
23
|
def investigate(processed_source)
|
@@ -36,7 +38,7 @@ module RuboCop
|
|
36
38
|
return unless extract_sigil(processed_source).nil?
|
37
39
|
|
38
40
|
token = processed_source.tokens.first
|
39
|
-
replace_with = suggested_strictness_level
|
41
|
+
replace_with = suggested_strictness_level
|
40
42
|
sigil = "# typed: #{replace_with}"
|
41
43
|
if token.text.start_with?("#!") # shebang line
|
42
44
|
corrector.insert_after(token.pos, "\n#{sigil}")
|
@@ -70,34 +72,37 @@ module RuboCop
|
|
70
72
|
|
71
73
|
token = processed_source.tokens.first
|
72
74
|
if require_sigil_on_all_files?
|
73
|
-
strictness = suggested_strictness_level
|
75
|
+
strictness = suggested_strictness_level
|
74
76
|
add_offense(
|
75
77
|
token,
|
76
78
|
location: token.pos,
|
77
79
|
message: "No Sorbet sigil found in file. " \
|
78
|
-
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this)."
|
80
|
+
"Try a `typed: #{strictness}` to start (you can also use `rubocop -a` to automatically add this).",
|
79
81
|
)
|
80
82
|
end
|
81
83
|
false
|
82
84
|
end
|
83
85
|
|
84
|
-
def suggested_strictness_level
|
86
|
+
def suggested_strictness_level
|
87
|
+
return exact_strictness if exact_strictness
|
85
88
|
# if no minimum strictness is set (eg. using Sorbet/HasSigil without config) then
|
86
89
|
# we always use the suggested strictness which defaults to `false`
|
87
90
|
return suggested_strictness unless minimum_strictness
|
88
91
|
|
89
92
|
# special case: if you're using Sorbet/IgnoreSigil without config, we should recommend `ignore`
|
90
|
-
return "ignore" if minimum_strictness == "ignore" && cop_config["SuggestedStrictness"].nil?
|
93
|
+
return "ignore" if minimum_strictness == "ignore" && cop_config["SuggestedStrictness"].nil? # rubocop:todo InternalAffairs/UndefinedConfig
|
91
94
|
|
92
95
|
# if a minimum strictness is set (eg. you're using Sorbet/FalseSigil)
|
93
96
|
# we want to compare the minimum strictness and suggested strictness. this is because
|
94
97
|
# the suggested strictness might be higher than the minimum (eg. if you want all new files
|
95
98
|
# at a higher strictness level, without having to migrate existing files at lower levels).
|
96
99
|
|
97
|
-
|
98
|
-
|
100
|
+
levels = [
|
101
|
+
STRICTNESS_LEVELS.index(suggested_strictness),
|
102
|
+
STRICTNESS_LEVELS.index(minimum_strictness),
|
103
|
+
]
|
99
104
|
|
100
|
-
|
105
|
+
STRICTNESS_LEVELS[levels.compact.max]
|
101
106
|
end
|
102
107
|
|
103
108
|
def check_strictness_not_empty(sigil, strictness)
|
@@ -106,7 +111,7 @@ module RuboCop
|
|
106
111
|
add_offense(
|
107
112
|
sigil,
|
108
113
|
location: sigil.pos,
|
109
|
-
message: "Sorbet sigil should not be empty."
|
114
|
+
message: "Sorbet sigil should not be empty.",
|
110
115
|
)
|
111
116
|
false
|
112
117
|
end
|
@@ -117,24 +122,38 @@ module RuboCop
|
|
117
122
|
add_offense(
|
118
123
|
sigil,
|
119
124
|
location: sigil.pos,
|
120
|
-
message: "Invalid Sorbet sigil `#{strictness}`."
|
125
|
+
message: "Invalid Sorbet sigil `#{strictness}`.",
|
121
126
|
)
|
122
127
|
false
|
123
128
|
end
|
124
129
|
|
125
130
|
def check_strictness_level(sigil, strictness)
|
126
|
-
return true
|
131
|
+
return true if !minimum_strictness && !exact_strictness
|
127
132
|
|
128
|
-
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
|
129
133
|
current_level = STRICTNESS_LEVELS.index(strictness)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
|
135
|
+
if exact_strictness
|
136
|
+
exact_level = STRICTNESS_LEVELS.index(exact_strictness)
|
137
|
+
if current_level != exact_level
|
138
|
+
add_offense(
|
139
|
+
sigil,
|
140
|
+
location: sigil.pos,
|
141
|
+
message: "Sorbet sigil should be `#{exact_strictness}` got `#{strictness}`.",
|
142
|
+
)
|
143
|
+
return false
|
144
|
+
end
|
145
|
+
else
|
146
|
+
minimum_level = STRICTNESS_LEVELS.index(minimum_strictness)
|
147
|
+
if current_level < minimum_level
|
148
|
+
add_offense(
|
149
|
+
sigil,
|
150
|
+
location: sigil.pos,
|
151
|
+
message: "Sorbet sigil should be at least `#{minimum_strictness}` got `#{strictness}`.",
|
152
|
+
)
|
153
|
+
return false
|
154
|
+
end
|
137
155
|
end
|
156
|
+
|
138
157
|
true
|
139
158
|
end
|
140
159
|
|
@@ -142,18 +161,24 @@ module RuboCop
|
|
142
161
|
|
143
162
|
# Default is `false`
|
144
163
|
def require_sigil_on_all_files?
|
145
|
-
!!cop_config["RequireSigilOnAllFiles"]
|
164
|
+
!!cop_config["RequireSigilOnAllFiles"] # rubocop:todo InternalAffairs/UndefinedConfig
|
146
165
|
end
|
147
166
|
|
148
167
|
# Default is `'false'`
|
149
168
|
def suggested_strictness
|
150
|
-
config = cop_config["SuggestedStrictness"].to_s
|
169
|
+
config = cop_config["SuggestedStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
|
151
170
|
STRICTNESS_LEVELS.include?(config) ? config : "false"
|
152
171
|
end
|
153
172
|
|
154
173
|
# Default is `nil`
|
155
174
|
def minimum_strictness
|
156
|
-
config = cop_config["MinimumStrictness"].to_s
|
175
|
+
config = cop_config["MinimumStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
|
176
|
+
config if STRICTNESS_LEVELS.include?(config)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Default is `nil`
|
180
|
+
def exact_strictness
|
181
|
+
config = cop_config["ExactStrictness"].to_s # rubocop:todo InternalAffairs/UndefinedConfig
|
157
182
|
config if STRICTNESS_LEVELS.include?(config)
|
158
183
|
end
|
159
184
|
end
|
@@ -5,10 +5,10 @@ require "rubocop"
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module Sorbet
|
8
|
-
#
|
8
|
+
# Disallows using `.override(allow_incompatible: true)`.
|
9
9
|
# Using `allow_incompatible` suggests a violation of the Liskov
|
10
10
|
# Substitution Principle, meaning that a subclass is not a valid
|
11
|
-
# subtype of
|
11
|
+
# subtype of its superclass. This Cop prevents these design smells
|
12
12
|
# from occurring.
|
13
13
|
#
|
14
14
|
# @example
|
@@ -18,40 +18,29 @@ module RuboCop
|
|
18
18
|
#
|
19
19
|
# # good
|
20
20
|
# sig.override
|
21
|
-
class AllowIncompatibleOverride < RuboCop::Cop::
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
nil?
|
26
|
-
:sig
|
27
|
-
...
|
28
|
-
)
|
29
|
-
PATTERN
|
21
|
+
class AllowIncompatibleOverride < RuboCop::Cop::Base
|
22
|
+
MSG = "Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. " \
|
23
|
+
"Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`"
|
24
|
+
RESTRICT_ON_SEND = [:override].freeze
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def_node_search(:allow_incompatible?, <<-PATTERN)
|
36
|
-
(pair (sym :allow_incompatible) (true))
|
37
|
-
PATTERN
|
38
|
-
|
39
|
-
def_node_matcher(:allow_incompatible_override?, <<-PATTERN)
|
40
|
-
(
|
41
|
-
send
|
42
|
-
[#not_nil? #sig?]
|
26
|
+
# @!method allow_incompatible_override?(node)
|
27
|
+
def_node_matcher(:allow_incompatible_override?, <<~PATTERN)
|
28
|
+
(send
|
29
|
+
#sig?
|
43
30
|
:override
|
44
|
-
|
31
|
+
(hash <$(pair (sym :allow_incompatible) true) ...>)
|
45
32
|
)
|
46
33
|
PATTERN
|
47
34
|
|
35
|
+
# @!method sig?(node)
|
36
|
+
def_node_search :sig?, <<~PATTERN
|
37
|
+
(send _ :sig ...)
|
38
|
+
PATTERN
|
39
|
+
|
48
40
|
def on_send(node)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
message: "Usage of `allow_incompatible` suggests a violation of the Liskov Substitution Principle. "\
|
53
|
-
"Instead, strive to write interfaces which respect subtyping principles and remove `allow_incompatible`",
|
54
|
-
)
|
41
|
+
allow_incompatible_override?(node) do |allow_incompatible_pair|
|
42
|
+
add_offense(allow_incompatible_pair)
|
43
|
+
end
|
55
44
|
end
|
56
45
|
end
|
57
46
|
end
|
@@ -6,7 +6,7 @@ require_relative "signature_cop"
|
|
6
6
|
module RuboCop
|
7
7
|
module Cop
|
8
8
|
module Sorbet
|
9
|
-
#
|
9
|
+
# Disallows the usage of `checked(true)`. This usage could cause
|
10
10
|
# confusion; it could lead some people to believe that a method would be checked
|
11
11
|
# even if runtime checks have not been enabled on the class or globally.
|
12
12
|
# Additionally, in the event where checks are enabled, `checked(true)` would
|
@@ -22,6 +22,7 @@ module RuboCop
|
|
22
22
|
class CheckedTrueInSignature < SignatureCop
|
23
23
|
include(RuboCop::Cop::RangeHelp)
|
24
24
|
|
25
|
+
# @!method offending_node(node)
|
25
26
|
def_node_search(:offending_node, <<~PATTERN)
|
26
27
|
(send _ :checked (true))
|
27
28
|
PATTERN
|
@@ -44,7 +45,7 @@ module RuboCop
|
|
44
45
|
error.location.line,
|
45
46
|
(error.location.selector.begin_pos)..(error.location.end.begin_pos),
|
46
47
|
),
|
47
|
-
message: MESSAGE
|
48
|
+
message: MESSAGE,
|
48
49
|
)
|
49
50
|
end
|
50
51
|
end
|
@@ -5,7 +5,7 @@ require_relative "signature_cop"
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module Sorbet
|
8
|
-
#
|
8
|
+
# Checks for blank lines after signatures.
|
9
9
|
#
|
10
10
|
# It also suggests an autocorrect
|
11
11
|
#
|
@@ -31,10 +31,10 @@ module RuboCop
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def autocorrect(node)
|
34
|
-
->
|
34
|
+
->(corrector) do
|
35
35
|
offending_range = node.source_range.with(
|
36
36
|
begin_pos: node.source_range.end_pos + 1,
|
37
|
-
end_pos: processed_source.buffer.line_range(next_method(node).line).begin_pos
|
37
|
+
end_pos: processed_source.buffer.line_range(next_method(node).line).begin_pos,
|
38
38
|
)
|
39
39
|
corrector.remove(offending_range)
|
40
40
|
clean_range = offending_range.source.split("\n").reject(&:empty?).join("\n")
|
@@ -7,7 +7,7 @@ require_relative "signature_cop"
|
|
7
7
|
module RuboCop
|
8
8
|
module Cop
|
9
9
|
module Sorbet
|
10
|
-
#
|
10
|
+
# Checks that every method definition and attribute accessor has a Sorbet signature.
|
11
11
|
#
|
12
12
|
# It also suggest an autocorrect with placeholders so the following code:
|
13
13
|
#
|
@@ -32,6 +32,7 @@ module RuboCop
|
|
32
32
|
@last_sig_for_scope = {}
|
33
33
|
end
|
34
34
|
|
35
|
+
# @!method accessor?(node)
|
35
36
|
def_node_matcher(:accessor?, <<-PATTERN)
|
36
37
|
(send nil? {:attr_reader :attr_writer :attr_accessor} ...)
|
37
38
|
PATTERN
|
@@ -67,13 +68,14 @@ module RuboCop
|
|
67
68
|
suggest.returns = "void" if method == :attr_writer
|
68
69
|
end
|
69
70
|
|
70
|
-
corrector.insert_before(node
|
71
|
+
corrector.insert_before(node, suggest.to_autocorrect)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
74
75
|
def scope(node)
|
75
|
-
return
|
76
|
+
return unless node.parent
|
76
77
|
return node.parent if [:begin, :block, :class, :module].include?(node.parent.type)
|
78
|
+
|
77
79
|
scope(node.parent)
|
78
80
|
end
|
79
81
|
|
@@ -84,7 +86,7 @@ module RuboCop
|
|
84
86
|
unless @last_sig_for_scope[scope]
|
85
87
|
add_offense(
|
86
88
|
node,
|
87
|
-
message: "Each method is required to have a signature."
|
89
|
+
message: "Each method is required to have a signature.",
|
88
90
|
)
|
89
91
|
end
|
90
92
|
@last_sig_for_scope[scope] = nil
|
@@ -123,6 +125,7 @@ module RuboCop
|
|
123
125
|
|
124
126
|
def generate_params
|
125
127
|
return if @params.empty?
|
128
|
+
|
126
129
|
out = StringIO.new
|
127
130
|
out << "params("
|
128
131
|
out << @params.map do |param|
|
@@ -135,6 +138,7 @@ module RuboCop
|
|
135
138
|
def generate_return
|
136
139
|
return "returns(#{@return_placeholder})" if @returns.nil?
|
137
140
|
return @returns if @returns == "void"
|
141
|
+
|
138
142
|
"returns(#{@returns})"
|
139
143
|
end
|
140
144
|
end
|
@@ -6,7 +6,7 @@ require_relative "signature_cop"
|
|
6
6
|
module RuboCop
|
7
7
|
module Cop
|
8
8
|
module Sorbet
|
9
|
-
#
|
9
|
+
# Checks for the ordering of keyword arguments required by
|
10
10
|
# sorbet-runtime. The ordering requires that all keyword arguments
|
11
11
|
# are at the end of the parameters list, and all keyword arguments
|
12
12
|
# with a default value must be after those without default values.
|
@@ -24,6 +24,7 @@ module RuboCop
|
|
24
24
|
def on_signature(node)
|
25
25
|
method_node = node.parent.children[node.sibling_index + 1]
|
26
26
|
return if method_node.nil?
|
27
|
+
|
27
28
|
method_parameters = method_node.arguments
|
28
29
|
|
29
30
|
check_order_for_kwoptargs(method_parameters)
|
@@ -35,13 +36,13 @@ module RuboCop
|
|
35
36
|
out_of_kwoptarg = false
|
36
37
|
|
37
38
|
parameters.reverse.each do |param|
|
38
|
-
out_of_kwoptarg = true unless param.
|
39
|
+
out_of_kwoptarg = true unless param.kwoptarg_type? || param.blockarg_type? || param.kwrestarg_type?
|
39
40
|
|
40
|
-
next unless param.
|
41
|
+
next unless param.kwoptarg_type? && out_of_kwoptarg
|
41
42
|
|
42
43
|
add_offense(
|
43
44
|
param,
|
44
|
-
message: "Optional keyword arguments must be at the end of the parameter list."
|
45
|
+
message: "Optional keyword arguments must be at the end of the parameter list.",
|
45
46
|
)
|
46
47
|
end
|
47
48
|
end
|
@@ -27,13 +27,18 @@ module RuboCop
|
|
27
27
|
:on_failure,
|
28
28
|
].each_with_index.to_h.freeze
|
29
29
|
|
30
|
+
# @!method root_call(node)
|
30
31
|
def_node_search(:root_call, <<~PATTERN)
|
31
32
|
(send nil? {#{ORDER.keys.map(&:inspect).join(" ")}} ...)
|
32
33
|
PATTERN
|
33
34
|
|
34
35
|
def on_signature(node)
|
35
36
|
calls = call_chain(node.children[2]).map(&:method_name)
|
36
|
-
return
|
37
|
+
return if calls.empty?
|
38
|
+
|
39
|
+
# While the developer is typing, we may have an incomplete call statement, which means `ORDER[call]` will
|
40
|
+
# return `nil`. In that case, invoking `sort_by` will raise
|
41
|
+
return if calls.any? { |call| ORDER[call].nil? }
|
37
42
|
|
38
43
|
expected_order = calls.sort_by { |call| ORDER[call] }
|
39
44
|
return if expected_order == calls
|
@@ -52,7 +57,7 @@ module RuboCop
|
|
52
57
|
end
|
53
58
|
|
54
59
|
def autocorrect(node)
|
55
|
-
return
|
60
|
+
return unless can_autocorrect?
|
56
61
|
|
57
62
|
lambda do |corrector|
|
58
63
|
tree = call_chain(node_reparsed_with_modern_features(node))
|
@@ -62,7 +67,7 @@ module RuboCop
|
|
62
67
|
end
|
63
68
|
|
64
69
|
corrector.replace(
|
65
|
-
node
|
70
|
+
node,
|
66
71
|
Unparser.unparse(tree),
|
67
72
|
)
|
68
73
|
end
|
@@ -8,9 +8,10 @@ module RuboCop
|
|
8
8
|
# Abstract cop specific to Sorbet signatures
|
9
9
|
#
|
10
10
|
# You can subclass it to use the `on_signature` trigger and the `signature?` node matcher.
|
11
|
-
class SignatureCop < RuboCop::Cop::Cop
|
11
|
+
class SignatureCop < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
|
12
12
|
@registry = Cop.registry # So we can properly subclass this cop
|
13
13
|
|
14
|
+
# @!method signature?(node)
|
14
15
|
def_node_matcher(:signature?, <<~PATTERN)
|
15
16
|
(block (send
|
16
17
|
{nil? #with_runtime? #without_runtime?}
|
@@ -19,10 +20,12 @@ module RuboCop
|
|
19
20
|
) (args) ...)
|
20
21
|
PATTERN
|
21
22
|
|
23
|
+
# @!method with_runtime?(node)
|
22
24
|
def_node_matcher(:with_runtime?, <<~PATTERN)
|
23
25
|
(const (const nil? :T) :Sig)
|
24
26
|
PATTERN
|
25
27
|
|
28
|
+
# @!method without_runtime?(node)
|
26
29
|
def_node_matcher(:without_runtime?, <<~PATTERN)
|
27
30
|
(const (const (const nil? :T) :Sig) :WithoutRuntime)
|
28
31
|
PATTERN
|
@@ -31,6 +34,8 @@ module RuboCop
|
|
31
34
|
on_signature(node) if signature?(node)
|
32
35
|
end
|
33
36
|
|
37
|
+
alias_method :on_numblock, :on_block
|
38
|
+
|
34
39
|
def on_signature(_)
|
35
40
|
# To be defined in subclasses
|
36
41
|
end
|
@@ -5,7 +5,7 @@ require "rubocop"
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module Sorbet
|
8
|
-
#
|
8
|
+
# Ensures all constants used as `T.type_alias` are using CamelCase.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
#
|
@@ -14,30 +14,23 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
# # good
|
16
16
|
# FooOrBar = T.type_alias { T.any(Foo, Bar) }
|
17
|
-
class TypeAliasName < RuboCop::Cop::
|
17
|
+
class TypeAliasName < RuboCop::Cop::Base
|
18
18
|
MSG = "Type alias constant name should be in CamelCase"
|
19
19
|
|
20
|
-
|
20
|
+
# @!method underscored_type_alias?(node)
|
21
|
+
def_node_matcher(:underscored_type_alias?, <<-PATTERN)
|
21
22
|
(casgn
|
22
23
|
_
|
23
|
-
_
|
24
|
+
/_/ # Name matches underscore
|
24
25
|
(block
|
25
|
-
(send
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
))
|
26
|
+
(send (const nil? :T) :type_alias)
|
27
|
+
...
|
28
|
+
)
|
29
|
+
)
|
30
30
|
PATTERN
|
31
31
|
|
32
32
|
def on_casgn(node)
|
33
|
-
|
34
|
-
|
35
|
-
name = node.children[1]
|
36
|
-
|
37
|
-
# From https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/naming/class_and_module_camel_case.rb
|
38
|
-
return unless /_/.match?(name)
|
39
|
-
|
40
|
-
add_offense(node)
|
33
|
+
add_offense(node) if underscored_type_alias?(node)
|
41
34
|
end
|
42
35
|
end
|
43
36
|
end
|
@@ -1,15 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require_relative "sorbet/mixin/target_sorbet_version.rb"
|
4
|
+
|
5
|
+
require_relative "sorbet/binding_constant_without_type_alias"
|
3
6
|
require_relative "sorbet/constants_from_strings"
|
4
7
|
require_relative "sorbet/forbid_superclass_const_literal"
|
5
8
|
require_relative "sorbet/forbid_include_const_literal"
|
6
9
|
require_relative "sorbet/forbid_untyped_struct_props"
|
10
|
+
require_relative "sorbet/implicit_conversion_method"
|
7
11
|
require_relative "sorbet/one_ancestor_per_line"
|
8
12
|
require_relative "sorbet/callback_conditionals_binding"
|
9
13
|
require_relative "sorbet/forbid_t_unsafe"
|
10
14
|
require_relative "sorbet/forbid_t_untyped"
|
11
15
|
require_relative "sorbet/redundant_extend_t_sig"
|
12
16
|
require_relative "sorbet/type_alias_name"
|
17
|
+
require_relative "sorbet/obsolete_strict_memoization"
|
13
18
|
|
14
19
|
require_relative "sorbet/rbi/forbid_extend_t_sig_helpers_in_shims"
|
15
20
|
require_relative "sorbet/rbi/forbid_rbi_outside_of_allowed_paths"
|
@@ -7,13 +7,15 @@ module RuboCop
|
|
7
7
|
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
8
8
|
# bit of our configuration.
|
9
9
|
module Inject
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
class << self
|
11
|
+
def defaults!
|
12
|
+
path = CONFIG_DEFAULT.to_s
|
13
|
+
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
14
|
+
config = Config.new(hash, path).tap(&:make_excludes_absolute)
|
15
|
+
puts "configuration from #{path}" if ConfigLoader.debug?
|
16
|
+
config = ConfigLoader.merge_with_default(config, path)
|
17
|
+
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/rubocop/sorbet.rb
CHANGED
data/manual/cops.md
CHANGED
@@ -24,7 +24,9 @@ In the following section you find all available cops:
|
|
24
24
|
* [Sorbet/ForbidUntypedStructProps](cops_sorbet.md#sorbetforbiduntypedstructprops)
|
25
25
|
* [Sorbet/HasSigil](cops_sorbet.md#sorbethassigil)
|
26
26
|
* [Sorbet/IgnoreSigil](cops_sorbet.md#sorbetignoresigil)
|
27
|
+
* [Sorbet/ImplicitConversionMethod](cops_sorbet.md#sorbetimplicitconversionmethod)
|
27
28
|
* [Sorbet/KeywordArgumentOrdering](cops_sorbet.md#sorbetkeywordargumentordering)
|
29
|
+
* [Sorbet/ObsoleteStrictMemoization](cops_sorbet.md#sorbetobsoletestrictmemoization)
|
28
30
|
* [Sorbet/OneAncestorPerLine](cops_sorbet.md#sorbetoneancestorperline)
|
29
31
|
* [Sorbet/RedundantExtendTSig](cops_sorbet.md#sorbetredundantextendtsig)
|
30
32
|
* [Sorbet/SignatureBuildOrder](cops_sorbet.md#sorbetsignaturebuildorder)
|