Skip to content

Commit db41e13

Browse files
authored
Track value locations in XCConfigs per assignment (#552)
In #513, initial support for this was added, this PR moves the location to be per assignment which allows emitting fix its not just for the last seen assignments. This will also allow looking at any conditions of assignments when choosing the location for emitting fix its.
1 parent 50d4c9c commit db41e13

File tree

2 files changed

+43
-63
lines changed

2 files changed

+43
-63
lines changed

Sources/SWBMacro/MacroEvaluationScope.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ private extension MacroValueAssignmentTable {
1717
func lookupMacro(_ macro: MacroDeclaration, overrideLookup: ((MacroDeclaration) -> MacroExpression?)? = nil) -> MacroValueAssignment? {
1818
// See if we have an overriding binding.
1919
if let override = overrideLookup?(macro) {
20-
return MacroValueAssignment(expression: override, conditions: nil, next: lookupMacro(macro))
20+
return MacroValueAssignment(expression: override, conditions: nil, next: lookupMacro(macro), location: nil)
2121
}
2222

2323
// Otherwise, return the normal lookup.

Sources/SWBMacro/MacroValueAssignmentTable.swift

Lines changed: 42 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
public import SWBUtil
14+
import Synchronization
1415

1516
/// A mapping from macro declarations to corresponding macro value assignments, each of which is a linked list of macro expressions in precedence order. At the moment it doesn’t support conditional assignments, but that functionality will be implemented soon.
1617
public struct MacroValueAssignmentTable: Serializable, Sendable {
@@ -20,23 +21,18 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
2021
/// Maps macro declarations to corresponding linked lists of assignments.
2122
public var valueAssignments: [MacroDeclaration: MacroValueAssignment]
2223

23-
private var valueLocations: [String: InternedMacroValueAssignmentLocation]
24-
private var macroConfigPaths: OrderedSet<Path>
25-
26-
private init(namespace: MacroNamespace, valueAssignments: [MacroDeclaration: MacroValueAssignment], valueLocations: [String: InternedMacroValueAssignmentLocation], macroConfigPaths: OrderedSet<Path>) {
24+
private init(namespace: MacroNamespace, valueAssignments: [MacroDeclaration: MacroValueAssignment]) {
2725
self.namespace = namespace
2826
self.valueAssignments = valueAssignments
29-
self.valueLocations = valueLocations
30-
self.macroConfigPaths = macroConfigPaths
3127
}
3228

3329
public init(namespace: MacroNamespace) {
34-
self.init(namespace: namespace, valueAssignments: [:], valueLocations: [:], macroConfigPaths: OrderedSet())
30+
self.init(namespace: namespace, valueAssignments: [:])
3531
}
3632

3733
/// Convenience initializer to create a `MacroValueAssignmentTable` from another instance (i.e., to create a copy).
3834
public init(copying table: MacroValueAssignmentTable) {
39-
self.init(namespace: table.namespace, valueAssignments: table.valueAssignments, valueLocations: table.valueLocations, macroConfigPaths: table.macroConfigPaths)
35+
self.init(namespace: table.namespace, valueAssignments: table.valueAssignments)
4036
}
4137

4238
/// Remove all assignments for the given macro.
@@ -86,28 +82,14 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
8682
assert(namespace.lookupMacroDeclaration(macro.name) === macro)
8783
// Validate the type.
8884
assert(macro.type.matchesExpressionType(value))
89-
valueAssignments[macro] = MacroValueAssignment(expression: value, conditions: conditions, next: valueAssignments[macro])
90-
91-
if let location {
92-
let index = macroConfigPaths.append(location.path).index
93-
valueLocations[macro.name] = InternedMacroValueAssignmentLocation(pathRef: index, line: location.line, startColumn: location.startColumn, endColumn: location.endColumn)
94-
}
95-
}
96-
97-
private mutating func mergeLocations(from otherTable: MacroValueAssignmentTable) {
98-
otherTable.valueLocations.forEach {
99-
let path = otherTable.macroConfigPaths[$0.value.pathRef]
100-
let index = macroConfigPaths.append(path).index
101-
valueLocations[$0.key] = .init(pathRef: index, line: $0.value.line, startColumn: $0.value.startColumn, endColumn: $0.value.endColumn)
102-
}
85+
valueAssignments[macro] = MacroValueAssignment(expression: value, conditions: conditions, next: valueAssignments[macro], location: location)
10386
}
10487

10588
/// Adds a mapping from each of the macro-to-value mappings in `otherTable`, inserting them ahead of any already existing assignments in the receiving table. The other table isn’t affected in any way (in particular, no reference is kept from the receiver to the other table).
10689
public mutating func pushContentsOf(_ otherTable: MacroValueAssignmentTable) {
10790
for (macro, firstAssignment) in otherTable.valueAssignments {
10891
valueAssignments[macro] = insertCopiesOfMacroValueAssignmentNodes(firstAssignment, inFrontOf: valueAssignments[macro])
10992
}
110-
mergeLocations(from: otherTable)
11193
}
11294

11395
/// Looks up and returns the first (highest-precedence) macro value assignment for `macro`, if there is one.
@@ -126,15 +108,7 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
126108
}
127109

128110
public func location(of macro: MacroDeclaration) -> MacroValueAssignmentLocation? {
129-
guard let location = valueLocations[macro.name] else {
130-
return nil
131-
}
132-
return MacroValueAssignmentLocation(
133-
path: macroConfigPaths[location.pathRef],
134-
line: location.line,
135-
startColumn: location.startColumn,
136-
endColumn: location.endColumn
137-
)
111+
return lookupMacro(macro)?.location
138112
}
139113

140114
public func bindConditionParameter(_ parameter: MacroConditionParameter, _ conditionValues: [String]) -> MacroValueAssignmentTable {
@@ -223,7 +197,6 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
223197
bindAndPushAssignment(firstAssignment)
224198

225199
}
226-
table.mergeLocations(from: self)
227200
return table
228201
}
229202

@@ -251,7 +224,7 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
251224
// MARK: Serialization
252225

253226
public func serialize<T: Serializer>(to serializer: T) {
254-
serializer.beginAggregate(3)
227+
serializer.beginAggregate(1)
255228

256229
// We don't directly serialize MacroDeclarations, but rather serialize their contents "by hand" so when we deserialize we can re-use existing declarations in our namespace.
257230
serializer.beginAggregate(valueAssignments.count)
@@ -279,17 +252,6 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
279252
}
280253
serializer.endAggregate() // valueAssignments
281254

282-
serializer.beginAggregate(valueLocations.count)
283-
for (decl, loc) in valueLocations.sorted(by: { $0.0 < $1.0 }) {
284-
serializer.beginAggregate(2)
285-
serializer.serialize(decl)
286-
serializer.serialize(loc)
287-
serializer.endAggregate()
288-
}
289-
serializer.endAggregate()
290-
291-
serializer.serialize(macroConfigPaths)
292-
293255
serializer.endAggregate() // the whole table
294256
}
295257

@@ -298,10 +260,9 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
298260
guard let delegate = deserializer.delegate as? (any MacroValueAssignmentTableDeserializerDelegate) else { throw DeserializerError.invalidDelegate("delegate must be a MacroValueAssignmentTableDeserializerDelegate") }
299261
self.namespace = delegate.namespace
300262
self.valueAssignments = [:]
301-
self.valueLocations = [:]
302263

303264
// Deserialize the table.
304-
try deserializer.beginAggregate(3)
265+
try deserializer.beginAggregate(1)
305266

306267
// Iterate over all the key-value pairs.
307268
let count: Int = try deserializer.beginAggregate()
@@ -348,16 +309,6 @@ public struct MacroValueAssignmentTable: Serializable, Sendable {
348309
// Add it to the dictionary.
349310
self.valueAssignments[decl] = asgn
350311
}
351-
352-
let count2 = try deserializer.beginAggregate()
353-
for _ in 0..<count2 {
354-
try deserializer.beginAggregate(2)
355-
let name: String = try deserializer.deserialize()
356-
let location: InternedMacroValueAssignmentLocation = try deserializer.deserialize()
357-
self.valueLocations[name] = location
358-
}
359-
360-
self.macroConfigPaths = try deserializer.deserialize()
361312
}
362313
}
363314

