From b7f0ce9d7f129fd434d24d665261fdf0c24d5a88 Mon Sep 17 00:00:00 2001 From: "Alik.eth Vovkotrub" Date: Tue, 17 Oct 2023 17:03:56 +0300 Subject: [PATCH 1/2] update SourceKit version to release 509 fix build error fix deprecations fix tests fix documentation --- Package.resolved | 4 +-- Package.swift | 3 +-- .../ExtractCaseValue/ExtractCaseValue.swift | 2 ++ .../ExtractCaseValueMacro.swift | 25 +++++++++--------- .../ExtractCaseValueTests.swift | 26 ++++++++++++------- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Package.resolved b/Package.resolved index c4f9794..48c07b6 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5", - "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a" + "revision" : "74203046135342e4a4a627476dd6caf8b28fe11b", + "version" : "509.0.0" } } ], diff --git a/Package.swift b/Package.swift index 41f07bb..3b80a74 100644 --- a/Package.swift +++ b/Package.swift @@ -19,8 +19,7 @@ let package = Package( ), ], dependencies: [ - // Depend on the latest Swift 5.9 prerelease of SwiftSyntax - .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b") + .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/Sources/ExtractCaseValue/ExtractCaseValue.swift b/Sources/ExtractCaseValue/ExtractCaseValue.swift index f3280f8..9254f63 100644 --- a/Sources/ExtractCaseValue/ExtractCaseValue.swift +++ b/Sources/ExtractCaseValue/ExtractCaseValue.swift @@ -20,6 +20,7 @@ import ExtractCaseValueMacros /// case relative(String) /// case absolute(String) /// case root +/// /// var path: String { /// switch self { /// case let .relative(__macro_local_4pathfMu_): @@ -53,6 +54,7 @@ public macro ExtractCaseValue(name: String, kind: CaseExtractionKind = .defau /// case relative(String) /// case absolute(String) /// case root +/// /// var path: String { /// switch self { /// case let .relative(__macro_local_4pathfMu_): diff --git a/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift b/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift index 347d2ae..69c1fc3 100644 --- a/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift +++ b/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift @@ -27,7 +27,7 @@ extension ExtractCaseValueMacro: MemberMacro { } guard - let arguments = attribute.argument, + let arguments = attribute.arguments, case let .argumentList(arguments) = arguments else { context.diagnose(ExtractCaseValueMacroDiagnostic.requiresArgs.diagnose(at: attribute)) @@ -59,10 +59,10 @@ extension ExtractCaseValueMacro: MemberMacro { // get expected type guard let returnType = attribute - .attributeName.as(SimpleTypeIdentifierSyntax.self)? + .attributeName.as(IdentifierTypeSyntax.self)? .genericArgumentClause? .arguments.first? - .argumentType + .argument else { context.diagnose(ExtractCaseValueMacroDiagnostic.requiresGenericType.diagnose(at: attribute)) return [] @@ -83,10 +83,11 @@ extension ExtractCaseValueMacro: MemberMacro { // create fix-it to add a default value if necessary guard - let tupleList = attribute.argument?.as(TupleExprElementListSyntax.self) + let tupleList = attribute.arguments?.as(LabeledExprListSyntax.self) else { return [] } let expr: ExprSyntax = ", \(propertyNameString): <#Type#>" - let newTupleList = tupleList.inserting(TupleExprElementSyntax(expression: expr), at: tupleList.count) + var newTupleList = tupleList + newTupleList.append(LabeledExprSyntax(expression: expr)) let insertDefaultFixIt = FixIt( message: InsertDefaultValueItMessage(), @@ -98,17 +99,17 @@ extension ExtractCaseValueMacro: MemberMacro { let elements = caseDecls.flatMap(\.elements) // infer access modifier from enum - let access = enumDecl.modifiers?.first(where: \.isNeededAccessLevelModifier) + let access = enumDecl.modifiers.first(where: \.isNeededAccessLevelModifier) var switchCaseSyntaxes: [SwitchCaseSyntax] = [] for element in elements { let caseSyntax = element.as(EnumCaseElementSyntax.self)! - guard let paramList = caseSyntax.associatedValue?.parameterList else { + guard let paramList = caseSyntax.parameterClause?.parameters else { if let defaultValue { switchCaseSyntaxes.append( - "case .\(element.identifier): return \(defaultValue)" + "case .\(element.name): return \(defaultValue)" ) continue } else { @@ -127,7 +128,7 @@ extension ExtractCaseValueMacro: MemberMacro { else { if let defaultValue { switchCaseSyntaxes.append( - "case .\(element.identifier): return \(defaultValue)" + "case .\(element.name): return \(defaultValue)" ) didUseDefaultValue = true break @@ -148,7 +149,7 @@ extension ExtractCaseValueMacro: MemberMacro { guard let associatedValue = paramList.first(labeled: name), let index = paramList.firstIndex(of: name) else { if let defaultValue { switchCaseSyntaxes.append( - "case .\(element.identifier): return \(defaultValue)" + "case .\(element.name): return \(defaultValue)" ) didUseDefaultValue = true break @@ -170,7 +171,7 @@ extension ExtractCaseValueMacro: MemberMacro { else { if let defaultValue { switchCaseSyntaxes.append( - "case .\(element.identifier): return \(defaultValue)" + "case .\(element.name): return \(defaultValue)" ) didUseDefaultValue = true break @@ -192,7 +193,7 @@ extension ExtractCaseValueMacro: MemberMacro { .joined(separator: ", ") switchCaseSyntaxes.append( - "case let .\(element.identifier)(\(raw: variablesAndUnderscores)): return \(uniqueVariableName)" + "case let .\(element.name)(\(raw: variablesAndUnderscores)): return \(uniqueVariableName)" ) } diff --git a/Tests/ExtractCaseValueTests/ExtractCaseValueTests.swift b/Tests/ExtractCaseValueTests/ExtractCaseValueTests.swift index 93fb5eb..1310acc 100644 --- a/Tests/ExtractCaseValueTests/ExtractCaseValueTests.swift +++ b/Tests/ExtractCaseValueTests/ExtractCaseValueTests.swift @@ -24,6 +24,7 @@ final class ExtractCaseValueTests: XCTestCase { case relative(String) case absolute(String) case root + var path: String { switch self { case let .relative(__macro_local_4pathfMu_): @@ -57,6 +58,7 @@ final class ExtractCaseValueTests: XCTestCase { case relative(String) case absolute(String) case root + public var path: String { switch self { case let .relative(__macro_local_4pathfMu_): @@ -88,6 +90,7 @@ final class ExtractCaseValueTests: XCTestCase { enum Coordinate { case twoDee(x: Double, y: Double) case threeDee(x: Double, y: Double, z: Double) + var x: Double { switch self { case let .twoDee(__macro_local_1xfMu_, _): @@ -119,6 +122,7 @@ final class ExtractCaseValueTests: XCTestCase { case relative(String) case absolute(String) case root + var path: String { switch self { case let .relative(__macro_local_4pathfMu_): @@ -150,6 +154,7 @@ final class ExtractCaseValueTests: XCTestCase { enum Coordinate { case twoDee(x: Double, y: Double) case threeDee(x: Double, y: Double, z: Double) + var y: Double { switch self { case let .twoDee(_, __macro_local_1yfMu_): @@ -179,6 +184,7 @@ final class ExtractCaseValueTests: XCTestCase { enum Coordinate { case twoDee(x: Double, y: Double) case threeDee(x: Double, y: Double, z: Double) + var z: Double? { switch self { case .twoDee: @@ -210,6 +216,7 @@ final class ExtractCaseValueTests: XCTestCase { enum Coordinate { case twoDee(x: Double, y: Double) case threeDee(x: Double, y: Double, z: Double) + var x: Double { switch self { case let .twoDee(__macro_local_1xfMu_, _): @@ -218,6 +225,7 @@ final class ExtractCaseValueTests: XCTestCase { return __macro_local_1xfMu0_ } } + var y: Double { switch self { case let .twoDee(_, __macro_local_1yfMu_): @@ -226,6 +234,7 @@ final class ExtractCaseValueTests: XCTestCase { return __macro_local_1yfMu0_ } } + var z: Double? { switch self { case .twoDee: @@ -263,6 +272,7 @@ final class ExtractCaseValueTests: XCTestCase { case array([_JSON]) case bool(Bool) case null + var string: String? { switch self { case let .string(__macro_local_6stringfMu_): @@ -294,8 +304,7 @@ final class ExtractCaseValueTests: XCTestCase { """, expandedSource: """ - struct NotAnEnum { - } + struct NotAnEnum {} """, diagnostics: [ .init(message: "'ExtractCaseValue' macro can only be applied to an enum", line: 1, column: 1) @@ -313,8 +322,7 @@ final class ExtractCaseValueTests: XCTestCase { """, expandedSource: """ - enum AnEnum { - } + enum AnEnum {} """, diagnostics: [ .init(message: "'ExtractCaseValue' macro requires arguments", line: 1, column: 1) @@ -332,8 +340,7 @@ final class ExtractCaseValueTests: XCTestCase { """, expandedSource: """ - enum AnEnum { - } + enum AnEnum {} """, diagnostics: [ .init(message: "'ExtractCaseValue' macro requires `name` argument", line: 1, column: 1) @@ -351,8 +358,7 @@ final class ExtractCaseValueTests: XCTestCase { """, expandedSource: """ - enum AnEnum { - } + enum AnEnum {} """, diagnostics: [ .init(message: "'ExtractCaseValue' macro argument `name` must be a string literal", line: 1, column: 33) @@ -370,8 +376,7 @@ final class ExtractCaseValueTests: XCTestCase { """, expandedSource: """ - enum AnEnum { - } + enum AnEnum {} """, diagnostics: [ .init(message: "'ExtractCaseValue' macro requires a generic type for the computed property", line: 1, column: 1) @@ -569,6 +574,7 @@ final class ExtractCaseValueTests: XCTestCase { enum Coordinate { case twoDee(x: Double, y: Double) case threeDee(x: Double, y: Double, z: Double) + var a: Double? { switch self { case .twoDee: From 1bb37f030116a96ad1e09970869192f1124022ed Mon Sep 17 00:00:00 2001 From: "Alik.eth Vovkotrub" Date: Tue, 17 Oct 2023 17:05:21 +0300 Subject: [PATCH 2/2] Add helper function to shorten the lines Add helper function to MacroExpansionContext to utilise shorthand enum syntax --- .../ExtractCaseValueMacros/Diagnostics.swift | 6 ++++ .../ExtractCaseValueMacro.swift | 33 ++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Sources/ExtractCaseValueMacros/Diagnostics.swift b/Sources/ExtractCaseValueMacros/Diagnostics.swift index 0b0949d..7d71a23 100644 --- a/Sources/ExtractCaseValueMacros/Diagnostics.swift +++ b/Sources/ExtractCaseValueMacros/Diagnostics.swift @@ -74,3 +74,9 @@ struct InsertDefaultValueItMessage: FixItMessage { MessageID(domain: "Swift", id: "ExtractCaseValue.\(self)") } } + +extension MacroExpansionContext { + func diagnose(_ diagnostic: ExtractCaseValueMacroDiagnostic, at node: some SyntaxProtocol, fixIts: [FixIt] = []) { + diagnose(diagnostic.diagnose(at: node, fixIts: fixIts)) + } +} diff --git a/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift b/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift index 69c1fc3..dc843e8 100644 --- a/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift +++ b/Sources/ExtractCaseValueMacros/ExtractCaseValueMacro.swift @@ -22,7 +22,7 @@ extension ExtractCaseValueMacro: MemberMacro { ) throws -> [DeclSyntax] { // Only apply to enums guard let enumDecl = declaration.as(EnumDeclSyntax.self) else { - context.diagnose(ExtractCaseValueMacroDiagnostic.requiresEnum.diagnose(at: declaration)) + context.diagnose(.requiresEnum, at: declaration) return [] } @@ -30,18 +30,18 @@ extension ExtractCaseValueMacro: MemberMacro { let arguments = attribute.arguments, case let .argumentList(arguments) = arguments else { - context.diagnose(ExtractCaseValueMacroDiagnostic.requiresArgs.diagnose(at: attribute)) + context.diagnose(.requiresArgs, at: attribute) return [] } // get `name` argument guard let propertyNameArg = arguments.first(labeled: caseParamExtractionPropertyNameArgumentLabel) else { - context.diagnose(ExtractCaseValueMacroDiagnostic.requiresPropertyNameArg.diagnose(at: attribute)) + context.diagnose(.requiresPropertyNameArg, at: attribute) return [] } guard let propertyNameString = propertyNameArg.expression.stringLiteralSegment else { - context.diagnose(ExtractCaseValueMacroDiagnostic.requiresPropertyNameStringLiteral.diagnose(at: propertyNameArg.expression)) + context.diagnose(.requiresPropertyNameStringLiteral, at: propertyNameArg.expression) return [] } @@ -64,7 +64,7 @@ extension ExtractCaseValueMacro: MemberMacro { .arguments.first? .argument else { - context.diagnose(ExtractCaseValueMacroDiagnostic.requiresGenericType.diagnose(at: attribute)) + context.diagnose(.requiresGenericType, at: attribute) return [] } @@ -113,7 +113,7 @@ extension ExtractCaseValueMacro: MemberMacro { ) continue } else { - context.diagnose(ExtractCaseValueMacroDiagnostic.noAssociatedValues(case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt])) + context.diagnose(.noAssociatedValues(case: element.name.text), at: element, fixIts: [insertDefaultFixIt]) return [] } } @@ -133,13 +133,13 @@ extension ExtractCaseValueMacro: MemberMacro { didUseDefaultValue = true break } else { - context.diagnose(ExtractCaseValueMacroDiagnostic.noValue(case: element.identifier.text, index: index).diagnose(at: element, fixIts: [insertDefaultFixIt])) + context.diagnose(.noValue(case: element.name.text, index: index), at: element, fixIts: [insertDefaultFixIt]) return [] } } guard associatedValue.element.type.matchesReturnType(returnType) else { - context.diagnose(ExtractCaseValueMacroDiagnostic.typeMismatch(case: element.identifier.text, index: index).diagnose(at: associatedValue.element)) + context.diagnose(.typeMismatch(case: element.name.text, index: index), at: associatedValue.element) return [] } @@ -154,13 +154,20 @@ extension ExtractCaseValueMacro: MemberMacro { didUseDefaultValue = true break } else { - context.diagnose(ExtractCaseValueMacroDiagnostic.noAssociatedValueForName(name: name, case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt])) + context.diagnose( + .noAssociatedValueForName(name: name, case: element.name.text), + at: element, + fixIts: [insertDefaultFixIt] + ) return [] } } guard associatedValue.type.matchesReturnType(returnType) else { - context.diagnose(ExtractCaseValueMacroDiagnostic.typeMismatchNamed(name: name, case: element.identifier.text).diagnose(at: associatedValue)) + context.diagnose( + .typeMismatchNamed(name: name, case: element.name.text), + at: associatedValue + ) return [] } @@ -176,7 +183,11 @@ extension ExtractCaseValueMacro: MemberMacro { didUseDefaultValue = true break } else { - context.diagnose(ExtractCaseValueMacroDiagnostic.noMatchingType(type: "\(returnType)", case: element.identifier.text).diagnose(at: element, fixIts: [insertDefaultFixIt])) + context.diagnose( + .noMatchingType(type: "\(returnType)", case: element.name.text), + at: element, + fixIts: [insertDefaultFixIt] + ) return [] } }