rbi 0.0.1 → 0.0.2
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/Gemfile +8 -5
- data/README.md +38 -10
- data/Rakefile +2 -0
- data/lib/rbi.rb +16 -5
- data/lib/rbi/index.rb +186 -0
- data/lib/rbi/loc.rb +36 -0
- data/lib/rbi/model.rb +879 -0
- data/lib/rbi/parser.rb +449 -0
- data/lib/rbi/printer.rb +643 -0
- data/lib/rbi/rewriters/group_nodes.rb +104 -0
- data/lib/rbi/rewriters/merge_trees.rb +587 -0
- data/lib/rbi/rewriters/nest_non_public_methods.rb +63 -0
- data/lib/rbi/rewriters/nest_singleton_methods.rb +40 -0
- data/lib/rbi/rewriters/sort_nodes.rb +84 -0
- data/lib/rbi/version.rb +5 -1
- data/lib/rbi/visitor.rb +19 -0
- metadata +36 -56
- data/exe/rbi +0 -7
- data/lib/rbi/cli.rb +0 -19
@@ -0,0 +1,104 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RBI
|
5
|
+
module Rewriters
|
6
|
+
class GroupNodes < Visitor
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { override.params(node: T.nilable(Node)).void }
|
10
|
+
def visit(node)
|
11
|
+
return unless node
|
12
|
+
|
13
|
+
case node
|
14
|
+
when Tree
|
15
|
+
kinds = node.nodes.map(&:group_kind)
|
16
|
+
kinds.compact!
|
17
|
+
kinds.uniq!
|
18
|
+
|
19
|
+
groups = {}
|
20
|
+
kinds.each { |kind| groups[kind] = Group.new(kind) }
|
21
|
+
|
22
|
+
node.nodes.dup.each do |child|
|
23
|
+
visit(child)
|
24
|
+
child.detach
|
25
|
+
groups[child.group_kind] << child
|
26
|
+
end
|
27
|
+
|
28
|
+
groups.each { |_, group| node << group }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Tree
|
35
|
+
extend T::Sig
|
36
|
+
|
37
|
+
sig { void }
|
38
|
+
def group_nodes!
|
39
|
+
visitor = Rewriters::GroupNodes.new
|
40
|
+
visitor.visit(self)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Node
|
45
|
+
extend T::Sig
|
46
|
+
|
47
|
+
sig { returns(Group::Kind) }
|
48
|
+
def group_kind
|
49
|
+
case self
|
50
|
+
when Include, Extend
|
51
|
+
Group::Kind::Mixins
|
52
|
+
when Helper
|
53
|
+
Group::Kind::Helpers
|
54
|
+
when TypeMember
|
55
|
+
Group::Kind::TypeMembers
|
56
|
+
when MixesInClassMethods
|
57
|
+
Group::Kind::MixesInClassMethods
|
58
|
+
when TStructField
|
59
|
+
Group::Kind::TStructFields
|
60
|
+
when TEnumBlock
|
61
|
+
Group::Kind::TEnums
|
62
|
+
when VisibilityGroup
|
63
|
+
Group::Kind::Methods
|
64
|
+
when Method
|
65
|
+
if name == "initialize"
|
66
|
+
Group::Kind::Inits
|
67
|
+
else
|
68
|
+
Group::Kind::Methods
|
69
|
+
end
|
70
|
+
when Scope, Const
|
71
|
+
Group::Kind::Consts
|
72
|
+
else
|
73
|
+
raise "Unknown group for #{self}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Group < Tree
|
79
|
+
extend T::Sig
|
80
|
+
|
81
|
+
sig { returns(Kind) }
|
82
|
+
attr_reader :kind
|
83
|
+
|
84
|
+
sig { params(kind: Kind).void }
|
85
|
+
def initialize(kind)
|
86
|
+
super()
|
87
|
+
@kind = kind
|
88
|
+
end
|
89
|
+
|
90
|
+
class Kind < T::Enum
|
91
|
+
enums do
|
92
|
+
Mixins = new
|
93
|
+
Helpers = new
|
94
|
+
TypeMembers = new
|
95
|
+
MixesInClassMethods = new
|
96
|
+
TStructFields = new
|
97
|
+
TEnums = new
|
98
|
+
Inits = new
|
99
|
+
Methods = new
|
100
|
+
Consts = new
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,587 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RBI
|
5
|
+
module Rewriters
|
6
|
+
# Merge two RBI trees together
|
7
|
+
#
|
8
|
+
# Be this `Tree`:
|
9
|
+
# ~~~rb
|
10
|
+
# class Foo
|
11
|
+
# attr_accessor :a
|
12
|
+
# def m; end
|
13
|
+
# C = 10
|
14
|
+
# end
|
15
|
+
# ~~~
|
16
|
+
#
|
17
|
+
# Merged with this one:
|
18
|
+
# ~~~rb
|
19
|
+
# class Foo
|
20
|
+
# attr_reader :a
|
21
|
+
# def m(x); end
|
22
|
+
# C = 10
|
23
|
+
# end
|
24
|
+
# ~~~
|
25
|
+
#
|
26
|
+
# Compatible definitions are merged together while incompatible definitions are moved into a `ConflictTree`:
|
27
|
+
# ~~~rb
|
28
|
+
# class Foo
|
29
|
+
# <<<<<<< left
|
30
|
+
# attr_accessor :a
|
31
|
+
# def m; end
|
32
|
+
# =======
|
33
|
+
# attr_reader :a
|
34
|
+
# def m(x); end
|
35
|
+
# >>>>>>> right
|
36
|
+
# C = 10
|
37
|
+
# end
|
38
|
+
# ~~~
|
39
|
+
class Merge
|
40
|
+
extend T::Sig
|
41
|
+
|
42
|
+
sig { params(left: Tree, right: Tree, left_name: String, right_name: String).returns(Tree) }
|
43
|
+
def self.merge_trees(left, right, left_name: "left", right_name: "right")
|
44
|
+
rewriter = Rewriters::Merge.new(left_name: left_name, right_name: right_name)
|
45
|
+
rewriter.merge(left)
|
46
|
+
rewriter.merge(right)
|
47
|
+
tree = rewriter.tree
|
48
|
+
ConflictTreeMerger.new.visit(tree)
|
49
|
+
tree
|
50
|
+
end
|
51
|
+
|
52
|
+
sig { returns(Tree) }
|
53
|
+
attr_reader :tree
|
54
|
+
|
55
|
+
sig { params(left_name: String, right_name: String).void }
|
56
|
+
def initialize(left_name: "left", right_name: "right")
|
57
|
+
@left_name = left_name
|
58
|
+
@right_name = right_name
|
59
|
+
@tree = T.let(Tree.new, Tree)
|
60
|
+
@scope_stack = T.let([@tree], T::Array[Tree])
|
61
|
+
end
|
62
|
+
|
63
|
+
sig { params(tree: Tree).returns(T::Array[Conflict]) }
|
64
|
+
def merge(tree)
|
65
|
+
v = TreeMerger.new(@tree, left_name: @left_name, right_name: @right_name)
|
66
|
+
v.visit(tree)
|
67
|
+
v.conflicts
|
68
|
+
end
|
69
|
+
|
70
|
+
# Used for logging / error displaying purpose
|
71
|
+
class Conflict < T::Struct
|
72
|
+
extend T::Sig
|
73
|
+
|
74
|
+
const :left, Node
|
75
|
+
const :right, Node
|
76
|
+
const :left_name, String
|
77
|
+
const :right_name, String
|
78
|
+
|
79
|
+
sig { returns(String) }
|
80
|
+
def to_s
|
81
|
+
"Conflicting definitions for `#{left}`"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class TreeMerger < Visitor
|
86
|
+
extend T::Sig
|
87
|
+
|
88
|
+
sig { returns(T::Array[Conflict]) }
|
89
|
+
attr_reader :conflicts
|
90
|
+
|
91
|
+
sig { params(output: Tree, left_name: String, right_name: String).void }
|
92
|
+
def initialize(output, left_name: "left", right_name: "right")
|
93
|
+
super()
|
94
|
+
@tree = output
|
95
|
+
@index = T.let(output.index, Index)
|
96
|
+
@scope_stack = T.let([@tree], T::Array[Tree])
|
97
|
+
@left_name = left_name
|
98
|
+
@right_name = right_name
|
99
|
+
@conflicts = T.let([], T::Array[Conflict])
|
100
|
+
end
|
101
|
+
|
102
|
+
sig { override.params(node: T.nilable(Node)).void }
|
103
|
+
def visit(node)
|
104
|
+
return unless node
|
105
|
+
|
106
|
+
case node
|
107
|
+
when Scope
|
108
|
+
prev = previous_definition(node)
|
109
|
+
|
110
|
+
if prev.is_a?(Scope)
|
111
|
+
if node.compatible_with?(prev)
|
112
|
+
prev.merge_with(node)
|
113
|
+
else
|
114
|
+
make_conflict_scope(prev, node)
|
115
|
+
end
|
116
|
+
@scope_stack << prev
|
117
|
+
else
|
118
|
+
copy = node.dup_empty
|
119
|
+
current_scope << copy
|
120
|
+
@scope_stack << copy
|
121
|
+
end
|
122
|
+
visit_all(node.nodes)
|
123
|
+
@scope_stack.pop
|
124
|
+
when Tree
|
125
|
+
current_scope.merge_with(node)
|
126
|
+
visit_all(node.nodes)
|
127
|
+
when Indexable
|
128
|
+
prev = previous_definition(node)
|
129
|
+
if prev
|
130
|
+
if node.compatible_with?(prev)
|
131
|
+
prev.merge_with(node)
|
132
|
+
else
|
133
|
+
make_conflict_tree(prev, node)
|
134
|
+
end
|
135
|
+
else
|
136
|
+
current_scope << node.dup
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
sig { returns(Tree) }
|
144
|
+
def current_scope
|
145
|
+
T.must(@scope_stack.last)
|
146
|
+
end
|
147
|
+
|
148
|
+
sig { params(node: Node).returns(T.nilable(Node)) }
|
149
|
+
def previous_definition(node)
|
150
|
+
case node
|
151
|
+
when Indexable
|
152
|
+
node.index_ids.each do |id|
|
153
|
+
others = @index[id]
|
154
|
+
return others.last unless others.empty?
|
155
|
+
end
|
156
|
+
end
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
sig { params(left: Scope, right: Scope).void }
|
161
|
+
def make_conflict_scope(left, right)
|
162
|
+
@conflicts << Conflict.new(left: left, right: right, left_name: @left_name, right_name: @right_name)
|
163
|
+
scope_conflict = ScopeConflict.new(left: left, right: right, left_name: @left_name, right_name: @right_name)
|
164
|
+
left.replace(scope_conflict)
|
165
|
+
end
|
166
|
+
|
167
|
+
sig { params(left: Node, right: Node).void }
|
168
|
+
def make_conflict_tree(left, right)
|
169
|
+
@conflicts << Conflict.new(left: left, right: right, left_name: @left_name, right_name: @right_name)
|
170
|
+
tree = left.parent_conflict_tree
|
171
|
+
unless tree
|
172
|
+
tree = ConflictTree.new(left_name: @left_name, right_name: @right_name)
|
173
|
+
left.replace(tree)
|
174
|
+
tree.left << left
|
175
|
+
end
|
176
|
+
tree.right << right
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Merge adjacent conflict trees
|
181
|
+
#
|
182
|
+
# Transform this:
|
183
|
+
# ~~~rb
|
184
|
+
# class Foo
|
185
|
+
# <<<<<<< left
|
186
|
+
# def m1; end
|
187
|
+
# =======
|
188
|
+
# def m1(a); end
|
189
|
+
# >>>>>>> right
|
190
|
+
# <<<<<<< left
|
191
|
+
# def m2(a); end
|
192
|
+
# =======
|
193
|
+
# def m2; end
|
194
|
+
# >>>>>>> right
|
195
|
+
# end
|
196
|
+
# ~~~
|
197
|
+
#
|
198
|
+
# Into this:
|
199
|
+
# ~~~rb
|
200
|
+
# class Foo
|
201
|
+
# <<<<<<< left
|
202
|
+
# def m1; end
|
203
|
+
# def m2(a); end
|
204
|
+
# =======
|
205
|
+
# def m1(a); end
|
206
|
+
# def m2; end
|
207
|
+
# >>>>>>> right
|
208
|
+
# end
|
209
|
+
# ~~~
|
210
|
+
class ConflictTreeMerger < Visitor
|
211
|
+
sig { override.params(node: T.nilable(Node)).void }
|
212
|
+
def visit(node)
|
213
|
+
visit_all(node.nodes) if node.is_a?(Tree)
|
214
|
+
end
|
215
|
+
|
216
|
+
sig { override.params(nodes: T::Array[Node]).void }
|
217
|
+
def visit_all(nodes)
|
218
|
+
last_conflict_tree = T.let(nil, T.nilable(ConflictTree))
|
219
|
+
nodes.dup.each do |node|
|
220
|
+
if node.is_a?(ConflictTree)
|
221
|
+
if last_conflict_tree
|
222
|
+
merge_conflict_trees(last_conflict_tree.left, node.left)
|
223
|
+
merge_conflict_trees(last_conflict_tree.right, node.right)
|
224
|
+
node.detach
|
225
|
+
next
|
226
|
+
else
|
227
|
+
last_conflict_tree = node
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
visit(node)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
sig { params(left: Tree, right: Tree).void }
|
238
|
+
def merge_conflict_trees(left, right)
|
239
|
+
right.nodes.dup.each do |node|
|
240
|
+
left << node
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class Node
|
248
|
+
extend T::Sig
|
249
|
+
|
250
|
+
# Can `self` and `_other` be merged into a single definition?
|
251
|
+
sig { params(_other: Node).returns(T::Boolean) }
|
252
|
+
def compatible_with?(_other)
|
253
|
+
true
|
254
|
+
end
|
255
|
+
|
256
|
+
# Merge `self` and `other` into a single definition
|
257
|
+
sig { params(other: Node).void }
|
258
|
+
def merge_with(other); end
|
259
|
+
|
260
|
+
sig { returns(T.nilable(ConflictTree)) }
|
261
|
+
def parent_conflict_tree
|
262
|
+
parent = T.let(parent_tree, T.nilable(Node))
|
263
|
+
while parent
|
264
|
+
return parent if parent.is_a?(ConflictTree)
|
265
|
+
parent = parent.parent_tree
|
266
|
+
end
|
267
|
+
nil
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
class NodeWithComments
|
272
|
+
extend T::Sig
|
273
|
+
|
274
|
+
sig { override.params(other: Node).void }
|
275
|
+
def merge_with(other)
|
276
|
+
return unless other.is_a?(NodeWithComments)
|
277
|
+
other.comments.each do |comment|
|
278
|
+
comments << comment unless comments.include?(comment)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class Tree
|
284
|
+
extend T::Sig
|
285
|
+
|
286
|
+
sig { params(other: Tree).returns(Tree) }
|
287
|
+
def merge(other)
|
288
|
+
Rewriters::Merge.merge_trees(self, other)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class Scope
|
293
|
+
extend T::Sig
|
294
|
+
|
295
|
+
# Duplicate `self` scope without its body
|
296
|
+
sig { returns(T.self_type) }
|
297
|
+
def dup_empty
|
298
|
+
case self
|
299
|
+
when Module
|
300
|
+
Module.new(name, loc: loc, comments: comments)
|
301
|
+
when Class
|
302
|
+
Class.new(name, superclass_name: superclass_name, loc: loc, comments: comments)
|
303
|
+
when SingletonClass
|
304
|
+
SingletonClass.new(loc: loc, comments: comments)
|
305
|
+
else
|
306
|
+
raise "Can't duplicate node #{self}"
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
class Class
|
312
|
+
extend T::Sig
|
313
|
+
|
314
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
315
|
+
def compatible_with?(other)
|
316
|
+
other.is_a?(Class) && superclass_name == other.superclass_name
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class Module
|
321
|
+
extend T::Sig
|
322
|
+
|
323
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
324
|
+
def compatible_with?(other)
|
325
|
+
other.is_a?(Module)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
class Const
|
330
|
+
extend T::Sig
|
331
|
+
|
332
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
333
|
+
def compatible_with?(other)
|
334
|
+
other.is_a?(Const) && name == other.name && value == other.value
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
class Attr
|
339
|
+
extend T::Sig
|
340
|
+
|
341
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
342
|
+
def compatible_with?(other)
|
343
|
+
return false unless other.is_a?(Attr)
|
344
|
+
return false unless names == other.names
|
345
|
+
sigs.empty? || other.sigs.empty? || sigs == other.sigs
|
346
|
+
end
|
347
|
+
|
348
|
+
sig { override.params(other: Node).void }
|
349
|
+
def merge_with(other)
|
350
|
+
return unless other.is_a?(Attr)
|
351
|
+
super
|
352
|
+
other.sigs.each do |sig|
|
353
|
+
sigs << sig unless sigs.include?(sig)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
class AttrReader
|
359
|
+
extend T::Sig
|
360
|
+
|
361
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
362
|
+
def compatible_with?(other)
|
363
|
+
other.is_a?(AttrReader) && super
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
class AttrWriter
|
368
|
+
extend T::Sig
|
369
|
+
|
370
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
371
|
+
def compatible_with?(other)
|
372
|
+
other.is_a?(AttrWriter) && super
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
class AttrAccessor
|
377
|
+
extend T::Sig
|
378
|
+
|
379
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
380
|
+
def compatible_with?(other)
|
381
|
+
other.is_a?(AttrAccessor) && super
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
class Method
|
386
|
+
extend T::Sig
|
387
|
+
|
388
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
389
|
+
def compatible_with?(other)
|
390
|
+
return false unless other.is_a?(Method)
|
391
|
+
return false unless name == other.name
|
392
|
+
return false unless params == other.params
|
393
|
+
sigs.empty? || other.sigs.empty? || sigs == other.sigs
|
394
|
+
end
|
395
|
+
|
396
|
+
sig { override.params(other: Node).void }
|
397
|
+
def merge_with(other)
|
398
|
+
return unless other.is_a?(Method)
|
399
|
+
super
|
400
|
+
other.sigs.each do |sig|
|
401
|
+
sigs << sig unless sigs.include?(sig)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
class Mixin
|
407
|
+
extend T::Sig
|
408
|
+
|
409
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
410
|
+
def compatible_with?(other)
|
411
|
+
other.is_a?(Mixin) && names == other.names
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
class Include
|
416
|
+
extend T::Sig
|
417
|
+
|
418
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
419
|
+
def compatible_with?(other)
|
420
|
+
other.is_a?(Include) && super
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
class Extend
|
425
|
+
extend T::Sig
|
426
|
+
|
427
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
428
|
+
def compatible_with?(other)
|
429
|
+
other.is_a?(Extend) && super
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
class MixesInClassMethods
|
434
|
+
extend T::Sig
|
435
|
+
|
436
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
437
|
+
def compatible_with?(other)
|
438
|
+
other.is_a?(MixesInClassMethods) && super
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
class Helper
|
443
|
+
extend T::Sig
|
444
|
+
|
445
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
446
|
+
def compatible_with?(other)
|
447
|
+
other.is_a?(Helper) && name == other.name
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
class TStructField
|
452
|
+
extend T::Sig
|
453
|
+
|
454
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
455
|
+
def compatible_with?(other)
|
456
|
+
other.is_a?(TStructField) && name == other.name && type == other.type && default == other.default
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
class TStructConst
|
461
|
+
extend T::Sig
|
462
|
+
|
463
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
464
|
+
def compatible_with?(other)
|
465
|
+
other.is_a?(TStructConst) && super
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
class TEnumBlock
|
470
|
+
extend T::Sig
|
471
|
+
|
472
|
+
sig { override.params(other: Node).void }
|
473
|
+
def merge_with(other)
|
474
|
+
return unless other.is_a?(TEnumBlock)
|
475
|
+
super
|
476
|
+
other.names.each do |name|
|
477
|
+
names << name unless names.include?(name)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
class TStructProp
|
483
|
+
extend T::Sig
|
484
|
+
|
485
|
+
sig { override.params(other: Node).returns(T::Boolean) }
|
486
|
+
def compatible_with?(other)
|
487
|
+
other.is_a?(TStructProp) && super
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# A tree showing incompatibles nodes
|
492
|
+
#
|
493
|
+
# Is rendered as a merge conflict between `left` and` right`:
|
494
|
+
# ~~~rb
|
495
|
+
# class Foo
|
496
|
+
# <<<<<<< left
|
497
|
+
# def m1; end
|
498
|
+
# def m2(a); end
|
499
|
+
# =======
|
500
|
+
# def m1(a); end
|
501
|
+
# def m2; end
|
502
|
+
# >>>>>>> right
|
503
|
+
# end
|
504
|
+
# ~~~
|
505
|
+
class ConflictTree < Tree
|
506
|
+
extend T::Sig
|
507
|
+
|
508
|
+
sig { returns(Tree) }
|
509
|
+
attr_reader :left, :right
|
510
|
+
|
511
|
+
sig { params(left_name: String, right_name: String).void }
|
512
|
+
def initialize(left_name: "left", right_name: "right")
|
513
|
+
super()
|
514
|
+
@left_name = left_name
|
515
|
+
@right_name = right_name
|
516
|
+
@left = T.let(Tree.new, Tree)
|
517
|
+
@left.parent_tree = self
|
518
|
+
@right = T.let(Tree.new, Tree)
|
519
|
+
@right.parent_tree = self
|
520
|
+
end
|
521
|
+
|
522
|
+
sig { override.params(v: Printer).void }
|
523
|
+
def accept_printer(v)
|
524
|
+
v.printl("<<<<<<< #{@left_name}")
|
525
|
+
v.visit(left)
|
526
|
+
v.printl("=======")
|
527
|
+
v.visit(right)
|
528
|
+
v.printl(">>>>>>> #{@right_name}")
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
# A conflict between two scope headers
|
533
|
+
#
|
534
|
+
# Is rendered as a merge conflict between `left` and` right` for scope definitions:
|
535
|
+
# ~~~rb
|
536
|
+
# <<<<<<< left
|
537
|
+
# class Foo
|
538
|
+
# =======
|
539
|
+
# module Foo
|
540
|
+
# >>>>>>> right
|
541
|
+
# def m1; end
|
542
|
+
# end
|
543
|
+
# ~~~
|
544
|
+
class ScopeConflict < Tree
|
545
|
+
extend T::Sig
|
546
|
+
|
547
|
+
sig { returns(Scope) }
|
548
|
+
attr_reader :left, :right
|
549
|
+
|
550
|
+
sig do
|
551
|
+
params(
|
552
|
+
left: Scope,
|
553
|
+
right: Scope,
|
554
|
+
left_name: String,
|
555
|
+
right_name: String
|
556
|
+
).void
|
557
|
+
end
|
558
|
+
def initialize(left:, right:, left_name: "left", right_name: "right")
|
559
|
+
super()
|
560
|
+
@left = left
|
561
|
+
@right = right
|
562
|
+
@left_name = left_name
|
563
|
+
@right_name = right_name
|
564
|
+
end
|
565
|
+
|
566
|
+
sig { override.params(v: Printer).void }
|
567
|
+
def accept_printer(v)
|
568
|
+
previous_node = v.previous_node
|
569
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
570
|
+
|
571
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
572
|
+
v.visit_all(comments)
|
573
|
+
|
574
|
+
v.printl("<<<<<<< #{@left_name}")
|
575
|
+
left.print_header(v)
|
576
|
+
v.printl("=======")
|
577
|
+
right.print_header(v)
|
578
|
+
v.printl(">>>>>>> #{@right_name}")
|
579
|
+
left.print_body(v)
|
580
|
+
end
|
581
|
+
|
582
|
+
sig { override.returns(T::Boolean) }
|
583
|
+
def oneline?
|
584
|
+
left.oneline?
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|