diff --git a/Package.resolved b/Package.resolved index bdf6e10..07284dd 100644 --- a/Package.resolved +++ b/Package.resolved @@ -23,8 +23,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" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", + "version" : "509.0.2" } }, { diff --git a/Package.swift b/Package.swift index 5d95a50..b8c42af 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( ), ], dependencies: [ - .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"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.1.0"), .package(url: "https://github.com/ShenghaiWang/SwiftKeychain.git", from: "0.2.0") ], diff --git a/Sources/Macros/Access.swift b/Sources/Macros/Access.swift index 9a4b473..d130e3d 100644 --- a/Sources/Macros/Access.swift +++ b/Sources/Macros/Access.swift @@ -125,34 +125,34 @@ public struct Access: AccessorMacro { } } -private extension TupleExprElementSyntax { +private extension LabeledExprSyntax { var type: String? { - expression.as(MemberAccessExprSyntax.self)?.name.text - ?? expression.as(FunctionCallExprSyntax.self)?.calledExpression.as(MemberAccessExprSyntax.self)?.name.text + expression.as(MemberAccessExprSyntax.self)?.declName.baseName.text + ?? expression.as(FunctionCallExprSyntax.self)?.calledExpression.as(MemberAccessExprSyntax.self)?.declName.baseName.text } } -private extension TupleExprElementSyntax { +private extension LabeledExprSyntax { var userDefaults: ExprSyntax { if expression.is(MemberAccessExprSyntax.self) { return "UserDefaults.standard" } - if let memeberAceess = expression.as(FunctionCallExprSyntax.self)?.argumentList.first? - .as(TupleExprElementSyntax.self)?.expression.as(MemberAccessExprSyntax.self) { - return "UserDefaults.\(raw: memeberAceess.name.text)" + if let memeberAceess = expression.as(FunctionCallExprSyntax.self)?.arguments.first? + .as(LabeledExprSyntax.self)?.expression.as(MemberAccessExprSyntax.self) { + return "UserDefaults.\(raw: memeberAceess.declName.baseName.text)" } else { - return expression.as(FunctionCallExprSyntax.self)?.argumentList.first?.expression ?? "UserDefaults.standard" + return expression.as(FunctionCallExprSyntax.self)?.arguments.first?.expression ?? "UserDefaults.standard" } } var object: ExprSyntax? { - expression.as(FunctionCallExprSyntax.self)?.argumentList.first?.as(TupleExprElementSyntax.self)?.expression + expression.as(FunctionCallExprSyntax.self)?.arguments.first?.as(LabeledExprSyntax.self)?.expression } } -private extension SimpleTypeIdentifierSyntax { +private extension IdentifierTypeSyntax { var type: SyntaxProtocol? { - genericArgumentClause?.arguments.first?.as(GenericArgumentSyntax.self)?.argumentType.as(OptionalTypeSyntax.self)?.wrappedType + genericArgumentClause?.arguments.first?.as(GenericArgumentSyntax.self)?.argument.as(OptionalTypeSyntax.self)?.wrappedType ?? genericArgumentClause?.arguments.first?.as(GenericArgumentSyntax.self) } } diff --git a/Sources/Macros/AddAssociatedValueVariable.swift b/Sources/Macros/AddAssociatedValueVariable.swift index 966f7db..e9eb99f 100644 --- a/Sources/Macros/AddAssociatedValueVariable.swift +++ b/Sources/Macros/AddAssociatedValueVariable.swift @@ -13,21 +13,21 @@ public struct AddAssociatedValueVariable: MemberMacro { } return try members.flatMap { list-> [DeclSyntax] in try list.compactMap { element -> DeclSyntax? in - guard let associatedValue = element.associatedValue else { return nil } + guard let associatedValue = element.parameterClause else { return nil } let typeValue: String - if associatedValue.parameterList.isOneSimpleTypeIdentifierSyntax { - typeValue = "\(associatedValue.parameterList.first ?? "")" + if associatedValue.parameters.isOneSimpleTypeIdentifierSyntax { + typeValue = "\(associatedValue.parameters.first ?? "")" } else { typeValue = "\(associatedValue)" } - let varSyntax = try VariableDeclSyntax("\(declaration.modifiers ?? ModifierListSyntax())var \(element.identifier)Value: \(raw: typeValue)?") { + let varSyntax = try VariableDeclSyntax("\(declaration.modifiers )var \(element.name)Value: \(raw: typeValue)?") { try IfExprSyntax( - "if case let .\(element.identifier)(\(raw: associatedValue.parameterList.toVariableNames)) = self", + "if case let .\(element.name)(\(raw: associatedValue.parameters.toVariableNames)) = self", bodyBuilder: { - if associatedValue.parameterList.count == 1 { - StmtSyntax("return \(raw: associatedValue.parameterList.toVariableNames)") + if associatedValue.parameters.count == 1 { + StmtSyntax("return \(raw: associatedValue.parameters.toVariableNames)") } else { - StmtSyntax("return (\(raw: associatedValue.parameterList.toVariableNames))") + StmtSyntax("return (\(raw: associatedValue.parameters.toVariableNames))") } }) StmtSyntax(#"return nil"#) @@ -44,6 +44,6 @@ extension EnumCaseParameterListSyntax { } var isOneSimpleTypeIdentifierSyntax: Bool { - count == 1 && (first?.type.is(SimpleTypeIdentifierSyntax.self) ?? false) + count == 1 && (first?.type.is(IdentifierTypeSyntax.self) ?? false) } } diff --git a/Sources/Macros/AddInit.swift b/Sources/Macros/AddInit.swift index 1f112d7..59f04aa 100644 --- a/Sources/Macros/AddInit.swift +++ b/Sources/Macros/AddInit.swift @@ -14,15 +14,13 @@ public struct AddInit: MemberMacro { let (parameters, body) = initBodyAndParams(for: declaration) let bodyExpr: ExprSyntax = "\(raw: body.joined(separator: "\n"))" var parametersLiteral = "init(\(parameters.joined(separator: ", ")))" - if let modifiers = declaration.modifiers { - parametersLiteral = "\(modifiers)\(parametersLiteral)" - } - let initDecl = try InitializerDeclSyntax(PartialSyntaxNodeString(stringLiteral: parametersLiteral), + parametersLiteral = "\(declaration.modifiers)\(parametersLiteral)" + let initDecl = try InitializerDeclSyntax(SyntaxNodeString(stringLiteral: parametersLiteral), bodyBuilder: { bodyExpr }) var result = [DeclSyntax(initDecl)] - if node.argument(for: "withMock")?.as(BooleanLiteralExprSyntax.self)?.booleanLiteral.tokenKind.keyword == .true { + if node.argument(for: "withMock")?.as(BooleanLiteralExprSyntax.self)?.literal.tokenKind.keyword == .true { let randomValue = node.argument(for: "randomMockValue")?.as(BooleanLiteralExprSyntax.self)? - .booleanLiteral.tokenKind.keyword != .false + .literal.tokenKind.keyword != .false result.append(mock(basedOn: declaration, randomValue: randomValue)) } return result @@ -45,16 +43,16 @@ public struct AddInit: MemberMacro { parameter += " = nil" } parameters.append(parameter) - body.append("self.\(identifier) = \(identifier)") + body.append(" self.\(identifier) = \(identifier)") } } return (params: parameters, body: body) } private static func mock(basedOn declaration: DeclGroupSyntax, randomValue: Bool) -> DeclSyntax { - let identifier = (declaration as? StructDeclSyntax)?.identifier.text - ?? (declaration as? ClassDeclSyntax)?.identifier.text - ?? (declaration as? ActorDeclSyntax)?.identifier.text ?? "" + let identifier = (declaration as? StructDeclSyntax)?.name.text + ?? (declaration as? ClassDeclSyntax)?.name.text + ?? (declaration as? ActorDeclSyntax)?.name.text ?? "" let parameters = declaration.memberBlock.members.compactMap { member -> String? in guard let patternBinding = member.decl.as(VariableDeclSyntax.self)?.bindings .as(PatternBindingListSyntax.self)?.first?.as(PatternBindingSyntax.self), @@ -66,9 +64,7 @@ public struct AddInit: MemberMacro { return "\(identifier): \(mockValue)" } var varDelcaration: DeclSyntax = "static let mock = \(raw: identifier)(\(raw: parameters.joined(separator: ", ")))" - if let modifiers = declaration.modifiers { - varDelcaration = "\(modifiers)varDelcaration" - } + varDelcaration = "\(declaration.modifiers)\(varDelcaration)" varDelcaration = "#if DEBUG\n\(varDelcaration)\n#endif" return varDelcaration } @@ -76,13 +72,13 @@ public struct AddInit: MemberMacro { extension AttributeSyntax { func argument(for label: String) -> ExprSyntax? { - argument?.as(TupleExprElementListSyntax.self)?.filter({ $0.label?.text == label }).first?.expression + arguments?.as(LabeledExprListSyntax.self)?.filter({ $0.label?.text == label }).first?.expression } } -extension SimpleTypeIdentifierSyntax { +extension IdentifierTypeSyntax { func mockValue(randomValue: Bool) -> String? { - guard let type = self.as(SimpleTypeIdentifierSyntax.self)?.name.text else { return nil } + guard let type = self.as(IdentifierTypeSyntax.self)?.name.text else { return nil } if let fun = mockFunctions[type] { return fun(randomValue) } else if name.text == "Void" { @@ -107,30 +103,30 @@ extension OptionalTypeSyntax { extension FunctionTypeSyntax { func mockValue(randomValue: Bool) -> String? { - let args = repeatElement("_", count: max(arguments.count, 1)).joined(separator: ", ") - let returnValue = output.returnType.mockValue(randomValue: randomValue) ?? "" + let args = repeatElement("_", count: max(parameters.count, 1)).joined(separator: ", ") + let returnValue = returnClause.type.mockValue(randomValue: randomValue) ?? "" return "{ \(args) in return \(returnValue) }" } } extension TypeSyntax { func mockValue(randomValue: Bool) -> String? { - if let mockValue = self.as(SimpleTypeIdentifierSyntax.self)?.mockValue(randomValue: randomValue) { + if let mockValue = self.as(IdentifierTypeSyntax.self)?.mockValue(randomValue: randomValue) { return mockValue } else if let type = self.as(DictionaryTypeSyntax.self) { - let mockKeyValue = type.keyType.mockValue(randomValue: randomValue) ?? "" - let mockValueValue = type.valueType.mockValue(randomValue: randomValue) ?? "nil" + let mockKeyValue = type.key.mockValue(randomValue: randomValue) ?? "" + let mockValueValue = type.value.mockValue(randomValue: randomValue) ?? "nil" return "[\(mockKeyValue): \(mockValueValue)]" } else if let mockValue = self.as(FunctionTypeSyntax.self)?.mockValue(randomValue: randomValue) { return mockValue } else if let mockValue = self.as(TupleTypeSyntax.self)?.elements.first?.type .as(FunctionTypeSyntax.self)?.mockValue(randomValue: randomValue) { return mockValue - } else if let type = self.as(ArrayTypeSyntax.self)?.elementType { + } else if let type = self.as(ArrayTypeSyntax.self)?.element { return "[" + (type.mockValue(randomValue: randomValue) ?? "nil") + "]" - } else if let type = self.as(SimpleTypeIdentifierSyntax.self), + } else if let type = self.as(IdentifierTypeSyntax.self), type.name.text == "Set", - let genericType = type.genericArgumentClause?.arguments.first?.argumentType { + let genericType = type.genericArgumentClause?.arguments.first?.argument { return "[" + (genericType.mockValue(randomValue: randomValue) ?? "nil") + "]" } return nil diff --git a/Sources/Macros/AddPublisher.swift b/Sources/Macros/AddPublisher.swift index 08149c1..9f4da70 100644 --- a/Sources/Macros/AddPublisher.swift +++ b/Sources/Macros/AddPublisher.swift @@ -9,8 +9,7 @@ public struct AddPublisher: PeerMacro { providingPeersOf declaration: Declaration, in context: Context) throws -> [DeclSyntax] { guard let variableDecl = declaration.as(VariableDeclSyntax.self), - let modifiers = variableDecl.modifiers, - modifiers.map({ $0.name.text }).contains("private") else { + variableDecl.modifiers.map({ $0.name.text }).contains("private") else { throw MacroDiagnostics.errorMacroUsage(message: "Please make the subject private and use the automated generated publisher variable outsite of this type") } guard let binding = variableDecl.bindings.first, @@ -32,12 +31,14 @@ public struct AddPublisher: PeerMacro { extension PatternBindingListSyntax.Element { var genericArgumentClause: GenericArgumentClauseSyntax? { - initializer?.value.as(FunctionCallExprSyntax.self)?.calledExpression.as(SpecializeExprSyntax.self)?.genericArgumentClause - ?? typeAnnotation?.type.as(SimpleTypeIdentifierSyntax.self)?.genericArgumentClause + initializer?.value.as(FunctionCallExprSyntax.self)? + .calledExpression.as(GenericSpecializationExprSyntax.self)? + .genericArgumentClause + ?? typeAnnotation?.type.as(IdentifierTypeSyntax.self)?.genericArgumentClause } var typeName: String? { - initializer?.value.as(FunctionCallExprSyntax.self)?.calledExpression.as(SpecializeExprSyntax.self)?.expression.as(IdentifierExprSyntax.self)?.identifier.text - ?? typeAnnotation?.type.as(SimpleTypeIdentifierSyntax.self)?.name.text + initializer?.value.as(FunctionCallExprSyntax.self)?.calledExpression.as(GenericSpecializationExprSyntax.self)?.expression.as(DeclReferenceExprSyntax.self)?.baseName.text + ?? typeAnnotation?.type.as(IdentifierTypeSyntax.self)?.name.text } } diff --git a/Sources/Macros/FormatDate.swift b/Sources/Macros/FormatDate.swift index 2f92404..910647b 100644 --- a/Sources/Macros/FormatDate.swift +++ b/Sources/Macros/FormatDate.swift @@ -13,18 +13,18 @@ public struct FormatDate: ExpressionMacro { let formatter: DeclSyntax = "let formatter = DateFormatter()" let formatterStatement = CodeBlockItemSyntax(item: .decl(formatter)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: formatterStatement) - node.argumentList.filter { $0.label != nil }.forEach { tupleExprElementSyntax in - if let parameter = tupleExprElementSyntax.label?.text, - !tupleExprElementSyntax.expression.is(NilLiteralExprSyntax.self) { - let stmt: StmtSyntax = "formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" - let codeblock = CodeBlockItemSyntax(item: .stmt(stmt)) - statementList = statementList.appending(codeblock) + let arguments = node.argumentList.filter { $0.label != nil } + .compactMap { tupleExprElementSyntax in + if let parameter = tupleExprElementSyntax.label?.text, + !tupleExprElementSyntax.expression.is(NilLiteralExprSyntax.self) { + let stmt: StmtSyntax = "\n formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" + return CodeBlockItemSyntax(item: .stmt(stmt)) + } + return nil } - } - let returnValue: ExprSyntax = "return formatter.string(from: \(date.expression))" + let returnValue: ExprSyntax = "\n return formatter.string(from: \(date.expression))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) + let statementList = CodeBlockItemListSyntax([formatterStatement] + arguments + [returnblock]) let closure = ClosureExprSyntax(statements: statementList) let function = FunctionCallExprSyntax(callee: closure) return ExprSyntax(function) diff --git a/Sources/Macros/FormatDateComponents.swift b/Sources/Macros/FormatDateComponents.swift index 3b53916..2026109 100644 --- a/Sources/Macros/FormatDateComponents.swift +++ b/Sources/Macros/FormatDateComponents.swift @@ -23,43 +23,31 @@ public struct FormatDateComponents: ExpressionMacro { return ExprSyntax(function) } - private static func parseFromToFunction(for argumentList: TupleExprElementListSyntax, + private static func parseFromToFunction(for argumentList: LabeledExprListSyntax, from fromDate: ExprSyntax, to toDate: ExprSyntax) -> CodeBlockItemListSyntax { let formatter: DeclSyntax = "let formatter = DateComponentsFormatter()" let formatterStatement = CodeBlockItemSyntax(item: .decl(formatter)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: formatterStatement) - argumentList.dropFirst(2).forEach { tupleExprElementSyntax in - if let codeblock = codeblock(for: tupleExprElementSyntax) { - statementList = statementList.appending(codeblock) - } - } - let returnValue: ExprSyntax = "return formatter.string(from: \(fromDate), to: \(toDate))" + let arguments = argumentList.dropFirst(2).compactMap { codeblock(for: $0) } + let returnValue: ExprSyntax = "\n return formatter.string(from: \(fromDate), to: \(toDate))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) - return statementList + return CodeBlockItemListSyntax([formatterStatement] + arguments + [returnblock]) } - private static func parseFromFunction(for argumentList: TupleExprElementListSyntax, + private static func parseFromFunction(for argumentList: LabeledExprListSyntax, from fromInterval: ExprSyntax) -> CodeBlockItemListSyntax { let formatter: DeclSyntax = "let formatter = DateComponentsFormatter()" let formatterStatement = CodeBlockItemSyntax(item: .decl(formatter)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: formatterStatement) - argumentList.dropFirst(1).forEach { tupleExprElementSyntax in - if let codeblock = codeblock(for: tupleExprElementSyntax) { - statementList = statementList.appending(codeblock) - } - } - let returnValue: ExprSyntax = "return formatter.string(from: \(fromInterval))" + let arguments = argumentList.dropFirst(1).compactMap { codeblock(for: $0) } + let returnValue: ExprSyntax = "\n return formatter.string(from: \(fromInterval))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) - return statementList + return CodeBlockItemListSyntax([formatterStatement] + arguments + [returnblock]) } - private static func codeblock(for tupleExprElementSyntax: TupleExprElementSyntax) -> CodeBlockItemSyntax? { + private static func codeblock(for tupleExprElementSyntax: LabeledExprSyntax) -> CodeBlockItemSyntax? { if let parameter = tupleExprElementSyntax.label?.text, !tupleExprElementSyntax.expression.is(NilLiteralExprSyntax.self) { - let stmt: StmtSyntax = "formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" + let stmt: StmtSyntax = "\n formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" let codeblock = CodeBlockItemSyntax(item: .stmt(stmt)) return codeblock } diff --git a/Sources/Macros/FormatDateInterval.swift b/Sources/Macros/FormatDateInterval.swift index f9e1523..0f871cd 100644 --- a/Sources/Macros/FormatDateInterval.swift +++ b/Sources/Macros/FormatDateInterval.swift @@ -14,18 +14,17 @@ public struct FormatDateInterval: ExpressionMacro { let formatter: DeclSyntax = "let formatter = DateIntervalFormatter()" let formatterStatement = CodeBlockItemSyntax(item: .decl(formatter)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: formatterStatement) - node.argumentList.dropFirst(2).forEach { tupleExprElementSyntax in + let arguments = node.argumentList.dropFirst(2).compactMap { tupleExprElementSyntax in if let parameter = tupleExprElementSyntax.label?.text, !tupleExprElementSyntax.expression.is(NilLiteralExprSyntax.self) { - let stmt: StmtSyntax = "formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" - let codeblock = CodeBlockItemSyntax(item: .stmt(stmt)) - statementList = statementList.appending(codeblock) + let stmt: StmtSyntax = "\n formatter.\(raw: parameter) = \(tupleExprElementSyntax.expression)" + return CodeBlockItemSyntax(item: .stmt(stmt)) } + return nil } - let returnValue: ExprSyntax = "return formatter.string(from: \(fromDate), to: \(toDate))" + let returnValue: ExprSyntax = "\n return formatter.string(from: \(fromDate), to: \(toDate))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) + let statementList = CodeBlockItemListSyntax([formatterStatement] + arguments + [returnblock]) let closure = ClosureExprSyntax(statements: statementList) let function = FunctionCallExprSyntax(callee: closure) return ExprSyntax(function) @@ -34,6 +33,6 @@ public struct FormatDateInterval: ExpressionMacro { extension FreestandingMacroExpansionSyntax { func argument(for label: String) -> ExprSyntax? { - argumentList.as(TupleExprElementListSyntax.self)?.filter({ $0.label?.text == label }).first?.expression + argumentList.as(LabeledExprListSyntax.self)?.filter({ $0.label?.text == label }).first?.expression } } diff --git a/Sources/Macros/JSONEncoderrDecoder.swift b/Sources/Macros/JSONEncoderrDecoder.swift index b6b2e6c..701414a 100644 --- a/Sources/Macros/JSONEncoderrDecoder.swift +++ b/Sources/Macros/JSONEncoderrDecoder.swift @@ -20,18 +20,18 @@ public struct Encode: ExpressionMacro { } let encoder: DeclSyntax = "let encoder = JSONEncoder()" let encoderStatement = CodeBlockItemSyntax(item: .decl(encoder)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: encoderStatement) - node.argumentList.filter { $0.label != nil }.forEach { tupleExprElementSyntax in - if let parameter = tupleExprElementSyntax.label?.text, - defaults[parameter] != "\(tupleExprElementSyntax.expression)" { - let stmt: StmtSyntax = "encoder.\(raw: parameter) = \(tupleExprElementSyntax.expression)" - let codeblock = CodeBlockItemSyntax(item: .stmt(stmt)) - statementList = statementList.appending(codeblock) + let arguments = node.argumentList.filter { $0.label != nil } + .compactMap { tupleExprElementSyntax in + if let parameter = tupleExprElementSyntax.label?.text, + defaults[parameter] != "\(tupleExprElementSyntax.expression)" { + let stmt: StmtSyntax = "\n encoder.\(raw: parameter) = \(tupleExprElementSyntax.expression)" + return CodeBlockItemSyntax(item: .stmt(stmt)) + } + return nil } - } - let returnValue: ExprSyntax = "return try encoder.encode(\(value))" + let returnValue: ExprSyntax = "\n return try encoder.encode(\(value))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) + let statementList = CodeBlockItemListSyntax([encoderStatement] + arguments + [returnblock]) let closure = ClosureExprSyntax(statements: statementList) let function = FunctionCallExprSyntax(callee: closure) return ExprSyntax(function) @@ -56,18 +56,19 @@ public struct Decode: ExpressionMacro { } let decoder: DeclSyntax = "let decoder = JSONDecoder()" let decoderStatement = CodeBlockItemSyntax(item: .decl(decoder)) - var statementList = CodeBlockItemListSyntax(arrayLiteral: decoderStatement) - node.argumentList.filter { $0.label != nil && $0.label?.text != "from" }.forEach { tupleExprElementSyntax in + let arguments = node.argumentList + .filter { $0.label != nil && $0.label?.text != "from" } + .compactMap { tupleExprElementSyntax in if let parameter = tupleExprElementSyntax.label?.text, defaults[parameter] != "\(tupleExprElementSyntax.expression)" { - let stmt: StmtSyntax = "decoder.\(raw: tupleExprElementSyntax.label?.text ?? "") = \(tupleExprElementSyntax.expression)" - let codeblock = CodeBlockItemSyntax(item: .stmt(stmt)) - statementList = statementList.appending(codeblock) + let stmt: StmtSyntax = "\n decoder.\(raw: tupleExprElementSyntax.label?.text ?? "") = \(tupleExprElementSyntax.expression)" + return CodeBlockItemSyntax(item: .stmt(stmt)) } + return nil } - let returnValue: ExprSyntax = "return try decoder.decode(\(type), from: \(data))" + let returnValue: ExprSyntax = "\n return try decoder.decode(\(type), from: \(data))" let returnblock = CodeBlockItemSyntax(item: .expr(returnValue)) - statementList = statementList.appending(returnblock) + let statementList = CodeBlockItemListSyntax([decoderStatement] + arguments + [returnblock]) let closure = ClosureExprSyntax(statements: statementList) let function = FunctionCallExprSyntax(callee: closure) return ExprSyntax(function) diff --git a/Sources/Macros/Mock.swift b/Sources/Macros/Mock.swift index 2a6ca40..1bf3df5 100644 --- a/Sources/Macros/Mock.swift +++ b/Sources/Macros/Mock.swift @@ -16,17 +16,15 @@ public struct Mock: PeerMacro { throw MacroDiagnostics.errorMacroUsage(message: "Must specify type name") } - let randomValue = node.argument(for: "randomMockValue")?.as(BooleanLiteralExprSyntax.self)? - .booleanLiteral.tokenKind.keyword != .false - let parameters = initializer.signature.input.parameterList.compactMap { parameter -> String in + let randomValue = node.argument(for: "randomMockValue")? + .as(BooleanLiteralExprSyntax.self)?.literal.tokenKind.keyword != .false + let parameters = initializer.signature.parameterClause.parameters.compactMap { parameter -> String in let name = parameter.firstName let mockValue = parameter.type.mockValue(randomValue: randomValue) ?? "nil" return "\(name): \(mockValue)" } var varDelcaration: DeclSyntax = "static let mock = \(raw: typeName)(\(raw: parameters.joined(separator: ", ")))" - if let modifiers = initializer.modifiers { - varDelcaration = "\(modifiers)\(varDelcaration)" - } + varDelcaration = "\(initializer.modifiers)\(varDelcaration)" varDelcaration = "#if DEBUG\n\(varDelcaration)\n#endif" return [varDelcaration] } diff --git a/Sources/Macros/Singleton.swift b/Sources/Macros/Singleton.swift index a6da38a..e411a2c 100644 --- a/Sources/Macros/Singleton.swift +++ b/Sources/Macros/Singleton.swift @@ -10,29 +10,29 @@ public struct Singleton: MemberMacro { guard [SwiftSyntax.SyntaxKind.classDecl, .structDecl].contains(declaration.kind) else { throw MacroDiagnostics.errorMacroUsage(message: "Can only be applied to a struct or class") } - let identifier = (declaration as? StructDeclSyntax)?.identifier ?? (declaration as? ClassDeclSyntax)?.identifier ?? "" + let identifier = (declaration as? StructDeclSyntax)?.name ?? (declaration as? ClassDeclSyntax)?.name ?? "" var override = "" - if let inheritedTypes = (declaration as? ClassDeclSyntax)?.inheritanceClause?.inheritedTypeCollection, - inheritedTypes.contains(where: { inherited in inherited.typeName.trimmedDescription == "NSObject" }) { + if let inheritedTypes = (declaration as? ClassDeclSyntax)?.inheritanceClause?.inheritedTypes, + inheritedTypes.contains(where: { inherited in inherited.type.trimmedDescription == "NSObject" }) { override = "override " } let initializer = try InitializerDeclSyntax("private \(raw: override)init()") {} let selfToken: TokenSyntax = "\(raw: identifier.text)()" - let initShared = FunctionCallExprSyntax(calledExpression: IdentifierExprSyntax(identifier: selfToken)) {} + let initShared = FunctionCallExprSyntax(calledExpression: DeclReferenceExprSyntax(baseName: selfToken)) {} let sharedInitializer = InitializerClauseSyntax(equal: .equalToken(trailingTrivia: .space), value: initShared) let staticToken: TokenSyntax = "static" let staticModifier = DeclModifierSyntax(name: staticToken) - var modifiers = ModifierListSyntax([staticModifier]) + var modifiers = DeclModifierListSyntax([staticModifier]) - let isPublicACL = declaration.modifiers?.compactMap(\.name.tokenKind.keyword).contains(.public) ?? false + let isPublicACL = declaration.modifiers.compactMap(\.name.tokenKind.keyword).contains(.public) if isPublicACL { let publicToken: TokenSyntax = "public" let publicModifier = DeclModifierSyntax(name: publicToken) - modifiers = modifiers.inserting(publicModifier, at: 0) + modifiers = DeclModifierListSyntax([publicModifier] + [staticModifier]) } let shared = VariableDeclSyntax(modifiers: modifiers, diff --git a/Tests/MacroTests/AddAssociatedValueVariableTests.swift b/Tests/MacroTests/AddAssociatedValueVariableTests.swift index 0e8a6f6..d6e059d 100644 --- a/Tests/MacroTests/AddAssociatedValueVariableTests.swift +++ b/Tests/MacroTests/AddAssociatedValueVariableTests.swift @@ -33,42 +33,49 @@ final class AddAssociatedValueVairiableTests: XCTestCase { case fifth(a: String, Int) case sixth(a: () -> Void) case seventh(() -> Void) + var secondValue: Int? { if case let .second(v0) = self { return v0 } return nil } + var thirdValue: (String, Int)? { if case let .third(v0, v1) = self { return (v0, v1) } return nil } + var third2Value: (String, Int)? { if case let .third2(v0, v1) = self { return (v0, v1) } return nil } + var forthValue: (a: String, b: Int)? { if case let .forth(v0, v1) = self { return (v0, v1) } return nil } + var fifthValue: (a: String, Int)? { if case let .fifth(v0, v1) = self { return (v0, v1) } return nil } + var sixthValue: (a: () -> Void)? { if case let .sixth(v0) = self { return v0 } return nil } + var seventhValue: (() -> Void)? { if case let .seventh(v0) = self { return v0 @@ -96,6 +103,7 @@ final class AddAssociatedValueVairiableTests: XCTestCase { public enum A { case first case second(Int) + public var secondValue: Int? { if case let .second(v0) = self { return v0 diff --git a/Tests/MacroTests/AddInitTests.swift b/Tests/MacroTests/AddInitTests.swift index b40d34e..18f4488 100644 --- a/Tests/MacroTests/AddInitTests.swift +++ b/Tests/MacroTests/AddInitTests.swift @@ -23,6 +23,7 @@ final class AddInitTests: XCTestCase { struct A { let a: Int? let b: Int + init(a: Int? = nil, b: Int) { self.a = a self.b = b @@ -48,6 +49,7 @@ final class AddInitTests: XCTestCase { public struct A { let a: Int? let b: Int + public init(a: Int? = nil, b: Int) { self.a = a self.b = b @@ -73,6 +75,7 @@ final class AddInitTests: XCTestCase { public class A { let a: Int? let b: Int + public init(a: Int? = nil, b: Int) { self.a = a self.b = b @@ -98,6 +101,7 @@ final class AddInitTests: XCTestCase { public class A { let a: Int? let b: (Int) -> Void + public init(a: Int? = nil, b: @escaping (Int) -> Void) { self.a = a self.b = b @@ -123,6 +127,7 @@ final class AddInitTests: XCTestCase { public class A { let a: Int? let b: ((Int) -> Void)? + public init(a: Int? = nil, b: ((Int) -> Void)? = nil) { self.a = a self.b = b @@ -148,6 +153,7 @@ final class AddInitTests: XCTestCase { actor A { let a: Int let b: Int? + init(a: Int, b: Int? = nil) { self.a = a self.b = b @@ -175,11 +181,13 @@ final class AddInitTests: XCTestCase { let a: Int let b: Int? let c: (Int) -> Int + init(a: Int, b: Int? = nil, c: @escaping (Int) -> Int) { self.a = a self.b = b self.c = c } + #if DEBUG static let mock = A(a: 1, b: nil, c: { _ in return 1 @@ -208,11 +216,13 @@ final class AddInitTests: XCTestCase { let a: [Int] let b: Set let c: [Int: String] + init(a: [Int], b: Set, c: [Int: String]) { self.a = a self.b = b self.c = c } + #if DEBUG static let mock = A(a: [1], b: [1], c: [1: "abcd"]) #endif @@ -240,9 +250,11 @@ final class AddInitTests: XCTestCase { } struct B { let a: A + init(a: A) { self.a = a } + #if DEBUG static let mock = B(a: A.mock) #endif diff --git a/Tests/MacroTests/AddPublisherTests.swift b/Tests/MacroTests/AddPublisherTests.swift index a3d31dd..5d952ac 100644 --- a/Tests/MacroTests/AddPublisherTests.swift +++ b/Tests/MacroTests/AddPublisherTests.swift @@ -18,6 +18,7 @@ final class AddPublisherTests: XCTestCase { """ private let subject = PassthroughSubject() + var subjectPublisher: AnyPublisher { subject.eraseToAnyPublisher() } @@ -36,6 +37,7 @@ final class AddPublisherTests: XCTestCase { """ private let subject = CurrentValueSubject(()) + var subjectPublisher: AnyPublisher { subject.eraseToAnyPublisher() } @@ -54,6 +56,7 @@ final class AddPublisherTests: XCTestCase { """ private let subject: CurrentValueSubject = .init(()) + var subjectPublisher: AnyPublisher { subject.eraseToAnyPublisher() } diff --git a/Tests/MacroTests/MockTests.swift b/Tests/MacroTests/MockTests.swift index e53c6e4..e33fab7 100644 --- a/Tests/MacroTests/MockTests.swift +++ b/Tests/MacroTests/MockTests.swift @@ -27,6 +27,7 @@ final class MockTests: XCTestCase { init(a: Int) { self.a = a } + #if DEBUG static let mock = AStruct(a: 1) #endif diff --git a/Tests/MacroTests/SingletonTests.swift b/Tests/MacroTests/SingletonTests.swift index d7f4568..f576d9d 100644 --- a/Tests/MacroTests/SingletonTests.swift +++ b/Tests/MacroTests/SingletonTests.swift @@ -12,15 +12,20 @@ final class SingletonTests: XCTestCase { assertMacroExpansion( """ @Singleton - struct A {} + struct A { + + } """, expandedSource: """ struct A { + private init() { } + static let shared = A() + } """, macros: testMacros @@ -31,15 +36,20 @@ final class SingletonTests: XCTestCase { assertMacroExpansion( """ @Singleton - public struct A {} + public struct A { + + } """, expandedSource: """ public struct A { + private init() { } + public static let shared = A() + } """, macros: testMacros @@ -55,8 +65,7 @@ final class SingletonTests: XCTestCase { expandedSource: """ - enum A { - } + enum A {} """, diagnostics: [ DiagnosticSpec(message: "Can only be applied to a struct or class", line: 1, column: 1) @@ -69,15 +78,20 @@ final class SingletonTests: XCTestCase { assertMacroExpansion( """ @Singleton - class A: NSObject {} + class A: NSObject { + + } """, expandedSource: """ class A: NSObject { + private override init() { } + static let shared = A() + } """, macros: testMacros