rubocop-sorbet 0.7.5 → 0.7.7

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: 9b2451806224baad5c72fb848ae38e6510037b2e26415afc236c3639f8504655
4
- data.tar.gz: e55c4a39d87a4fe345a6257e14483de155738ea5d39c25ef1e7822a2174321cb
3
+ metadata.gz: 8a1efe9f67422bb3173e5d5f91b3ccfd9f3862218af34495ca45e37be474ce6d
4
+ data.tar.gz: aeef803f94dd5084efa7d95cb1e899dd1e901b0a992acdb1e1bfe5b3613b78d7
5
5
  SHA512:
6
- metadata.gz: d05d0627ce52223c931f3461e221f6cb105838c21eeae6d68a7270934e6e292fcd2a7390453583c95d721bc1544125cb74f2d65ef6161c4d8fe823c3ee8217e6
7
- data.tar.gz: adf840bad5a49581286937604e83b3ee864f45031efb115db9faed9032da04d4178d7022b3d2040e08e8b10dc5f7a95bc8bf8a0ee1ac06ba74780b135d947b26
6
+ metadata.gz: 607f488db395a271ab0fe3997f710f1f275d04c62b0fdd00bfb3bf4b3ffbd0274315d65d284440078fe92415b3ba7b66f364de415af004ab45f745238081de31
7
+ data.tar.gz: d55d280a2c2404fe754bcb59445369b3c67c03329b4055700984e99effef6b6c53b7c44560925ee029f1a963649cbc65d30f49d30cb406fca7d92eafc83a6859
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.7.5)
4
+ rubocop-sorbet (0.7.7)
5
5
  rubocop (>= 0.90.0)
6
6
 
7
7
  GEM
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
@@ -89,6 +89,11 @@ Sorbet/ForbidIncludeConstLiteral:
89
89
  VersionAdded: 0.2.0
90
90
  VersionChanged: 0.5.0
91
91
 
92
+ Sorbet/ForbidTypeAliasedShapes:
93
+ Description: 'Forbids defining type aliases that contain shapes'
94
+ Enabled: false
95
+ VersionAdded: 0.7.6
96
+
92
97
  Sorbet/ForbidSuperclassConstLiteral:
93
98
  Description: 'Forbid superclasses which are non-literal constants.'
94
99
  Enabled: false
@@ -288,3 +293,8 @@ Sorbet/ValidSigil:
288
293
  - bin/**/*
289
294
  - db/**/*.rb
290
295
  - script/**/*
