@@ -15,6 +15,9 @@ public struct CompatibilityLayer {
1515 /// Deprecated members that the compatibility layer needs for each node.
1616 private var deprecatedMembersByNode : [ SyntaxNodeKind : DeprecatedMemberInfo ] = [ : ]
1717
18+ /// Deprecated members that the compatibility layer needs for each trait.
19+ public var deprecatedMembersByTrait : [ String : DeprecatedMemberInfo ] = [ : ]
20+
1821 /// Cache for `replacementChild(for:)`. Ensures that we don't create
1922 /// two different replacement nodes even if we refactor the same child twice.
2023 private var cachedReplacementChildren : [ Child : [ Child ] ] = [ : ]
@@ -24,11 +27,19 @@ public struct CompatibilityLayer {
2427 return deprecatedMembersByNode [ node. kind] ?? DeprecatedMemberInfo ( )
2528 }
2629
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 ] ) {
2836 // Note that we compute these up-front, greedily, so that all of the mutation is isolated by the lazy var's state.
2937 for node in nodes {
3038 computeMembers ( for: node)
3139 }
40+ for trait in traits {
41+ computeMembers ( for: trait)
42+ }
3243 }
3344
3445 /// Returns the child or children that would have existed in place of this
@@ -77,22 +88,54 @@ public struct CompatibilityLayer {
7788 return
7889 }
7990
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 {
80123 // The results that will ultimately be saved into the DeprecatedMemberInfo.
81124 var vars : [ Child ] = [ ]
82125 var initSignatures : [ InitSignature ] = [ ]
83126
84127 // Temporary working state for the loop.
85- var children = layoutNode . children
128+ var children = initialChildren
86129 var knownVars = Set ( children)
87130
88131 func firstIndexOfChild( named targetName: String ) -> Int {
89132 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) ) ) " )
91134 }
92135 return i
93136 }
94137
95- for changeSet in layoutNode . childHistory {
138+ for changeSet in history {
96139 var unexpectedChildrenWithNewNames : Set < Child > = [ ]
97140
98141 // First pass: Apply the changes explicitly specified in the change set.
@@ -102,12 +145,14 @@ public struct CompatibilityLayer {
102145 let replacementChildren = replacementChildren ( for: children [ i] , by: refactoring)
103146 children. replaceSubrange ( i... i, with: replacementChildren)
104147
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+ }
111156 }
112157 }
113158
@@ -130,10 +175,13 @@ public struct CompatibilityLayer {
130175 // 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.
131176 vars += children. filter { knownVars. insert ( $0) . inserted }
132177
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+ }
134182 }
135183
136- deprecatedMembersByNode [ node . syntaxNodeKind ] = DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
184+ return DeprecatedMemberInfo ( vars: vars, inits: initSignatures)
137185 }
138186}
139187
0 commit comments