rubocop-sorbet 0.7.6 → 0.7.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bb19df178a322278126862ef69ee548a1480a3273b2fa7cb390efea682076d3
4
- data.tar.gz: a4808b614e42b591e1254298ae40b41327b5762f5d7e494e5dbd476034d7f5a8
3
+ metadata.gz: 68f2d0d8c272caa3933e34350356e99c32e0ec42bec4b43a39c748ef2422d048
4
+ data.tar.gz: c0bd1e275d17d85ff1a6f63ab0bad42f47e5f3f17480ac4d06e5d70f4f52973d
5
5
  SHA512:
6
- metadata.gz: 495f4c62a3e669483d4a2fb958672480e1f50519589bbef0efab007b32f56c32fad54a795a47ee8da6157d4595da0a50f845744578e0f44fab34e57fc67aa28e
7
- data.tar.gz: 3e07de7f56533ed0c86dfb510e8efa0a3d1c9eb79cd130f24235cd6919a1f05ca88afc8fa7ae114de9de3ed49beac2ddc16d0d0c3e37a0a2bf6f7404ac80dcaa
6
+ metadata.gz: 8746cfe46cc7c1f7ecc6f4310c21a725b34172168de624a02485c890b5441948e26fc4617b488365a055fa3d44ee2193a5eb41ab0c4423d06d3cea8d058ccb55
7
+ data.tar.gz: e32a6b29d524cbb963c69ba8bb7bbb6b8535ac9793c0ff80db7817aa9ce751e4a6d82161f50a2942fd3a0c17e61c70954bf4406718430cb72167564963348452
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.7.6)
4
+ rubocop-sorbet (0.7.8)
5
5
  rubocop (>= 0.90.0)
6
6
 
7
7
  GEM
@@ -54,7 +54,7 @@ GEM
54
54
  unparser (0.6.0)
55
55
  diff-lcs (~> 1.3)
56
56
  parser (>= 3.0.0)
57
- yard (0.9.25)
57
+ yard (0.9.36)
58
58
 
59
59
  PLATFORMS
60
60
  ruby
data/README.md CHANGED
@@ -69,6 +69,14 @@ inherit_gem:
69
69
 
70
70
  This will turn off default cops for `**/*.rbi` files and enable the RBI specific cops.
71
71
 
72
+ You'll also need to add an entry to the main `.rubocop.yml` so that RBI files are included, e.g.:
73
+
74
+ ```yaml
75
+ AllCops:
76
+ Include:
77
+ - "sorbet/rbi/shims/**/*.rbi"
78
+ ```
79
+
72
80
  ## The Cops
73
81
  All cops are located under [`lib/rubocop/cop/sorbet`](lib/rubocop/cop/sorbet), and contain examples/documentation.
74
82
 
data/config/default.yml CHANGED
@@ -293,3 +293,8 @@ Sorbet/ValidSigil:
293
293
  - bin/**/*
294
294
  - db/**/*.rb
295
295
  - script/**/*
296
+
297
+ Sorbet/VoidCheckedTests:
298
+ Description: 'Forbid `.void.checked(:tests)`'
299
+ Enabled: true
300
+ VersionAdded: 0.7.7
@@ -102,7 +102,7 @@ module RuboCop
102
102
  end
103
103
 
104
104
  class Property
105
- attr_reader :node, :kind, :name, :type, :default, :factory
105
+ attr_reader :node, :kind, :name, :default, :factory
106
106
 
107
107
  def initialize(node, kind, name, type, default:, factory:)
108
108
  @node = node
@@ -151,6 +151,11 @@ module RuboCop
151
151
  def nilable?
152
152
  type.start_with?("T.nilable(")
153
153
  end
154
+
155
+ def type
156
+ copy = @type.gsub(/[[:space:]]+/, "").strip # Remove newlines and spaces
157
+ copy.gsub(",", ", ") # Add a space after each comma
158
+ end
154
159
  end
155
160
 
156
161
  # @!method t_struct?(node)
@@ -215,8 +220,35 @@ module RuboCop
215
220
  sorted_props = props.sort_by { |prop| prop.default || prop.factory || prop.nilable? ? 1 : 0 }
216
221
 
217
222
  string = +"\n"