296
+
297
+ Sorbet/VoidCheckedTests:
298
+ Description: 'Forbid `.void.checked(:tests)`'
299
+ Enabled: true
300
+ VersionAdded: 0.7.7
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Sorbet
8
+ # Disallows defining type aliases that contain shapes
9
+ #
10
+ # @example
11
+ #
12
+ # # bad
13
+ # Foo = T.type_alias { { foo: Integer } }
14
+ #
15
+ # # good
16
+ # class Foo
17
+ # extend T::Sig
18
+ #
19
+ # sig { params(foo: Integer).void }
20
+ # def initialize(foo)
21
+ # @foo = foo
22
+ # end
23
+ # end
24
+ class ForbidTypeAliasedShapes < RuboCop::Cop::Base
25
+ MSG = "Type aliases shouldn't contain shapes because of significant performance overhead"
26
+
27
+ # @!method shape_type_alias?(node)
28
+ def_node_matcher(:shape_type_alias?, <<-PATTERN)
29
+ (block
30
+ (send (const {nil? cbase} :T) :type_alias)
31
+ (args)
32
+ `hash
33
+ )
34
+ PATTERN
35
+
36
+ def on_block(node)
37
+ add_offense(node) if shape_type_alias?(node)
38
+ end
39
+
40
+ alias_method :on_numblock, :on_block
41
+ end
42
+ end
43
+ end
44
+ 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
@@ -7,6 +7,7 @@ require_relative "sorbet/binding_constant_without_type_alias"
7
7
  require_relative "sorbet/constants_from_strings"
8
8
  require_relative "sorbet/forbid_superclass_const_literal"
9
9
  require_relative "sorbet/forbid_include_const_literal"
10
+ require_relative "sorbet/forbid_type_aliased_shapes"
10
11
  require_relative "sorbet/forbid_untyped_struct_props"
11
12
  require_relative "sorbet/implicit_conversion_method"
12
13
  require_relative "sorbet/one_ancestor_per_line"
@@ -25,6 +26,7 @@ require_relative "sorbet/rbi/single_line_rbi_class_module_definitions"
25
26
 
26
27
  require_relative "sorbet/signatures/allow_incompatible_override"
27
28
  require_relative "sorbet/signatures/checked_true_in_signature"
29
+ require_relative "sorbet/signatures/void_checked_tests"
28
30
  require_relative "sorbet/signatures/keyword_argument_ordering"
29
31
  require_relative "sorbet/signatures/signature_build_order"
30
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.5"
5
+ VERSION = "0.7.7"
6
6
  end
7
7
  end
data/manual/cops.md CHANGED
@@ -23,6 +23,7 @@ In the following section you find all available cops:
23
23
  * [Sorbet/ForbidTStruct](cops_sorbet.md#sorbetforbidtstruct)
24
24
  * [Sorbet/ForbidTUnsafe](cops_sorbet.md#sorbetforbidtunsafe)
25
25
  * [Sorbet/ForbidTUntyped](cops_sorbet.md#sorbetforbidtuntyped)
26
+ * [Sorbet/ForbidTypeAliasedShapes](cops_sorbet.md#sorbetforbidtypealiasedshapes)
26
27
  * [Sorbet/ForbidUntypedStructProps](cops_sorbet.md#sorbetforbiduntypedstructprops)
27
28
  * [Sorbet/HasSigil](cops_sorbet.md#sorbethassigil)
28
29
  * [Sorbet/IgnoreSigil](cops_sorbet.md#sorbetignoresigil)
@@ -38,6 +39,7 @@ In the following section you find all available cops:
38
39
  * [Sorbet/TrueSigil](cops_sorbet.md#sorbettruesigil)
39
40
  * [Sorbet/TypeAliasName](cops_sorbet.md#sorbettypealiasname)
40
41
  * [Sorbet/ValidSigil](cops_sorbet.md#sorbetvalidsigil)
42
+ * [Sorbet/VoidCheckedTests](cops_sorbet.md#sorbetvoidcheckedtests)
41
43
 
42
44
  <!-- END_COP_LIST -->
43
45
 
@@ -496,6 +496,31 @@ sig { params(my_argument: String).void }
496
496
  def foo(my_argument); end
497
497
  ```
498
498
 
499
+ ## Sorbet/ForbidTypeAliasedShapes
500
+
501
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
502
+ --- | --- | --- | --- | ---
503
+ Disabled | Yes | No | 0.7.6 | -
504
+
505
+ Disallows defining type aliases that contain shapes
506
+
507
+ ### Examples
508
+
509
+ ```ruby
510
+ # bad
511
+ Foo = T.type_alias { { foo: Integer } }
512
+
513
+ # good
514
+ class Foo
515
+ extend T::Sig
516
+
517
+ sig { params(foo: Integer).void }
518
+ def initialize(foo)
519
+ @foo = foo
520
+ end
521
+ end
522
+ ```
523
+
499
524
  ## Sorbet/ForbidUntypedStructProps
500
525
 
501
526
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
@@ -715,12 +740,6 @@ Checks for the correct order of sig builder methods:
715
740
  - returns, or void
716
741
  - soft, checked, or on_failure
717
742
 
718
- # bad
719
- sig { returns(Integer).params(x: Integer) }
720
-
721
- # good
722
- sig { params(x: Integer).returns(Integer) }
723
-
724
743
  ### Examples
725
744
 
726
745
  ```ruby
@@ -729,6 +748,12 @@ sig { void.abstract }
729
748
 
730
749
  # good
731
750
  sig { abstract.void }
751
+
752
+ # bad
753
+ sig { returns(Integer).params(x: Integer) }
754
+
755
+ # good
756
+ sig { params(x: Integer).returns(Integer) }
732
757
  ```
733
758
 
734
759
  ## Sorbet/SingleLineRbiClassModuleDefinitions
@@ -859,3 +884,37 @@ MinimumStrictness | `nil` | String
859
884
  ExactStrictness | `nil` | String
860
885
  Include | `**/*.{rb,rbi,rake,ru}` | Array
861
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.5
4
+ version: 0.7.7
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-10-31 00:00:00.000000000 Z
14
+ date: 2024-02-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rspec
@@ -95,6 +95,7 @@ files:
95
95
  - lib/rubocop/cop/sorbet/forbid_t_struct.rb
96
96
  - lib/rubocop/cop/sorbet/forbid_t_unsafe.rb
97
97
  - lib/rubocop/cop/sorbet/forbid_t_untyped.rb
98
+ - lib/rubocop/cop/sorbet/forbid_type_aliased_shapes.rb
98
99
  - lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb
99
100
  - lib/rubocop/cop/sorbet/implicit_conversion_method.rb
100
101
  - lib/rubocop/cop/sorbet/mixin/signature_help.rb
@@ -121,6 +122,7 @@ files:
121
122
  - lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb
122
123
  - lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb
123
124
  - lib/rubocop/cop/sorbet/signatures/signature_build_order.rb
125
+ - lib/rubocop/cop/sorbet/signatures/void_checked_tests.rb
124
126
  - lib/rubocop/cop/sorbet/type_alias_name.rb
125
127
  - lib/rubocop/cop/sorbet_cops.rb
126
128
  - lib/rubocop/sorbet.rb
@@ -154,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
156
  - !ruby/object:Gem::Version
155
157
  version: '0'
156
158
  requirements: []
157
- rubygems_version: 3.4.21
159
+ rubygems_version: 3.5.6
158
160
  signing_key:
159
161
  specification_version: 4
160
162
  summary: Automatic Sorbet code style checking tool.