mirror of
https://github.com/zhigang1992/swift-request.git
synced 2026-01-12 17:52:47 +08:00
70 lines
2.5 KiB
Swift
70 lines
2.5 KiB
Swift
import SwiftSyntax
|
|
import SwiftSyntaxMacros
|
|
import Foundation
|
|
import SwiftDiagnostics
|
|
|
|
public class MethodMacro: PeerMacro {
|
|
public static func expansion(
|
|
of node: AttributeSyntax,
|
|
providingPeersOf declaration: some DeclSyntaxProtocol,
|
|
in context: some MacroExpansionContext
|
|
) throws -> [DeclSyntax] {
|
|
let method = node.attributeName.description
|
|
let diagnostics = MethodDiagnostics(method: method)
|
|
|
|
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
|
|
context.diagnose(diagnostics.justFunction(node: declaration))
|
|
return []
|
|
}
|
|
|
|
if let staticModifier = funcDecl.modifiers?.first(where: {
|
|
$0.name.tokenKind == TokenKind.keyword(.static)
|
|
})?.as(DeclModifierSyntax.self) {
|
|
context.diagnose(diagnostics.nonStaticFunction(node: funcDecl, staticModifier: staticModifier))
|
|
return []
|
|
}
|
|
|
|
let effectSpecifiers = funcDecl.signature.effectSpecifiers
|
|
guard effectSpecifiers?.asyncSpecifier != nil, effectSpecifiers?.throwsSpecifier != nil else {
|
|
context.diagnose(diagnostics.asyncAndThrowsRequired(node: funcDecl))
|
|
return []
|
|
}
|
|
|
|
guard let returnType = funcDecl.signature.output?.returnType else {
|
|
context.diagnose(diagnostics.outputTypeRequired(node: funcDecl))
|
|
return []
|
|
}
|
|
|
|
guard validate(outputType: returnType, in: context) else {
|
|
context.diagnose(diagnostics.outputTypeMustBeTypeOrTuple(node: funcDecl))
|
|
return []
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
private static func validate(
|
|
outputType: TypeSyntax,
|
|
in context: some MacroExpansionContext
|
|
) -> Bool {
|
|
if outputType.is(SimpleTypeIdentifierSyntax.self) || outputType.is(MemberTypeIdentifierSyntax.self) {
|
|
return true
|
|
}
|
|
|
|
if let arrayType = outputType.as(ArrayTypeSyntax.self) {
|
|
return validate(outputType: arrayType.elementType, in: context)
|
|
}
|
|
|
|
guard let tupleSyntax = outputType.as(TupleTypeSyntax.self),
|
|
let tupleElements = tupleSyntax.elements.as(TupleTypeElementListSyntax.self),
|
|
tupleElements.count == 2,
|
|
let secondElement = tupleElements.last?.as(TupleTypeElementSyntax.self),
|
|
secondElement.type.description == "HTTPURLResponse" else {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
}
|