218
- string << "#{indent}sig { params(#{sorted_props.map(&:initialize_sig_param).join(", ")}).void }\n"
219
- string << "#{indent}def initialize(#{sorted_props.map(&:initialize_param).join(", ")})\n"
223
+
224
+ line = "#{indent}sig { params(#{sorted_props.map(&:initialize_sig_param).join(", ")}).void }\n"
225
+ if line.length <= max_line_length
226
+ string << line
227
+ else
228
+ string << "#{indent}sig do\n"
229
+ string << "#{indent} params(\n"
230
+ sorted_props.each do |prop|
231
+ string << "#{indent} #{prop.initialize_sig_param}"
232
+ string << "," if prop != sorted_props.last
233
+ string << "\n"
234
+ end
235
+ string << "#{indent} ).void\n"
236
+ string << "#{indent}end\n"
237
+ end
238
+
239
+ line = "#{indent}def initialize(#{sorted_props.map(&:initialize_param).join(", ")})\n"
240
+ if line.length <= max_line_length
241
+ string << line
242
+ else
243
+ string << "#{indent}def initialize(\n"
244
+ sorted_props.each do |prop|
245
+ string << "#{indent} #{prop.initialize_param}"
246
+ string << "," if prop != sorted_props.last
247
+ string << "\n"
248
+ end
249
+ string << "#{indent})\n"
250
+ end
251
+
220
252
  props.each do |prop|
221
253
  string << "#{indent} #{prop.initialize_assign}\n"
222
254
  end
@@ -23,11 +23,11 @@ module RuboCop
23
23
  # # good
24
24
  # sig { abstract.void }
25
25
  #
26
- # # bad
27
- # sig { returns(Integer).params(x: Integer) }
26
+ # # bad
27
+ # sig { returns(Integer).params(x: Integer) }
28
28
  #
29
- # # good
30
- # sig { params(x: Integer).returns(Integer) }
29
+ # # good
30
+ # sig { params(x: Integer).returns(Integer) }
31
31
  class SignatureBuildOrder < ::RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
32
32
  include SignatureHelp
33
33
 
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # Disallows the usage of `.void.checked(:tests)`.
7
+ #
8
+ # Using `.void` changes the value returned from the method, but only if
9
+ # runtime type checking is enabled for the method. Methods marked `.void`
10
+ # will return different values in tests compared with non-test
11
+ # environments. This is particularly troublesome if branching on the
12
+ # result of a `.void` method, because the returned value in test code
13
+ # will be the truthy `VOID` value, while the non-test return value may be
14
+ # falsy depending on the method's implementation.
15
+ #
16
+ # - Use `.returns(T.anything).checked(:tests)` to keep the runtime type
17
+ # checking for the rest of the parameters.
18
+ # - Use `.void.checked(:never)` if you are on an older version of Sorbet
19
+ # which does not have `T.anything` (meaning versions 0.5.10781 or
20
+ # earlier. Versions released after 2023-04-14 include `T.anything`.)
21
+ #
22
+ # @example
23
+ #
24
+ # # bad
25
+ # sig { void.checked(:tests) }
26
+ #
27
+ # # good
28
+ # sig { void }
29
+ # sig { returns(T.anything).checked(:tests) }
30
+ # sig { void.checked(:never) }
31
+ class VoidCheckedTests < ::RuboCop::Cop::Base
32
+ include(RuboCop::Cop::RangeHelp)
33
+ include(RuboCop::Cop::Sorbet::SignatureHelp)
34
+ extend AutoCorrector
35
+
36
+ # @!method checked_tests(node)
37
+ def_node_search(:checked_tests, <<~PATTERN)
38
+ ({csend send} _ :checked (sym :tests))
39
+ PATTERN
40
+
41
+ MESSAGE =
42
+ "Returning `.void` from a sig marked `.checked(:tests)` means that the " \
43
+ "method will return a different value in non-test environments (possibly " \
44
+ "with different truthiness). Either use `.returns(T.anything).checked(:tests)` " \
45
+ "to keep checking in tests, or `.void.checked(:never)` to leave it untouched."
46
+ private_constant(:MESSAGE)
47
+
48
+ private def top_level_void(node)
49
+ return unless node.is_a?(RuboCop::AST::SendNode)
50
+
51
+ if node.method?(:void)
52
+ node
53
+ elsif (recv = node.receiver)
54
+ top_level_void(recv)
55
+ end
56
+ end
57
+
58
+ def on_signature(node)
59
+ checked_send = checked_tests(node).first
60
+ return unless checked_send
61
+
62
+ if (parent = node.parent) && (sibling_index = node.sibling_index)
63
+ later_siblings = parent.children[(sibling_index + 1)..]
64
+ if (def_node = later_siblings.find { |sibling| sibling.is_a?(RuboCop::AST::DefNode) })
65
+ # Sorbet requires that `initialize` methods return `.void`
66
+ # (A stylistic convention which happens to be enforced by Sorbet)
67
+ return if def_node.method?(:initialize)
68
+ end
69
+ end
70
+
71
+ void_send = top_level_void(node.body)
72
+
73
+ return unless void_send
74
+
75
+ add_offense(
76
+ void_send.selector,
77
+ message: MESSAGE,
78
+ ) do |corrector|
79
+ corrector.replace(void_send.selector, "returns(T.anything)")
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -26,6 +26,7 @@ require_relative "sorbet/rbi/single_line_rbi_class_module_definitions"
26
26
 
