@@ -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 `replacementChildren(for:by:)`. Ensures that we don't create two different replacement children even
19
22
/// if we refactor the same child twice, so we can reliably equate and hash `Child` objects by object identity.
20
23
private var cachedReplacementChildren : [ Child : [ Child ] ] = [ : ]
@@ -24,13 +27,21 @@ 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
// This instance will be stored in a global that's used from multiple threads simultaneously, so it won't be safe
29
37
// to mutate once the initializer returns. We therefore do all the work to populate its tables up front, rather
30
38
// than computing it lazily on demand.
31
39
for node in nodes {
32
40
computeMembers ( for: node)
33
41
}
42
+ for trait in traits {
43
+ computeMembers ( for: trait)
44
+ }
34
45
}
35
46
36
47
/// Returns the child or children that would have existed in place of this
@@ -79,24 +90,56 @@ public struct CompatibilityLayer {
79
90
return
80
91
}
81
92
93
+ let result = computeMembersFor (
94
+ typeName: layoutNode. kind. rawValue,
95
+ initialChildren: layoutNode. children,
96
+ history: layoutNode. childHistory,
97
+ areRequirements: false
98
+ )
99
+
100
+ deprecatedMembersByNode [ node. syntaxNodeKind] = result
101
+ }
102
+
103
+ private mutating func computeMembers( for trait: Trait ) {
104
+ guard deprecatedMembersByTrait [ trait. traitName] == nil else {
105
+ return
106
+ }
107
+
108
+ let result = computeMembersFor (
109
+ typeName: trait. traitName,
110
+ initialChildren: trait. children,
111
+ history: trait. childHistory,
112
+ areRequirements: true
113
+ )
114
+
115
+ deprecatedMembersByTrait [ trait. traitName] = result
116
+ }
117
+
118
+ /// Compute and cache compatibility layer information for the given children.
119
+ private mutating func computeMembersFor(
120
+ typeName: String ,
121
+ initialChildren: [ Child ] ,
122
+ history: Child . History ,
123
+ areRequirements: Bool
124
+ ) -> DeprecatedMemberInfo {
82
125
// The results that will ultimately be saved into the DeprecatedMemberInfo.
83
126
var vars : [ Child ] = [ ]
84
127
var initSignatures : [ InitSignature ] = [ ]
85
128
86
129
// Temporary working state for the loop.
87
- var children = layoutNode . children
130
+ var children = initialChildren
88
131
var knownVars = Set ( children)
89
132
90
133
func firstIndexOfChild( named targetName: String ) -> Int {
91
134
guard let i = children. firstIndex ( where: { $0. name == targetName } ) else {
92
135
fatalError (
93
- " couldn't find ' \( targetName) ' in current children of \( node . syntaxNodeKind . rawValue ) : \( String ( reflecting: children. map ( \. name) ) ) "
136
+ " couldn't find ' \( targetName) ' in current children of \( typeName ) : \( String ( reflecting: children. map ( \. name) ) ) "
94
137
)
95
138
}
96
139
return i
97
140
}
98
141
99
- for changeSet in layoutNode . childHistory {
142
+ for changeSet in history {
100
143
var unexpectedChildrenWithNewNames : Set < Child > = [ ]
101
144
102
145
// First pass: Apply the changes explicitly specified in the change set.
@@ -106,12 +149,14 @@ public struct CompatibilityLayer {
106
149
let replacementChildren = replacementChildren ( for: children [ i] , by: refactoring)
107
150
children. replaceSubrange ( i... i, with: replacementChildren)
108
151
109
- // Mark adjacent unexpected node children whose names have changed too.
110
- if currentName != replacementChildren. first? . name {
111
- unexpectedChildrenWithNewNames. insert ( children [ i - 1 ] )
112
- }
113
- if currentName != replacementChildren. last? . name {
114
- unexpectedChildrenWithNewNames. insert ( children [ i + replacementChildren. count] )
152
+ if !areRequirements {
153
+ // Mark adjacent unexpected node children whose names have changed too.
154
+ if currentName != replacementChildren. first? . name {
155
+ unexpectedChildrenWithNewNames. insert ( children [ i - 1 ] )
156
+ }
157
+ if currentName != replacementChildren. last? . name {
158
+ unexpectedChildrenWithNewNames. insert ( children [ i + replacementChildren. count] )
159
+ }
115
160
}
116
161
}
117
162
@@ -134,10 +179,13 @@ public struct CompatibilityLayer {
134
179
// 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.
135
180
vars += children. filter { knownVars. insert ( $0) . inserted }
136
181
137
- initSignatures. append ( InitSignature ( children: children) )
182
+ // We don't create compatibility layers for protocol requirement inits.
183
+ if !areRequirements {
184
+ initSignatures. append ( InitSignature ( children: children) )
185
+ }
138
186
}
139
187
140
- deprecatedMembersByNode [ node . syntaxNodeKind ] = DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
188
+ return DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
141
189
}
142
190
}
143
191
0 commit comments