diff --git a/Sources/SwiftWarningControl/SyntaxProtocol+WarningControl.swift b/Sources/SwiftWarningControl/SyntaxProtocol+WarningControl.swift index 2b058d721a0..c3d8a4fd305 100644 --- a/Sources/SwiftWarningControl/SyntaxProtocol+WarningControl.swift +++ b/Sources/SwiftWarningControl/SyntaxProtocol+WarningControl.swift @@ -27,7 +27,7 @@ extension SyntaxProtocol { @_spi(ExperimentalLanguageFeatures) public func warningGroupControl( for diagnosticGroupIdentifier: DiagnosticGroupIdentifier, - globalControls: [DiagnosticGroupIdentifier: WarningGroupControl] = [:], + globalControls: [(DiagnosticGroupIdentifier, WarningGroupControl)] = [], groupInheritanceTree: DiagnosticGroupInheritanceTree? = nil ) -> WarningGroupControl? { let warningControlRegions = root.warningGroupControlRegionTreeImpl( diff --git a/Sources/SwiftWarningControl/WarningControlDeclSyntax.swift b/Sources/SwiftWarningControl/WarningControlDeclSyntax.swift index 6480600645a..dbc406e45f9 100644 --- a/Sources/SwiftWarningControl/WarningControlDeclSyntax.swift +++ b/Sources/SwiftWarningControl/WarningControlDeclSyntax.swift @@ -15,8 +15,8 @@ import SwiftSyntax extension WithAttributesSyntax { /// Compute a dictionary of all `@warn` diagnostic group behavior controls /// specified on this warning control declaration scope. - var allWarningGroupControls: [DiagnosticGroupIdentifier: WarningGroupControl] { - attributes.reduce(into: [DiagnosticGroupIdentifier: WarningGroupControl]()) { result, attr in + var allWarningGroupControls: [(DiagnosticGroupIdentifier, WarningGroupControl)] { + attributes.reduce(into: [(DiagnosticGroupIdentifier, WarningGroupControl)]()) { result, attr in // `@warn` attributes guard case .attribute(let attributeSyntax) = attr, attributeSyntax.attributeName.as(IdentifierTypeSyntax.self)?.name.text == "warn" @@ -50,7 +50,7 @@ extension WithAttributesSyntax { else { return } - result[DiagnosticGroupIdentifier(diagnosticGroupID)] = control + result.append((DiagnosticGroupIdentifier(diagnosticGroupID), control)) } } } diff --git a/Sources/SwiftWarningControl/WarningControlRegionBuilder.swift b/Sources/SwiftWarningControl/WarningControlRegionBuilder.swift index 285864bd2ee..fc156a262c7 100644 --- a/Sources/SwiftWarningControl/WarningControlRegionBuilder.swift +++ b/Sources/SwiftWarningControl/WarningControlRegionBuilder.swift @@ -16,7 +16,7 @@ import SwiftSyntax extension SyntaxProtocol { @_spi(ExperimentalLanguageFeatures) public func warningGroupControlRegionTree( - globalControls: [DiagnosticGroupIdentifier: WarningGroupControl] = [:], + globalControls: [(DiagnosticGroupIdentifier, WarningGroupControl)] = [], groupInheritanceTree: DiagnosticGroupInheritanceTree? = nil ) -> WarningControlRegionTree { return warningGroupControlRegionTreeImpl( @@ -30,7 +30,7 @@ extension SyntaxProtocol { /// a specific absolute position - meant to speed up tree generation for individual /// queries. func warningGroupControlRegionTreeImpl( - globalControls: [DiagnosticGroupIdentifier: WarningGroupControl], + globalControls: [(DiagnosticGroupIdentifier, WarningGroupControl)], groupInheritanceTree: DiagnosticGroupInheritanceTree?, containing position: AbsolutePosition? = nil ) -> WarningControlRegionTree { diff --git a/Sources/SwiftWarningControl/WarningControlRegions.swift b/Sources/SwiftWarningControl/WarningControlRegions.swift index 8faf4c5901b..ce4d84b6c3d 100644 --- a/Sources/SwiftWarningControl/WarningControlRegions.swift +++ b/Sources/SwiftWarningControl/WarningControlRegions.swift @@ -123,7 +123,7 @@ public struct WarningControlRegionTree { /// Add a warning control region to the tree mutating func addWarningGroupControls( range: Range, - controls: [DiagnosticGroupIdentifier: WarningGroupControl] + controls: [(DiagnosticGroupIdentifier, WarningGroupControl)] ) { guard !controls.isEmpty else { return } let newNode = WarningControlRegionNode(range: range) diff --git a/Tests/SwiftWarningControlTest/WarningControlTests.swift b/Tests/SwiftWarningControlTest/WarningControlTests.swift index acf23b2012d..8afa9baf0c1 100644 --- a/Tests/SwiftWarningControlTest/WarningControlTests.swift +++ b/Tests/SwiftWarningControlTest/WarningControlTests.swift @@ -272,7 +272,7 @@ public class WarningGroupControlTests: XCTestCase { 1️⃣let x = 1 } """, - globalControls: ["GroupID": .warning], + globalControls: [("GroupID", .warning)], diagnosticGroupID: "GroupID", states: [ "1️⃣": .error @@ -289,7 +289,7 @@ public class WarningGroupControlTests: XCTestCase { } } """, - globalControls: ["GroupID": .error], + globalControls: [("GroupID", .error)], diagnosticGroupID: "GroupID", states: [ "1️⃣": .error, @@ -306,7 +306,7 @@ public class WarningGroupControlTests: XCTestCase { 1️⃣let x = 1 } """, - globalControls: ["GroupID": .warning], + globalControls: [("GroupID", .warning)], diagnosticGroupID: "GroupID", states: [ "1️⃣": .warning @@ -351,13 +351,49 @@ public class WarningGroupControlTests: XCTestCase { ) } } + + func testOrderedGlobalControls() throws { + // Parent group is ignored, followed by sub-group treated as warning + try assertWarningGroupControl( + """ + func foo() { + 1️⃣let x = 1 + } + """, + globalControls: [("SuperGroupID", .ignored), ("GroupID", .warning)], + groupInheritanceTree: DiagnosticGroupInheritanceTree(subGroups: [ + "SuperGroupID": ["GroupID"] + ]), + diagnosticGroupID: "GroupID", + states: [ + "1️⃣": .warning + ] + ) + + // Parent group is treated as warning, followed by ignored sub-group + try assertWarningGroupControl( + """ + func foo() { + 1️⃣let x = 1 + } + """, + globalControls: [("SuperGroupID", .warning), ("GroupID", .ignored)], + groupInheritanceTree: DiagnosticGroupInheritanceTree(subGroups: [ + "SuperGroupID": ["GroupID"] + ]), + diagnosticGroupID: "GroupID", + states: [ + "1️⃣": .ignored + ] + ) + } } /// Assert that the various marked positions in the source code have the /// expected warning behavior controls. private func assertWarningGroupControl( _ markedSource: String, - globalControls: [DiagnosticGroupIdentifier: WarningGroupControl] = [:], + globalControls: [(DiagnosticGroupIdentifier, WarningGroupControl)] = [], groupInheritanceTree: DiagnosticGroupInheritanceTree? = nil, diagnosticGroupID: DiagnosticGroupIdentifier, states: [String: WarningGroupControl?],