rbi 0.1.13 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,169 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class UnexpectedMultipleSigsError < Error
6
+ sig { returns(Node) }
7
+ attr_reader :node
8
+
9
+ sig { params(node: Node).void }
10
+ def initialize(node)
11
+ super(<<~MSG)
12
+ This declaration cannot have more than one sig.
13
+
14
+ #{node.string.chomp}
15
+ MSG
16
+
17
+ @node = node
18
+ end
19
+ end
20
+
21
+ module Rewriters
22
+ class AttrToMethods < Visitor
23
+ extend T::Sig
24
+
25
+ sig { override.params(node: T.nilable(Node)).void }
26
+ def visit(node)
27
+ case node
28
+ when Tree
29
+ visit_all(node.nodes.dup)
30
+
31
+ when Attr
32
+ replace(node, with: node.convert_to_methods)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ sig { params(node: Node, with: T::Array[Node]).void }
39
+ def replace(node, with:)
40
+ tree = node.parent_tree
41
+ raise ReplaceNodeError, "Can't replace #{self} without a parent tree" unless tree
42
+
43
+ node.detach
44
+ with.each { |node| tree << node }
45
+ end
46
+ end
47
+ end
48
+
49
+ class Tree
50
+ extend T::Sig
51
+
52
+ sig { void }
53
+ def replace_attributes_with_methods!
54
+ visitor = Rewriters::AttrToMethods.new
55
+ visitor.visit(self)
56
+ end
57
+ end
58
+
59
+ class Attr
60
+ sig { abstract.returns(T::Array[Method]) }
61
+ def convert_to_methods; end
62
+
63
+ private
64
+
65
+ sig(:final) { returns([T.nilable(Sig), T.nilable(T.any(Type, String))]) }
66
+ def parse_sig
67
+ raise UnexpectedMultipleSigsError, self if 1 < sigs.count
68
+
69
+ sig = sigs.first
70
+ return [nil, nil] unless sig
71
+
72
+ attribute_type = case self
73
+ when AttrReader, AttrAccessor then sig.return_type
74
+ when AttrWriter then sig.params.first&.type
75
+ end
76
+
77
+ [sig, attribute_type]
78
+ end
79
+
80
+ sig do
81
+ params(
82
+ name: String,
83
+ sig: T.nilable(Sig),
84
+ visibility: Visibility,
85
+ loc: T.nilable(Loc),
86
+ comments: T::Array[Comment],
87
+ ).returns(Method)
88
+ end
89
+ def create_getter_method(name, sig, visibility, loc, comments)
90
+ Method.new(
91
+ name,
92
+ params: [],
93
+ visibility: visibility,
94
+ sigs: sig ? [sig] : [],
95
+ loc: loc,
96
+ comments: comments,
97
+ )
98
+ end
99
+
100
+ sig do
101
+ params(
102
+ name: String,
103
+ sig: T.nilable(Sig),
104
+ attribute_type: T.nilable(T.any(Type, String)),
105
+ visibility: Visibility,
106
+ loc: T.nilable(Loc),
107
+ comments: T::Array[Comment],
108
+ ).returns(Method)
109
+ end
110
+ def create_setter_method(name, sig, attribute_type, visibility, loc, comments) # rubocop:disable Metrics/ParameterLists
111
+ sig = if sig # Modify the original sig to correct the name, and remove the return type
112
+ params = attribute_type ? [SigParam.new(name, attribute_type)] : []
113
+
114
+ Sig.new(
115
+ params: params,
116
+ return_type: "void",
117
+ is_abstract: sig.is_abstract,
118
+ is_override: sig.is_override,
119
+ is_overridable: sig.is_overridable,
120
+ is_final: sig.is_final,
121
+ type_params: sig.type_params,
122
+ checked: sig.checked,
123
+ loc: sig.loc,
124
+ )
125
+ end
126
+
127
+ Method.new(
128
+ "#{name}=",
129
+ params: [ReqParam.new(name)],
130
+ visibility: visibility,
131
+ sigs: sig ? [sig] : [],
132
+ loc: loc,
133
+ comments: comments,
134
+ )
135
+ end
136
+ end
137
+
138
+ class AttrAccessor
139
+ sig { override.returns(T::Array[Method]) }
140
+ def convert_to_methods
141
+ sig, attribute_type = parse_sig
142
+
143
+ names.flat_map do |name|
144
+ [
145
+ create_getter_method(name.to_s, sig, visibility, loc, comments),
146
+ create_setter_method(name.to_s, sig, attribute_type, visibility, loc, comments),
147
+ ]
148
+ end
149
+ end
150
+ end
151
+
152
+ class AttrReader
153
+ sig { override.returns(T::Array[Method]) }
154
+ def convert_to_methods
155
+ sig, _ = parse_sig
156
+
157
+ names.map { |name| create_getter_method(name.to_s, sig, visibility, loc, comments) }
158
+ end
159
+ end
160
+
161
+ class AttrWriter
162
+ sig { override.returns(T::Array[Method]) }
163
+ def convert_to_methods
164
+ sig, attribute_type = parse_sig
165
+
166
+ names.map { |name| create_setter_method(name.to_s, sig, attribute_type, visibility, loc, comments) }
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,65 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ module Rewriters
6
+ # Rewrite non-singleton methods inside singleton classes to singleton methods
7
+ #
8
+ # Example:
9
+ # ~~~rb
10
+ # class << self
11
+ # def m1; end
12
+ # def self.m2; end
13
+ #
14
+ # class << self
15
+ # def m3; end
16
+ # end
17
+ # end
18
+ # ~~~
19
+ #
20
+ # will be rewritten to:
21
+ #
22
+ # ~~~rb
23
+ # def self.m1; end
24
+ #
25
+ # class << self
26
+ # def self.m2; end
27
+ # def self.m3; end
28
+ # end
29
+ # ~~~
30
+ class FlattenSingletonMethods < Visitor
31
+ extend T::Sig
32
+
33
+ sig { override.params(node: T.nilable(Node)).void }
34
+ def visit(node)
35
+ return unless node
36
+
37
+ case node
38
+ when SingletonClass
39
+ node.nodes.dup.each do |child|
40
+ visit(child)
41
+ next unless child.is_a?(Method) && !child.is_singleton
42
+
43
+ child.detach
44
+ child.is_singleton = true
45
+ T.must(node.parent_tree) << child
46
+ end
47
+
48
+ node.detach if node.nodes.empty?
49
+ when Tree
50
+ visit_all(node.nodes)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ class Tree
57
+ extend T::Sig
58
+
59
+ sig { void }
60
+ def flatten_singleton_methods!
61
+ visitor = Rewriters::FlattenSingletonMethods.new
62
+ visitor.visit(self)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,65 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ module Rewriters
6
+ # Flattens visibility nodes into method nodes
7
+ #
8
+ # Example:
9
+ # ~~~rb
10
+ # class A
11
+ # def m1; end
12
+ # private
13
+ # def m2; end
14
+ # def m3; end
15
+ # end
16
+ # ~~~
17
+ #
18
+ # will be transformed into:
19
+ #
20
+ # ~~~rb
21
+ # class A
22
+ # def m1; end
23
+ # private def m2; end
24
+ # private def m3; end
25
+ # end
26
+ # ~~~
27
+ class FlattenVisibilities < Visitor
28
+ extend T::Sig
29
+
30
+ sig { void }
31
+ def initialize
32
+ super
33
+
34
+ @current_visibility = T.let([Public.new], T::Array[Visibility])
35
+ end
36
+
37
+ sig { override.params(node: T.nilable(Node)).void }
38
+ def visit(node)
39
+ return unless node
40
+
41
+ case node
42
+ when Public, Protected, Private
43
+ @current_visibility[-1] = node
44
+ node.detach
45
+ when Tree
46
+ @current_visibility << Public.new
47
+ visit_all(node.nodes.dup)
48
+ @current_visibility.pop
49
+ when Attr, Method
50
+ node.visibility = T.must(@current_visibility.last)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ class Tree
57
+ extend T::Sig
58
+
59
+ sig { void }
60
+ def flatten_visibilities!
61
+ visitor = Rewriters::FlattenVisibilities.new
62
+ visitor.visit(self)
63
+ end
64
+ end
65
+ end
@@ -2,6 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RBI
5
+ class GroupNodesError < Error; end
6
+
5
7
  module Rewriters
