Skip to content

Commit 9c0ae27

Browse files
authored
Add Wrappers for Class, Actor, Extension, along with DeclGroupProtocol and ModifierProtocol (#17)
* add missing wrappers * swift-format * add inherited types * swift-format * Remove RawRepresentable Conformance * remove AnyDeclProtocol * swift-format * swift-format is whack
1 parent 4375a1c commit 9c0ae27

27 files changed

+702
-248
lines changed

Sources/MacroToolkit/ClassRestrictionType.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ public struct ClassRestrictionType: TypeProtocol {
55
public var _baseSyntax: ClassRestrictionTypeSyntax
66
public var _attributedSyntax: AttributedTypeSyntax?
77

8-
public init(_ syntax: ClassRestrictionTypeSyntax, attributedSyntax: AttributedTypeSyntax? = nil) {
8+
public init(
9+
_ syntax: ClassRestrictionTypeSyntax,
10+
attributedSyntax: AttributedTypeSyntax? = nil
11+
) {
912
_baseSyntax = syntax
1013
_attributedSyntax = attributedSyntax
1114
}

Sources/MacroToolkit/DeclGroup.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import SwiftSyntax
2+
3+
/// Wraps an `actor` declaration.
4+
public struct Actor: DeclGroupProtocol, RepresentableBySyntax {
5+
/// The underlying syntax node for the `actor` declaration.
6+
public var _syntax: ActorDeclSyntax
7+
8+
/// The identifier (name) of the `actor`.
9+
public var identifier: String {
10+
_syntax.name.withoutTrivia().text
11+
}
12+
13+
/// Initializes an `Actor` instance with the given syntax node.
14+
///
15+
/// - Parameter syntax: The syntax node representing the `actor` declaration.
16+
public init(_ syntax: ActorDeclSyntax) {
17+
_syntax = syntax
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import SwiftSyntax
2+
3+
/// Wraps a `class` declaration.
4+
public struct Class: DeclGroupProtocol, RepresentableBySyntax {
5+
/// The underlying syntax node for the `class` declaration.
6+
public var _syntax: ClassDeclSyntax
7+
8+
/// The identifier (name) of the `class`.
9+
public var identifier: String {
10+
_syntax.name.withoutTrivia().text
11+
}
12+
13+
/// Initializes a `Class` instance with the given syntax node.
14+
///
15+
/// - Parameter syntax: The syntax node representing the `class` declaration.
16+
public init(_ syntax: ClassDeclSyntax) {
17+
_syntax = syntax
18+
}
19+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import SwiftSyntax
2+
3+
/// An enum that encapsulates various types of declaration groups (`struct`, `class`, `enum`, `actor`, `extension`)
4+
/// and provides a unified interface for interacting with them. This enum conforms to `DeclGroupProtocol`,
5+
/// allowing access to common properties of declaration groups.
6+
public enum DeclGroup: DeclGroupProtocol {
7+
case `struct`(Struct)
8+
case `enum`(Enum)
9+
case `class`(Class)
10+
case `actor`(Actor)
11+
case `extension`(Extension)
12+
13+
/// A private computed property that returns the wrapped `DeclGroupProtocol` instance.
14+
///
15+
/// This property is used internally to access the underlying implementation of the declaration group.
16+
private var wrapped: any DeclGroupProtocol {
17+
switch self {
18+
case .struct(let wrapped): return wrapped
19+
case .enum(let wrapped): return wrapped
20+
case .class(let wrapped): return wrapped
21+
case .actor(let wrapped): return wrapped
22+
case .extension(let wrapped): return wrapped
23+
}
24+
}
25+
26+
/// Initializes a `DeclGroup` instance from a `DeclGroupSyntax`.
27+
///
28+
/// - Parameter syntax: The syntax node representing the declaration group.
29+
/// - Note: This initializer will fatalError if the syntax node does not match any known declaration group type.
30+
public init(_ syntax: DeclGroupSyntax) {
31+
if let syntax = syntax.as(ActorDeclSyntax.self) {
32+
self = .actor(Actor(syntax))
33+
} else if let syntax = syntax.as(ClassDeclSyntax.self) {
34+
self = .class(Class(syntax))
35+
} else if let syntax = syntax.as(EnumDeclSyntax.self) {
36+
self = .enum(Enum(syntax))
37+
} else if let syntax = syntax.as(ExtensionDeclSyntax.self) {
38+
self = .extension(Extension(syntax))
39+
} else if let syntax = syntax.as(StructDeclSyntax.self) {
40+
self = .struct(Struct(syntax))
41+
} else {
42+
fatalError("Unhandled decl group type '\(type(of: syntax))'")
43+
}
44+
}
45+
46+
/// The identifier of the declaration group.
47+
public var identifier: String { wrapped.identifier }
48+
49+
/// All members declared within the declaration group.
50+
public var members: [Decl] { wrapped.members }
51+
52+
/// All properties declared within the declaration group.
53+
public var properties: [Property] { wrapped.properties }
54+
55+
/// All types that the declaration group inherits from or conforms to.
56+
public var inheritedTypes: [Type] { wrapped.inheritedTypes }
57+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import SwiftSyntax
2+
3+
/// A protocol that represents a declaration group, such as a `struct`, `class`, `enum`, or `protocol`.
4+
/// This protocol defines common properties that all declaration groups should have.
5+
public protocol DeclGroupProtocol {
6+
/// The identifier of the declaration group.
7+
var identifier: String { get }
8+
9+
/// All members declared within the declaration group.
10+
var members: [Decl] { get }
11+
12+
/// All properties declared within the declaration group.
13+
var properties: [Property] { get }
14+
15+
/// All types that the declaration group inherits from or conforms to.
16+
var inheritedTypes: [Type] { get }
17+
}
18+
19+
extension DeclGroupProtocol where UnderlyingSyntax: DeclGroupSyntax, Self: RepresentableBySyntax {
20+
/// Attempts to initialize the wrapper from an arbitrary declaration group.
21+
///
22+
/// - Parameter syntax: The syntax node representing the declaration group.
23+
/// - Note: This initializer will return `nil` if the syntax node does not match the expected type.
24+
public init?(_ syntax: any DeclGroupSyntax) {
25+
guard let syntax = syntax as? UnderlyingSyntax else { return nil }
26+
self.init(syntax)
27+
}
28+
29+
public var members: [Decl] {
30+
_syntax.memberBlock.members.map(\.decl).map(Decl.init)
31+
}
32+
33+
public var properties: [Property] {
34+
members.compactMap(\.asVariable).flatMap { variable in
35+
var bindings = variable._syntax.bindings.flatMap { binding in
36+
Property.properties(from: binding, in: variable)
37+
}
38+
// For the declaration `var a, b: Int` where `a` doesn't have an annotation,
39+
// `a` gets given the type of `b` (`Int`). To implement this, we 'drag' the
40+
// type annotations backwards over the non-annotated bindings.
41+
var lastSeenType: Type?
42+
for (i, binding) in bindings.enumerated().reversed() {
43+
if let type = binding.type {
44+
lastSeenType = type
45+
} else {
46+
bindings[i].type = lastSeenType
47+
}
48+
}
49+
return bindings
50+
}
51+
}
52+
53+
public var inheritedTypes: [Type] {
54+
_syntax.inheritanceClause?.inheritedTypes.map(\.type).map(Type.init) ?? []
55+
}
56+
57+
public var accessLevel: AccessModifier? {
58+
AccessModifier(firstModifierOfKindIn: _syntax.modifiers)
59+
}
60+
61+
public var declarationContext: DeclarationContextModifier? {
62+
DeclarationContextModifier(firstModifierOfKindIn: _syntax.modifiers)
63+
}
64+
}

Sources/MacroToolkit/Enum.swift renamed to Sources/MacroToolkit/DeclGroup/Enum.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import SwiftSyntax
22

33
/// Wraps an `enum` declaration.
4-
public struct Enum: DeclGroupProtocol {
4+
public struct Enum: DeclGroupProtocol, RepresentableBySyntax {
5+
/// The underlying syntax node for the `enum` declaration.
56
public var _syntax: EnumDeclSyntax
67

8+
/// The identifier (name) of the `enum`.
79
public var identifier: String {
810
_syntax.name.withoutTrivia().text
911
}
1012

13+
/// Initializes an `Enum` instance with the given syntax node.
14+
///
15+
/// - Parameter syntax: The syntax node representing the `enum` declaration.
1116
public init(_ syntax: EnumDeclSyntax) {
1217
_syntax = syntax
1318
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import SwiftSyntax
2+
3+
/// Wraps an `extension` declaration.
4+
public struct Extension: DeclGroupProtocol, RepresentableBySyntax {
5+
/// The underlying syntax node for the `extension` declaration.
6+
public var _syntax: ExtensionDeclSyntax
7+
8+
/// The identifier (extended type) of the `extension`.
9+
public var identifier: String {
10+
_syntax.extendedType.withoutTrivia().description
11+
}
12+
13+
/// Initializes an `Extension` instance with the given syntax node.
14+
///
15+
/// - Parameter syntax: The syntax node representing the `extension` declaration.
16+
public init(_ syntax: ExtensionDeclSyntax) {
17+
_syntax = syntax
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import SwiftSyntax
2+
3+
/// Wraps a `struct` declaration.
4+
public struct Struct: DeclGroupProtocol, RepresentableBySyntax {
5+
/// The underlying syntax node for the `struct` declaration.
6+
public var _syntax: StructDeclSyntax
7+
8+
/// The identifier (name) of the `struct`.
9+
public var identifier: String {
10+
_syntax.name.withoutTrivia().text
11+
}
12+
13+
/// Initializes a `Struct` instance with the given syntax node.
14+
///
15+
/// - Parameter syntax: The syntax node representing the `struct` declaration.
16+
public init(_ syntax: StructDeclSyntax) {
17+
_syntax = syntax
18+
}
19+
}

Sources/MacroToolkit/DeclGroupProtocol.swift

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)