Files
SwiftLint/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift
T
2023-10-19 21:35:57 +02:00

81 lines
2.6 KiB
Swift

import SwiftSyntax
import SwiftSyntaxMacros
enum SwiftSyntaxRule: ExtensionMacro {
static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
return [
try ExtensionDeclSyntax("""
extension \(type): SwiftSyntaxRule {
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
Visitor(configuration: configuration, file: file)
}
}
"""),
try createFoldingPreprocessor(type: type, foldArgument: node.foldArgument),
try createRewriter(type: type, rewriterArgument: node.explicitRewriterArgument)
].compactMap { $0 }
}
private static func createFoldingPreprocessor(
type: some TypeSyntaxProtocol,
foldArgument: ExprSyntax?
) throws -> ExtensionDeclSyntax? {
guard foldArgument.isTrueLiteral else {
return nil
}
return try ExtensionDeclSyntax("""
extension \(type) {
func preprocess(file: SwiftLintFile) -> SourceFileSyntax? {
file.foldedSyntaxTree
}
}
""")
}
private static func createRewriter(
type: some TypeSyntaxProtocol,
rewriterArgument: ExprSyntax?
) throws -> ExtensionDeclSyntax? {
guard rewriterArgument.isTrueLiteral else {
return nil
}
return try ExtensionDeclSyntax("""
extension \(type): SwiftSyntaxCorrectableRule {
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(locationConverter: file.locationConverter, disabledRegions: disabledRegions(file: file))
}
}
""")
}
}
private extension AttributeSyntax {
var foldArgument: ExprSyntax? {
findArgument(withName: "foldExpressions")
}
var explicitRewriterArgument: ExprSyntax? {
findArgument(withName: "explicitRewriter")
}
private func findArgument(withName name: String) -> ExprSyntax? {
if case let .argumentList(args) = arguments, let first = args.first(where: { $0.label?.text == name }) {
first.expression
} else {
nil
}
}
}
private extension ExprSyntax? {
var isTrueLiteral: Bool {
self?.as(BooleanLiteralExprSyntax.self)?.literal.text == "true"
}
}