6
8
  class GroupNodes < Visitor
7
9
  extend T::Sig
@@ -12,8 +14,7 @@ module RBI
12
14
 
13
15
  case node
14
16
  when Tree
15
- kinds = node.nodes.map(&:group_kind)
16
- kinds.compact!
17
+ kinds = node.nodes.map { |child| group_kind(child) }
17
18
  kinds.uniq!
18
19
 
19
20
  groups = {}
@@ -22,12 +23,54 @@ module RBI
22
23
  node.nodes.dup.each do |child|
23
24
  visit(child)
24
25
  child.detach
25
- groups[child.group_kind] << child
26
+ groups[group_kind(child)] << child
26
27
  end
27
28
 
28
29
  groups.each { |_, group| node << group }
29
30
  end
30
31
  end
32
+
33
+ private
34
+
35
+ sig { params(node: Node).returns(Group::Kind) }
36
+ def group_kind(node)
37
+ case node
38
+ when Group
39
+ node.kind
40
+ when Include, Extend
41
+ Group::Kind::Mixins
42
+ when RequiresAncestor
43
+ Group::Kind::RequiredAncestors
44
+ when Helper
45
+ Group::Kind::Helpers
46
+ when TypeMember
47
+ Group::Kind::TypeMembers
48
+ when MixesInClassMethods
49
+ Group::Kind::MixesInClassMethods
50
+ when Send
51
+ Group::Kind::Sends
52
+ when Attr
53
+ Group::Kind::Attrs
54
+ when TStructField
55
+ Group::Kind::TStructFields
56
+ when TEnumBlock
57
+ Group::Kind::TEnums
58
+ when VisibilityGroup
59
+ Group::Kind::Methods
60
+ when Method
61
+ if node.name == "initialize"
62
+ Group::Kind::Inits
63
+ else
64
+ Group::Kind::Methods
65
+ end
66
+ when SingletonClass
67
+ Group::Kind::SingletonClasses
68
+ when Scope, Const
69
+ Group::Kind::Consts
70
+ else
71
+ raise GroupNodesError, "Unknown group for #{self}"
72
+ end
73
+ end
31
74
  end