@@ -379,11 +330,38 @@ public final class MacroValueAssignment: Serializable, CustomStringConvertible,
379330
/// Reference to the next (lower precedence) assignment in the linked list, or nil if this is the last one.
380331
public let next: MacroValueAssignment?
381332

333+
private let _location: InternedMacroValueAssignmentLocation?
334+
private static let macroConfigPaths = SWBMutex<OrderedSet<Path>>(OrderedSet())
335+
336+
var location: MacroValueAssignmentLocation? {
337+
if let _location {
338+
return .init(
339+
path: Self.macroConfigPaths.withLock { $0[_location.pathRef] },
340+
line: _location.line,
341+
startColumn: _location.startColumn,
342+
endColumn: _location.endColumn
343+
)
344+
} else {
345+
return nil
346+
}
347+
}
348+
382349
/// Initializes the macro value assignment to represent `expression`, with the next existing macro value assignment (if any).
383-
init(expression: MacroExpression, conditions: MacroConditionSet? = nil, next: MacroValueAssignment?) {
350+
init(expression: MacroExpression, conditions: MacroConditionSet? = nil, next: MacroValueAssignment?, location: MacroValueAssignmentLocation?) {
384351
self.expression = expression
385352
self.conditions = conditions
386353
self.next = next
354+
355+
if let location {
356+
self._location = InternedMacroValueAssignmentLocation(
357+
pathRef: Self.macroConfigPaths.withLock({ $0.append(location.path).index }),
358+
line: location.line,
359+
startColumn: location.startColumn,
360+
endColumn: location.endColumn
361+
)
362+
} else {
363+
self._location = nil
364+
}
387365
}
388366

389367
/// Returns the first macro value assignment that is reachable from the receiver and whose conditions match the given set of parameter values, or nil if there is no such assignment value. The returned assignment may be the receiver itself, or it may be any assignment that’s downstream in the linked list of macro value assignments, or it may be nil if there is none. Unconditional macro value assignments are considered to match any conditions. Conditions that reference parameters that don’t have a value in `paramValues` are only considered to match if the match pattern is `*`, i.e. the “match-anything” pattern (which is effectively a no-op).
@@ -435,18 +413,20 @@ public final class MacroValueAssignment: Serializable, CustomStringConvertible,
435413
// MARK: Serialization
436414

437415
public func serialize<T: Serializer>(to serializer: T) {
438-
serializer.beginAggregate(3)
416+
serializer.beginAggregate(4)
439417
serializer.serialize(expression)
440418
serializer.serialize(conditions)
441419
serializer.serialize(next)
420+
serializer.serialize(_location)
442421
serializer.endAggregate()
443422
}
444423

445424
public init(from deserializer: any Deserializer) throws {
446-
try deserializer.beginAggregate(3)
425+
try deserializer.beginAggregate(4)
447426
self.expression = try deserializer.deserialize()
448427
self.conditions = try deserializer.deserialize()
449428
self.next = try deserializer.deserialize()
429+
self._location = try deserializer.deserialize()
450430
}
451431
}
452432

@@ -510,10 +490,10 @@ private func insertCopiesOfMacroValueAssignmentNodes(_ srcAsgn: MacroValueAssign
510490
}
511491

512492
if let srcNext = srcAsgn.next {
513-
return MacroValueAssignment(expression: srcAsgn.expression, conditions:srcAsgn.conditions, next: insertCopiesOfMacroValueAssignmentNodes(srcNext, inFrontOf: dstAsgn))
493+
return MacroValueAssignment(expression: srcAsgn.expression, conditions:srcAsgn.conditions, next: insertCopiesOfMacroValueAssignmentNodes(srcNext, inFrontOf: dstAsgn), location: srcAsgn.location)
514494
}
515495
else {
516-
return MacroValueAssignment(expression: srcAsgn.expression, conditions:srcAsgn.conditions, next: dstAsgn)
496+
return MacroValueAssignment(expression: srcAsgn.expression, conditions:srcAsgn.conditions, next: dstAsgn, location: srcAsgn.location)
517497
}
518498
}
519499

0 commit comments

Comments
 (0)