Skip to content

Commit a28bb9c

Browse files
committed
fix: fixed empty CodingKeys enum generated instead of being skipped
1 parent 97a6057 commit a28bb9c

40 files changed

+1111
-1144
lines changed

Sources/CodableMacroPlugin/Attributes/Attribute.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ extension Attribute {
5252
/// This attribute can must be removed or its usage condition
5353
/// must be satisfied.
5454
var misuseMessageID: MessageID { messageID("\(id)-misuse") }
55-
/// Message id for unnecessary usage of this attribute.
56-
///
57-
/// This attribute can be omitted in such scenario and the
58-
/// final result will still be the same.
59-
var unusedMessageID: MessageID { messageID("\(id)-unused") }
6055

6156
/// Creates a new message id in current package domain.
6257
///

Sources/CodableMacroPlugin/Attributes/CodedAs.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ struct CodedAs: PropertyAttribute {
4949
/// * If macro has zero arguments provided:
5050
/// * Attached declaration is an enum declaration.
5151
/// * This attribute must be combined with `Codable`
52-
/// and `TaggedAt` attribute.
52+
/// and `CodedAt` attribute.
5353
/// * This attribute mustn't be combined with `CodedBy`
54-
/// attribute.
54+
/// attribute.
5555
/// * If macro has one argument provided:
5656
/// * Attached declaration is an enum-case declaration.
5757
/// * This attribute isn't used combined with `IgnoreCoding`
58-
/// attribute.
58+
/// attribute.
5959
///
6060
/// - Returns: The built diagnoser instance.
6161
func diagnoser() -> DiagnosticProducer {
@@ -70,7 +70,7 @@ struct CodedAs: PropertyAttribute {
7070
else: AggregatedDiagnosticProducer {
7171
expect(syntaxes: EnumDeclSyntax.self)
7272
mustBeCombined(with: Codable.self)
73-
mustBeCombined(with: TaggedAt.self)
73+
mustBeCombined(with: CodedAt.self)
7474
cantBeCombined(with: CodedBy.self)
7575
}
7676
)

Sources/CodableMacroPlugin/Attributes/CodedBy.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct CodedBy: PropertyAttribute {
4040
/// * Macro usage is not duplicated for the same declaration.
4141
/// * If attached declaration is enum declaration:
4242
/// * This attribute must be combined with `Codable`
43-
/// and `TaggedAt` attribute.
43+
/// and `CodedAt` attribute.
4444
/// * This attribute mustn't be combined with `CodedAs`
4545
/// attribute.
4646
/// * If macro has one argument provided:
@@ -58,7 +58,7 @@ struct CodedBy: PropertyAttribute {
5858
isEnum,
5959
AggregatedDiagnosticProducer {
6060
mustBeCombined(with: Codable.self)
61-
mustBeCombined(with: TaggedAt.self)
61+
mustBeCombined(with: CodedAt.self)
6262
cantBeCombined(with: CodedAs.self)
6363
},
6464
else: AggregatedDiagnosticProducer {

Sources/CodableMacroPlugin/Attributes/KeyPath/CodedAt.swift

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct CodedAt: PropertyAttribute {
3535
/// * Macro usage is not duplicated for the same declaration.
3636
/// * If macro is attached to enum declaration:
3737
/// * This attribute must be combined with `Codable`
38-
/// and `TaggedAt` attribute.
38+
/// attribute.
3939
/// * else:
4040
/// * Attached declaration is a variable declaration.
4141
/// * Attached declaration is not a grouped variable
@@ -51,10 +51,7 @@ struct CodedAt: PropertyAttribute {
5151
cantDuplicate()
5252
`if`(
5353
isEnum,
54-
AggregatedDiagnosticProducer {
55-
mustBeCombined(with: Codable.self)
56-
mustBeCombined(with: TaggedAt.self)
57-
},
54+
mustBeCombined(with: Codable.self),
5855
else: AggregatedDiagnosticProducer {
5956
attachedToUngroupedVariable()
6057
attachedToNonStaticVariable()
@@ -65,3 +62,49 @@ struct CodedAt: PropertyAttribute {
6562
}
6663
}
6764
}
65+
66+
extension Registration
67+
where Var == ExternallyTaggedEnumSwitcher, Decl == EnumDeclSyntax {
68+
/// Checks if enum declares internal tagging.
69+
///
70+
/// Checks if identifier path provided with `CodedAt` macro,
71+
/// identifier type is used if `CodedAs` macro provided falling back to
72+
/// the `fallbackType` passed.
73+
///
74+
/// - Parameters:
75+
/// - encodeContainer: The container for case variation encoding.
76+
/// - identifier: The identifier name to use.
77+
/// - fallbackType: The fallback identifier type to use if not provided.
78+
/// - codingKeys: The map where `CodingKeys` maintained.
79+
/// - context: The context in which to perform the macro expansion.
80+
/// - variableBuilder: The builder action for building identifier.
81+
/// - switcherBuilder: The further builder action if check succeeds.
82+
///
83+
/// - Returns: Type-erased variable registration applying builders
84+
/// if succeeds, otherwise current variable type-erased registration.
85+
func checkForInternalTagging<Variable, Switcher>(
86+
encodeContainer: TokenSyntax,
87+
identifier: TokenSyntax, fallbackType: TypeSyntax,
88+
codingKeys: CodingKeysMap, context: some MacroExpansionContext,
89+
variableBuilder: @escaping (
90+
PathRegistration<EnumDeclSyntax, BasicPropertyVariable>
91+
) -> PathRegistration<EnumDeclSyntax, Variable>,
92+
switcherBuilder: @escaping (
93+
Registration<Decl, Key, InternallyTaggedEnumSwitcher<Variable>>
94+
) -> Registration<Decl, Key, Switcher>
95+
) -> Registration<Decl, Key, AnyEnumSwitcher>
96+
where Variable: PropertyVariable, Switcher: EnumSwitcherVariable {
97+
guard
98+
let tagAttr = CodedAt(from: decl)
99+
else { return self.updating(with: variable.any) }
100+
let typeAttr = CodedAs(from: decl)
101+
let variable = InternallyTaggedEnumSwitcher(
102+
encodeContainer: encodeContainer, identifier: identifier,
103+
identifierType: typeAttr?.type ?? fallbackType,
104+
keyPath: tagAttr.keyPath(withExisting: []), codingKeys: codingKeys,
105+
decl: decl, context: context, variableBuilder: variableBuilder
106+
)
107+
let newRegistration = switcherBuilder(self.updating(with: variable))
108+
return newRegistration.updating(with: newRegistration.variable.any)
109+
}
110+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
@_implementationOnly import SwiftDiagnostics
2+
@_implementationOnly import SwiftSyntax
3+
@_implementationOnly import SwiftSyntaxMacros
4+
5+
/// Attribute type for `ContentAt` macro-attribute.
6+
///
7+
/// This type can validate`ContentAt` macro-attribute
8+
/// usage and extract data for `Codable` macro to
9+
/// generate implementation.
10+
struct ContentAt: PropertyAttribute {
11+
/// The node syntax provided
12+
/// during initialization.
13+
let node: AttributeSyntax
14+
15+
/// Creates a new instance with the provided node.
16+
///
17+
/// The initializer fails to create new instance if the name
18+
/// of the provided node is different than this attribute.
19+
///
20+
/// - Parameter node: The attribute syntax to create with.
21+
/// - Returns: Newly created attribute instance.
22+
init?(from node: AttributeSyntax) {
23+
guard
24+
node.attributeName.as(IdentifierTypeSyntax.self)!
25+
.name.text == Self.name
26+
else { return nil }
27+
self.node = node
28+
}
29+
30+
/// Builds diagnoser that can validate this macro
31+
/// attached declaration.
32+
///
33+
/// The following conditions are checked by the
34+
/// built diagnoser:
35+
/// * Attached declaration is an enum declaration.
36+
/// * Macro should be used in presence of `Codable`.
37+
/// * Macro usage is not duplicated for the same
38+
/// declaration.
39+
///
40+
/// - Returns: The built diagnoser instance.
41+
func diagnoser() -> DiagnosticProducer {
42+
return AggregatedDiagnosticProducer {
43+
expect(syntaxes: EnumDeclSyntax.self)
44+
mustBeCombined(with: Codable.self)
45+
mustBeCombined(with: CodedAt.self)
46+
cantDuplicate()
47+
}
48+
}
49+
}
50+
51+
extension ContentAt: KeyPathProvider {
52+
/// Indicates whether `CodingKey` path
53+
/// data is provided to this instance.
54+
///
55+
/// Always `true` for this type.
56+
var provided: Bool { true }
57+
58+
/// Updates `CodingKey` path using the provided path.
59+
///
60+
/// The `CodingKey` path overrides current `CodingKey` path data.
61+
///
62+
/// - Parameter path: Current `CodingKey` path.
63+
/// - Returns: Updated `CodingKey` path.
64+
func keyPath(withExisting path: [String]) -> [String] { providedPath }
65+
}

Sources/CodableMacroPlugin/Attributes/KeyPath/TaggedAt.swift

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

Sources/CodableMacroPlugin/Diagnostics/CombinedUsage.swift

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,4 @@ extension Attribute {
103103
) -> CombinedUsage<Self, Comb> {
104104
return .init(self, cantBeCombinedWith: type)
105105
}
106-
107-
/// Indicates this macro should be used together with
108-
/// the provided attribute.
109-
///
110-
/// The created diagnostic producer produces warning diagnostic,
111-
/// if attribute isn't used together with the provided attribute.
112-
///
113-
/// - Parameter type: The unsupported attribute type.
114-
/// - Returns: Attribute combination usage validation
115-
/// diagnostic producer.
116-
func shouldBeCombined<Comb: Attribute>(
117-
with type: Comb.Type
118-
) -> CombinedUsage<Self, Comb> {
119-
return .init(self, cantBeCombinedWith: type, severity: .warning)
120-
}
121106
}

Sources/CodableMacroPlugin/Diagnostics/Condition/DeclarationCondition.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ extension Attribute {
2929
///
3030
/// Uses `DeclarationCondition` to check syntax type.
3131
var isEnum: DeclarationCondition<EnumDeclSyntax> { .init() }
32-
/// Whether declaration is `actor` declaration.
33-
///
34-
/// Uses `DeclarationCondition` to check syntax type.
35-
var isActor: DeclarationCondition<ActorDeclSyntax> { .init() }
3632
/// Whether declaration is `variable` declaration.
3733
///
3834
/// Uses `DeclarationCondition` to check syntax type.

Sources/CodableMacroPlugin/Diagnostics/Condition/DiagnosticCondition.swift

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,6 @@ protocol DiagnosticCondition {
1414
func satisfied(by syntax: some SyntaxProtocol) -> Bool
1515
}
1616

17-
/// A `DiagnosticCondition` that acts as `AND` operation
18-
/// between two `DiagnosticCondition`s.
19-
///
20-
/// This condition is satisfied only if both conditions are satisfied.
21-
struct AndDiagnosticCondition<L, R>: DiagnosticCondition
22-
where L: DiagnosticCondition, R: DiagnosticCondition {
23-
/// The first condition.
24-
let lhs: L
25-
/// The second condition.
26-
let rhs: R
27-
28-
/// Determines whether provided syntax passes validation.
29-
///
30-
/// This type checks the provided syntax with current data for validation.
31-
/// This condition is satisfied only if both conditions are satisfied.
32-
///
33-
/// - Parameter syntax: The syntax to validate.
34-
/// - Returns: Whether syntax passes validation.
35-
func satisfied(by syntax: some SyntaxProtocol) -> Bool {
36-
return lhs.satisfied(by: syntax) && rhs.satisfied(by: syntax)
37-
}
38-
}
39-
4017
/// A `DiagnosticCondition` that acts as `OR` operation
4118
/// between two `DiagnosticCondition`s.
4219
///
@@ -60,18 +37,6 @@ where L: DiagnosticCondition, R: DiagnosticCondition {
6037
}
6138
}
6239

63-
/// Creates `AndDiagnosticCondition` with provided conditions.
64-
///
65-
/// - Parameters:
66-
/// - lhs: The first condition.
67-
/// - rhs: The second condition.
68-
///
69-
/// - Returns: The resulting condition.
70-
func && <L, R>(lhs: L, rhs: R) -> AndDiagnosticCondition<L, R>
71-
where L: DiagnosticCondition, R: DiagnosticCondition {
72-
return .init(lhs: lhs, rhs: rhs)
73-
}
74-
7540
/// Creates `OrDiagnosticCondition` with provided conditions.
7641
///
7742
/// - Parameters:

0 commit comments

Comments
 (0)