32
75
  end
33
76
 
@@ -41,50 +84,6 @@ module RBI
41
84
  end
42
85
  end
43
86
 
44
- class Node
45
- extend T::Sig
46
-
47
- sig { returns(Group::Kind) }
48
- def group_kind
49
- case self
50
- when Group
51
- kind
52
- when Include, Extend
53
- Group::Kind::Mixins
54
- when RequiresAncestor
55
- Group::Kind::RequiredAncestors
56
- when Helper
57
- Group::Kind::Helpers
58
- when TypeMember
59
- Group::Kind::TypeMembers
60
- when MixesInClassMethods
61
- Group::Kind::MixesInClassMethods
62
- when Send
63
- Group::Kind::Sends
64
- when Attr
65
- Group::Kind::Attrs
66
- when TStructField
67
- Group::Kind::TStructFields
68
- when TEnumBlock
69
- Group::Kind::TEnums
70
- when VisibilityGroup
71
- Group::Kind::Methods
72
- when Method
73
- if name == "initialize"
74
- Group::Kind::Inits
75
- else
76
- Group::Kind::Methods
77
- end
78
- when SingletonClass
79
- Group::Kind::SingletonClasses
80
- when Scope, Const
81
- Group::Kind::Consts
82
- else
83
- raise "Unknown group for #{self}"
84
- end
85
- end
86
- end
87
-
88
87
  class Group < Tree
89
88
  extend T::Sig
90
89
 
@@ -348,6 +348,8 @@ module RBI
348
348
  end
349
349
  end
350
350
 
351
+ class DuplicateNodeError < Error; end
352
+
351
353
  class Scope
352
354
  extend T::Sig
353
355
 
@@ -357,6 +359,12 @@ module RBI
357
359
  case self
358
360
  when Module
359
361
  Module.new(name, loc: loc, comments: comments)
362
+ when TEnum
363
+ TEnum.new(name, loc: loc, comments: comments)
364
+ when TEnumBlock
365
+ TEnumBlock.new(loc: loc, comments: comments)
366
+ when TStruct
367
+ TStruct.new(name, loc: loc, comments: comments)
360
368
  when Class
361
369
  Class.new(name, superclass_name: superclass_name, loc: loc, comments: comments)
362
370
  when Struct
@@ -364,7 +372,7 @@ module RBI
364
372
  when SingletonClass
365
373
  SingletonClass.new(loc: loc, comments: comments)
366
374
  else
367
- raise "Can't duplicate node #{self}"
375
+ raise DuplicateNodeError, "Can't duplicate node #{self}"
368
376
  end
369
377
  end
370
378
  end
@@ -549,20 +557,6 @@ module RBI
549
557
  end
550
558
  end
551
559
 
552
- class TEnumBlock
553
- extend T::Sig
554
-
555
- sig { override.params(other: Node).void }
556
- def merge_with(other)
557
- return unless other.is_a?(TEnumBlock)
558
-
559
- super
560
- other.names.each do |name|
561
- names << name unless names.include?(name)
562
- end
563
- end
564
- end
565
-
566
560
  class TStructProp
567
561
  extend T::Sig
568
562
 
@@ -592,6 +586,9 @@ module RBI
592
586
  sig { returns(Tree) }
593
587
  attr_reader :left, :right
594
588
 
