@@ -15,6 +15,9 @@ public struct CompatibilityLayer {
15
15
/// Deprecated members that the compatibility layer needs for each node.
16
16
private var deprecatedMembersByNode : [ SyntaxNodeKind : DeprecatedMemberInfo ] = [ : ]
17
17
18
+ /// Deprecated members that the compatibility layer needs for each trait.
19
+ public var deprecatedMembersByTrait : [ String : DeprecatedMemberInfo ] = [ : ]
20
+
18
21
/// Cache for `replacementChild(for:)`. Ensures that we don't create
19
22
/// two different replacement nodes even if we refactor the same child twice.
20
23
private var cachedReplacementChildren : [ Child : [ Child ] ] = [ : ]
@@ -24,11 +27,19 @@ public struct CompatibilityLayer {
24
27
return deprecatedMembersByNode [ node. kind] ?? DeprecatedMemberInfo ( )
25
28
}
26
29
27
- internal init ( nodes: [ Node ] ) {
30
+ /// Returns the deprecated members that the compatibility layer needs for `trait`.
31
+ public func deprecatedMembers( for trait: Trait ) -> DeprecatedMemberInfo {
32
+ return deprecatedMembersByTrait [ trait. traitName] ?? DeprecatedMemberInfo ( )
33
+ }
34
+
35
+ internal init ( nodes: [ Node ] , traits: [ Trait ] ) {
28
36
// Note that we compute these up-front, greedily, so that all of the mutation is isolated by the lazy var's state.
29
37
for node in nodes {
30
38
computeMembers ( for: node)
31
39
}
40
+ for trait in traits {
41
+ computeMembers ( for: trait)
42
+ }
32
43
}
33
44
34
45
/// Returns the child or children that would have existed in place of this
@@ -77,22 +88,54 @@ public struct CompatibilityLayer {
77
88
return
78
89
}
79
90
91
+ let result = computeMembersFor (
92
+ typeName: layoutNode. kind. rawValue,
93
+ initialChildren: layoutNode. children,
94
+ history: layoutNode. childHistory,
95
+ areRequirements: false
96
+ )
97
+
98
+ deprecatedMembersByNode [ node. syntaxNodeKind] = result
99
+ }
100
+
101
+ private mutating func computeMembers( for trait: Trait ) {
102
+ guard deprecatedMembersByTrait [ trait. traitName] == nil else {
103
+ return
104
+ }
105
+
106
+ let result = computeMembersFor (
107
+ typeName: trait. traitName,
108
+ initialChildren: trait. children,
109
+ history: trait. childHistory,
110
+ areRequirements: true
111
+ )
112
+
113
+ deprecatedMembersByTrait [ trait. traitName] = result
114
+ }
115
+
116
+ /// Compute and cache compatibility layer information for the given children.
117
+ private mutating func computeMembersFor(
118
+ typeName: String ,
119
+ initialChildren: [ Child ] ,
120
+ history: Child . History ,
121
+ areRequirements: Bool
122
+ ) -> DeprecatedMemberInfo {
80
123
// The results that will ultimately be saved into the DeprecatedMemberInfo.
81
124
var vars : [ Child ] = [ ]
82
125
var initSignatures : [ InitSignature ] = [ ]
83
126
84
127
// Temporary working state for the loop.
85
- var children = layoutNode . children
128
+ var children = initialChildren
86
129
var knownVars = Set ( children)
87
130
88
131
func firstIndexOfChild( named targetName: String ) -> Int {
89
132
guard let i = children. firstIndex ( where: { $0. name == targetName } ) else {
90
- fatalError ( " couldn't find ' \( targetName) ' in current children of \( node . syntaxNodeKind . rawValue ) : \( String ( reflecting: children. map ( \. name) ) ) " )
133
+ fatalError ( " couldn't find ' \( targetName) ' in current children of \( typeName ) : \( String ( reflecting: children. map ( \. name) ) ) " )
91
134
}
92
135
return i
93
136
}
94
137
95
- for changeSet in layoutNode . childHistory {
138
+ for changeSet in history {
96
139
var unexpectedChildrenWithNewNames : Set < Child > = [ ]
97
140
98
141
// First pass: Apply the changes explicitly specified in the change set.
@@ -102,12 +145,14 @@ public struct CompatibilityLayer {
102
145
let replacementChildren = replacementChildren ( for: children [ i] , by: refactoring)
103
146
children. replaceSubrange ( i... i, with: replacementChildren)
104
147
105
- // Mark adjacent unexpected node children whose names have changed too.
106
- if currentName != replacementChildren. first? . name {
107
- unexpectedChildrenWithNewNames. insert ( children [ i - 1 ] )
108
- }
109
- if currentName != replacementChildren. last? . name {
110
- unexpectedChildrenWithNewNames. insert ( children [ i + replacementChildren. count] )
148
+ if !areRequirements {
149
+ // Mark adjacent unexpected node children whose names have changed too.
150
+ if currentName != replacementChildren. first? . name {
151
+ unexpectedChildrenWithNewNames. insert ( children [ i - 1 ] )
152
+ }
153
+ if currentName != replacementChildren. last? . name {
154
+ unexpectedChildrenWithNewNames. insert ( children [ i + replacementChildren. count] )
155
+ }
111
156
}
112
157
}
113
158
@@ -130,10 +175,13 @@ public struct CompatibilityLayer {
130
175
// Third pass: Append newly-created children to vars. We do this now so that changes from the first two passes are properly interleaved, preserving source order.
131
176
vars += children. filter { knownVars. insert ( $0) . inserted }
132
177
133
- initSignatures. append ( InitSignature ( children: children) )
178
+ // We don't create compatibility layers for protocol requirement inits.
179
+ if !areRequirements {
180
+ initSignatures. append ( InitSignature ( children: children) )
181
+ }
134
182
}
135
183
136
- deprecatedMembersByNode [ node . syntaxNodeKind ] = DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
184
+ return DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
137
185
}
138
186
}
139
187
0 commit comments