27
27
  require_relative "sorbet/signatures/allow_incompatible_override"
28
28
  require_relative "sorbet/signatures/checked_true_in_signature"
29
+ require_relative "sorbet/signatures/void_checked_tests"
29
30
  require_relative "sorbet/signatures/keyword_argument_ordering"
30
31
  require_relative "sorbet/signatures/signature_build_order"
31
32
  require_relative "sorbet/signatures/enforce_signatures"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Sorbet
5
- VERSION = "0.7.6"
5
+ VERSION = "0.7.8"
6
6
  end
7
7
  end
data/manual/cops.md CHANGED
@@ -39,6 +39,7 @@ In the following section you find all available cops:
39
39
  * [Sorbet/TrueSigil](cops_sorbet.md#sorbettruesigil)
40
40
  * [Sorbet/TypeAliasName](cops_sorbet.md#sorbettypealiasname)
41
41
  * [Sorbet/ValidSigil](cops_sorbet.md#sorbetvalidsigil)
42
+ * [Sorbet/VoidCheckedTests](cops_sorbet.md#sorbetvoidcheckedtests)
42
43
 
43
44
  <!-- END_COP_LIST -->
44
45
 
@@ -740,12 +740,6 @@ Checks for the correct order of sig builder methods:
740
740
  - returns, or void
741
741
  - soft, checked, or on_failure
742
742
 
743
- # bad
744
- sig { returns(Integer).params(x: Integer) }
745
-
746
- # good
747
- sig { params(x: Integer).returns(Integer) }
748
-
749
743
  ### Examples
750
744
 
751
745
  ```ruby
@@ -754,6 +748,12 @@ sig { void.abstract }
754
748
 
755
749
  # good
756
750
  sig { abstract.void }
751
+
752
+ # bad
753
+ sig { returns(Integer).params(x: Integer) }
754
+
755
+ # good
756
+ sig { params(x: Integer).returns(Integer) }
757
757
  ```
758
758
 
759
759
  ## Sorbet/SingleLineRbiClassModuleDefinitions
@@ -884,3 +884,37 @@ MinimumStrictness | `nil` | String
884
884
  ExactStrictness | `nil` | String
885
885
  Include | `**/*.{rb,rbi,rake,ru}` | Array
886
886
  Exclude | `bin/**/*`, `db/**/*.rb`, `script/**/*` | Array
887
+
888
+ ## Sorbet/VoidCheckedTests
889
+
890
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
891
+ --- | --- | --- | --- | ---
892
+ Enabled | Yes | Yes | 0.7.7 | -
893
+
894
+ Disallows the usage of `.void.checked(:tests)`.
895
+
896
+ Using `.void` changes the value returned from the method, but only if
897
+ runtime type checking is enabled for the method. Methods marked `.void`
898
+ will return different values in tests compared with non-test
899
+ environments. This is particularly troublesome if branching on the
900
+ result of a `.void` method, because the returned value in test code
901
+ will be the truthy `VOID` value, while the non-test return value may be
902
+ falsy depending on the method's implementation.
903
+
904
+ - Use `.returns(T.anything).checked(:tests)` to keep the runtime type
905
+ checking for the rest of the parameters.
906
+ - Use `.void.checked(:never)` if you are on an older version of Sorbet
907
+ which does not have `T.anything` (meaning versions 0.5.10781 or
908
+ earlier. Versions released after 2023-04-14 include `T.anything`.)
909
+
910
+ ### Examples
911
+
912
+ ```ruby
913
+ # bad
914
+ sig { void.checked(:tests) }
915
+
916
+ # good
917
+ sig { void }
918
+ sig { returns(T.anything).checked(:tests) }
919
+ sig { void.checked(:never) }
920
+ ```
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.6
4
+ version: 0.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2023-12-04 00:00:00.000000000 Z
14
+ date: 2024-03-06 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rspec
@@ -122,6 +122,7 @@ files:
122
122
  - lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb
123
123
  - lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb
124
124
  - lib/rubocop/cop/sorbet/signatures/signature_build_order.rb
125
+ - lib/rubocop/cop/sorbet/signatures/void_checked_tests.rb
125
126
  - lib/rubocop/cop/sorbet/type_alias_name.rb
126
127
  - lib/rubocop/cop/sorbet_cops.rb
127
128
  - lib/rubocop/sorbet.rb
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
156
  - !ruby/object:Gem::Version
156
157
  version: '0'
157
158
  requirements: []
158
- rubygems_version: 3.4.22
159
+ rubygems_version: 3.5.6
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: Automatic Sorbet code style checking tool.