diff --git a/Package.swift b/Package.swift index 5936cfd..b4ddb82 100644 --- a/Package.swift +++ b/Package.swift @@ -52,6 +52,7 @@ let package = Package( name: "AliasTests", dependencies: [ "Alias", + "AliasPlugin", .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), diff --git a/Sources/AliasPlugin/AliasMacro.swift b/Sources/AliasPlugin/AliasMacro.swift index bc536dd..d611f27 100644 --- a/Sources/AliasPlugin/AliasMacro.swift +++ b/Sources/AliasPlugin/AliasMacro.swift @@ -128,9 +128,37 @@ extension AliasMacro { } guard let binding = varDecl.bindings.first, - let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier, - binding.typeAnnotation != nil else { - context.diagnose(AliasMacroDiagnostic.specifyTypeExplicitly.diagnose(at: varDecl)) + let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier else { + context.diagnose(AliasMacroDiagnostic.unsupportedDeclaration.diagnose(at: varDecl)) + return [] + } + + var typeAnnotation: TypeAnnotationSyntax? + if let specifiedType = binding.typeAnnotation { + typeAnnotation = specifiedType + } else if let defaultValue = binding.initializer?.value { + var type: TypeSyntax? + switch defaultValue { + case _ where defaultValue.is(StringLiteralExprSyntax.self): + type = "Swift.String" + case _ where defaultValue.is(IntegerLiteralExprSyntax.self): + type = "Swift.Int" + case _ where defaultValue.is(FloatLiteralExprSyntax.self): + type = "Swift.Double" + case _ where defaultValue.is(BooleanLiteralExprSyntax.self): + type = "Swift.Bool" + default: break + } + if let type { + typeAnnotation = .init( + type: type, + trailingTrivia: .space + ) + } + } + + guard let typeAnnotation else { + context.diagnose(AliasMacroDiagnostic.specifyTypeExplicitly.diagnose(at: binding)) return [] } @@ -147,6 +175,7 @@ extension AliasMacro { binding .with(\.pattern, .init(IdentifierPatternSyntax(identifier: .identifier(arguments.alias)))) .with(\.initializer, nil) + .with(\.typeAnnotation, typeAnnotation) .with(\.accessorBlock, .init(accessors: .accessors( AccessorDeclListSyntax { diff --git a/Tests/AliasTests/AliasTests.swift b/Tests/AliasTests/AliasTests.swift index dbadf4a..6fc8546 100644 --- a/Tests/AliasTests/AliasTests.swift +++ b/Tests/AliasTests/AliasTests.swift @@ -48,6 +48,29 @@ final class AliasTests: XCTestCase { ) } + func testVariableAliasWithLiteral() throws { + assertMacroExpansion( + """ + @Alias("newText", access: .inherit) + fileprivate var string = "text" + """, + expandedSource: + """ + fileprivate var string = "text" + + fileprivate var newText: Swift.String { + set { + string = newValue + } + get { + string + } + } + """, + macros: macros + ) + } + func testFunctionAlias() throws { assertMacroExpansion( """ @@ -342,19 +365,19 @@ final class AliasTests: XCTestCase { assertMacroExpansion( """ @Alias("newText", access: .inherit) - fileprivate var string = "text" + fileprivate var string = String() """, expandedSource: """ - fileprivate var string = "text" + fileprivate var string = String() """, diagnostics: [ DiagnosticSpec( message: AliasMacroDiagnostic .specifyTypeExplicitly .message, - line: 1, - column: 1 + line: 2, + column: 17 ) ], macros: macros