589
+ sig { returns(String) }
590
+ attr_reader :left_name, :right_name
591
+
595
592
  sig { params(left_name: String, right_name: String).void }
596
593
  def initialize(left_name: "left", right_name: "right")
597
594
  super()
@@ -602,15 +599,6 @@ module RBI
602
599
  @right = T.let(Tree.new, Tree)
603
600
  @right.parent_tree = self
604
601
  end
605
-
606
- sig { override.params(v: Printer).void }
607
- def accept_printer(v)
608
- v.printl("<<<<<<< #{@left_name}")
609
- v.visit(left)
610
- v.printl("=======")
611
- v.visit(right)
612
- v.printl(">>>>>>> #{@right_name}")
613
- end
614
602
  end
615
603
 
616
604
  # A conflict between two scope headers
@@ -631,6 +619,9 @@ module RBI
631
619
  sig { returns(Scope) }
632
620
  attr_reader :left, :right
633
621
 
622
+ sig { returns(String) }
623
+ attr_reader :left_name, :right_name
624
+
634
625
  sig do
635
626
  params(
636
627
  left: Scope,
@@ -646,26 +637,5 @@ module RBI
646
637
  @left_name = left_name
647
638
  @right_name = right_name
648
639
  end
649
-
650
- sig { override.params(v: Printer).void }
651
- def accept_printer(v)
652
- previous_node = v.previous_node
653
- v.printn if previous_node && (!previous_node.oneline? || !oneline?)
654
-
655
- v.printl("# #{loc}") if loc && v.print_locs
656
- v.visit_all(comments)
657
-
658
- v.printl("<<<<<<< #{@left_name}")
659
- left.print_header(v)
660
- v.printl("=======")
661
- right.print_header(v)
662
- v.printl(">>>>>>> #{@right_name}")
663
- left.print_body(v)
664
- end
665
-
666
- sig { override.returns(T::Boolean) }
667
- def oneline?
668
- left.oneline?
669
- end
670
640
  end
671
641
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RBI
5
5
  module Rewriters
6
- class NestNonPublicMethods < Visitor
6
+ class NestNonPublicMembers < Visitor
7
7
  extend T::Sig
8
8
 
9
9
  sig { override.params(node: T.nilable(Node)).void }
@@ -18,7 +18,7 @@ module RBI
18
18
 
19
19
  node.nodes.dup.each do |child|
20
20
  visit(child)
21
- next unless child.is_a?(Method)
21
+ next unless child.is_a?(Attr) || child.is_a?(Method)
22
22
 
23
23
  child.detach
24
24
  case child.visibility
@@ -43,8 +43,8 @@ module RBI
43
43
  extend T::Sig
44
44
 
45
45
  sig { void }
46
- def nest_non_public_methods!
47
- visitor = Rewriters::NestNonPublicMethods.new
46
+ def nest_non_public_members!
47
+ visitor = Rewriters::NestNonPublicMembers.new
48
48
  visitor.visit(self)
49
49
  end
50
50
  end
@@ -0,0 +1,68 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ module Rewriters
6
+ # This rewriter moves top-level members into a top-level Object class
7
+ #
8
+ # Example:
9
+ # ~~~rb
10
+ # def foo; end
11
+ # attr_reader :bar
12
+ # ~~~
13
+ #
14
+ # will be rewritten to:
15
+ #
16
+ # ~~~rb
17
+ # class Object
18
+ # def foo; end
19
+ # attr_reader :bar
20
+ # end
21
+ # ~~~
22
+ class NestTopLevelMembers < Visitor
23
+ extend T::Sig
24
+
25
+ sig { void }
26
+ def initialize
27
+ super
28
+
29
+ @top_level_object_class = T.let(nil, T.nilable(Class))
30
+ end
31
+
32
+ sig { override.params(node: T.nilable(Node)).void }
33
+ def visit(node)
34
+ return unless node
35
+
36
+ case node
37
+ when Tree
38
+ visit_all(node.nodes.dup)
39
+ else
40
+ scope = node.parent_scope
41
+ unless scope
42
+ parent = node.parent_tree
43
+ raise unless parent
44
+
45
+ node.detach
46
+
47
+ unless @top_level_object_class
48
+ @top_level_object_class = Class.new("Object")
49
+ parent.nodes << @top_level_object_class
50
+ end
51
+
52
+ @top_level_object_class << node
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ class Tree
60
+ extend T::Sig
61
+
62
+ sig { void }
63
+ def nest_top_level_members!
64
+ visitor = Rewriters::NestTopLevelMembers.new
65
+ visitor.visit(self)
66
+ end
67
+ end
68
+ end