Skip to content

Commit

Permalink
fix: fixed empty CodingKeys enum generated instead of being skipped
Browse files Browse the repository at this point in the history
  • Loading branch information
soumyamahunt committed Jan 9, 2024
1 parent 97a6057 commit a28bb9c
Show file tree
Hide file tree
Showing 40 changed files with 1,111 additions and 1,144 deletions.
5 changes: 0 additions & 5 deletions Sources/CodableMacroPlugin/Attributes/Attribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ extension Attribute {
/// This attribute can must be removed or its usage condition
/// must be satisfied.
var misuseMessageID: MessageID { messageID("\(id)-misuse") }
/// Message id for unnecessary usage of this attribute.
///
/// This attribute can be omitted in such scenario and the
/// final result will still be the same.
var unusedMessageID: MessageID { messageID("\(id)-unused") }

/// Creates a new message id in current package domain.
///
Expand Down
8 changes: 4 additions & 4 deletions Sources/CodableMacroPlugin/Attributes/CodedAs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ struct CodedAs: PropertyAttribute {
/// * If macro has zero arguments provided:
/// * Attached declaration is an enum declaration.
/// * This attribute must be combined with `Codable`
/// and `TaggedAt` attribute.
/// and `CodedAt` attribute.
/// * This attribute mustn't be combined with `CodedBy`
/// attribute.
/// attribute.
/// * If macro has one argument provided:
/// * Attached declaration is an enum-case declaration.
/// * This attribute isn't used combined with `IgnoreCoding`
/// attribute.
/// attribute.
///
/// - Returns: The built diagnoser instance.
func diagnoser() -> DiagnosticProducer {
Expand All @@ -70,7 +70,7 @@ struct CodedAs: PropertyAttribute {
else: AggregatedDiagnosticProducer {
expect(syntaxes: EnumDeclSyntax.self)
mustBeCombined(with: Codable.self)
mustBeCombined(with: TaggedAt.self)
mustBeCombined(with: CodedAt.self)
cantBeCombined(with: CodedBy.self)
}
)
Expand Down
4 changes: 2 additions & 2 deletions Sources/CodableMacroPlugin/Attributes/CodedBy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct CodedBy: PropertyAttribute {
/// * Macro usage is not duplicated for the same declaration.
/// * If attached declaration is enum declaration:
/// * This attribute must be combined with `Codable`
/// and `TaggedAt` attribute.
/// and `CodedAt` attribute.
/// * This attribute mustn't be combined with `CodedAs`
/// attribute.
/// * If macro has one argument provided:
Expand All @@ -58,7 +58,7 @@ struct CodedBy: PropertyAttribute {
isEnum,
AggregatedDiagnosticProducer {
mustBeCombined(with: Codable.self)
mustBeCombined(with: TaggedAt.self)
mustBeCombined(with: CodedAt.self)
cantBeCombined(with: CodedAs.self)
},
else: AggregatedDiagnosticProducer {
Expand Down
53 changes: 48 additions & 5 deletions Sources/CodableMacroPlugin/Attributes/KeyPath/CodedAt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct CodedAt: PropertyAttribute {
/// * Macro usage is not duplicated for the same declaration.
/// * If macro is attached to enum declaration:
/// * This attribute must be combined with `Codable`
/// and `TaggedAt` attribute.
/// attribute.
/// * else:
/// * Attached declaration is a variable declaration.
/// * Attached declaration is not a grouped variable
Expand All @@ -51,10 +51,7 @@ struct CodedAt: PropertyAttribute {
cantDuplicate()
`if`(
isEnum,
AggregatedDiagnosticProducer {
mustBeCombined(with: Codable.self)
mustBeCombined(with: TaggedAt.self)
},
mustBeCombined(with: Codable.self),
else: AggregatedDiagnosticProducer {
attachedToUngroupedVariable()
attachedToNonStaticVariable()
Expand All @@ -65,3 +62,49 @@ struct CodedAt: PropertyAttribute {
}
}
}

extension Registration
where Var == ExternallyTaggedEnumSwitcher, Decl == EnumDeclSyntax {
/// Checks if enum declares internal tagging.
///
/// Checks if identifier path provided with `CodedAt` macro,
/// identifier type is used if `CodedAs` macro provided falling back to
/// the `fallbackType` passed.
///
/// - Parameters:
/// - encodeContainer: The container for case variation encoding.
/// - identifier: The identifier name to use.
/// - fallbackType: The fallback identifier type to use if not provided.
/// - codingKeys: The map where `CodingKeys` maintained.
/// - context: The context in which to perform the macro expansion.
/// - variableBuilder: The builder action for building identifier.
/// - switcherBuilder: The further builder action if check succeeds.
///
/// - Returns: Type-erased variable registration applying builders
/// if succeeds, otherwise current variable type-erased registration.
func checkForInternalTagging<Variable, Switcher>(
encodeContainer: TokenSyntax,
identifier: TokenSyntax, fallbackType: TypeSyntax,
codingKeys: CodingKeysMap, context: some MacroExpansionContext,
variableBuilder: @escaping (
PathRegistration<EnumDeclSyntax, BasicPropertyVariable>
) -> PathRegistration<EnumDeclSyntax, Variable>,
switcherBuilder: @escaping (
Registration<Decl, Key, InternallyTaggedEnumSwitcher<Variable>>
) -> Registration<Decl, Key, Switcher>
) -> Registration<Decl, Key, AnyEnumSwitcher>
where Variable: PropertyVariable, Switcher: EnumSwitcherVariable {
guard
let tagAttr = CodedAt(from: decl)
else { return self.updating(with: variable.any) }
let typeAttr = CodedAs(from: decl)
let variable = InternallyTaggedEnumSwitcher(
encodeContainer: encodeContainer, identifier: identifier,
identifierType: typeAttr?.type ?? fallbackType,
keyPath: tagAttr.keyPath(withExisting: []), codingKeys: codingKeys,
decl: decl, context: context, variableBuilder: variableBuilder
)
let newRegistration = switcherBuilder(self.updating(with: variable))
return newRegistration.updating(with: newRegistration.variable.any)
}
}
65 changes: 65 additions & 0 deletions Sources/CodableMacroPlugin/Attributes/KeyPath/ContentAt.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@_implementationOnly import SwiftDiagnostics
@_implementationOnly import SwiftSyntax
@_implementationOnly import SwiftSyntaxMacros

/// Attribute type for `ContentAt` macro-attribute.
///
/// This type can validate`ContentAt` macro-attribute
/// usage and extract data for `Codable` macro to
/// generate implementation.
struct ContentAt: PropertyAttribute {
/// The node syntax provided
/// during initialization.
let node: AttributeSyntax

/// Creates a new instance with the provided node.
///
/// The initializer fails to create new instance if the name
/// of the provided node is different than this attribute.
///
/// - Parameter node: The attribute syntax to create with.
/// - Returns: Newly created attribute instance.
init?(from node: AttributeSyntax) {
guard
node.attributeName.as(IdentifierTypeSyntax.self)!
.name.text == Self.name
else { return nil }
self.node = node
}

/// Builds diagnoser that can validate this macro
/// attached declaration.
///
/// The following conditions are checked by the
/// built diagnoser:
/// * Attached declaration is an enum declaration.
/// * Macro should be used in presence of `Codable`.
/// * Macro usage is not duplicated for the same
/// declaration.
///
/// - Returns: The built diagnoser instance.
func diagnoser() -> DiagnosticProducer {
return AggregatedDiagnosticProducer {
expect(syntaxes: EnumDeclSyntax.self)
mustBeCombined(with: Codable.self)
mustBeCombined(with: CodedAt.self)
cantDuplicate()
}
}
}

extension ContentAt: KeyPathProvider {
/// Indicates whether `CodingKey` path
/// data is provided to this instance.
///
/// Always `true` for this type.
var provided: Bool { true }

/// Updates `CodingKey` path using the provided path.
///
/// The `CodingKey` path overrides current `CodingKey` path data.
///
/// - Parameter path: Current `CodingKey` path.
/// - Returns: Updated `CodingKey` path.
func keyPath(withExisting path: [String]) -> [String] { providedPath }
}
110 changes: 0 additions & 110 deletions Sources/CodableMacroPlugin/Attributes/KeyPath/TaggedAt.swift

This file was deleted.

15 changes: 0 additions & 15 deletions Sources/CodableMacroPlugin/Diagnostics/CombinedUsage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,4 @@ extension Attribute {
) -> CombinedUsage<Self, Comb> {
return .init(self, cantBeCombinedWith: type)
}

/// Indicates this macro should be used together with
/// the provided attribute.
///
/// The created diagnostic producer produces warning diagnostic,
/// if attribute isn't used together with the provided attribute.
///
/// - Parameter type: The unsupported attribute type.
/// - Returns: Attribute combination usage validation
/// diagnostic producer.
func shouldBeCombined<Comb: Attribute>(
with type: Comb.Type
) -> CombinedUsage<Self, Comb> {
return .init(self, cantBeCombinedWith: type, severity: .warning)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ extension Attribute {
///
/// Uses `DeclarationCondition` to check syntax type.
var isEnum: DeclarationCondition<EnumDeclSyntax> { .init() }
/// Whether declaration is `actor` declaration.
///
/// Uses `DeclarationCondition` to check syntax type.
var isActor: DeclarationCondition<ActorDeclSyntax> { .init() }
/// Whether declaration is `variable` declaration.
///
/// Uses `DeclarationCondition` to check syntax type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,6 @@ protocol DiagnosticCondition {
func satisfied(by syntax: some SyntaxProtocol) -> Bool
}

/// A `DiagnosticCondition` that acts as `AND` operation
/// between two `DiagnosticCondition`s.
///
/// This condition is satisfied only if both conditions are satisfied.
struct AndDiagnosticCondition<L, R>: DiagnosticCondition
where L: DiagnosticCondition, R: DiagnosticCondition {
/// The first condition.
let lhs: L
/// The second condition.
let rhs: R

/// Determines whether provided syntax passes validation.
///
/// This type checks the provided syntax with current data for validation.
/// This condition is satisfied only if both conditions are satisfied.
///
/// - Parameter syntax: The syntax to validate.
/// - Returns: Whether syntax passes validation.
func satisfied(by syntax: some SyntaxProtocol) -> Bool {
return lhs.satisfied(by: syntax) && rhs.satisfied(by: syntax)
}
}

/// A `DiagnosticCondition` that acts as `OR` operation
/// between two `DiagnosticCondition`s.
///
Expand All @@ -60,18 +37,6 @@ where L: DiagnosticCondition, R: DiagnosticCondition {
}
}

/// Creates `AndDiagnosticCondition` with provided conditions.
///
/// - Parameters:
/// - lhs: The first condition.
/// - rhs: The second condition.
///
/// - Returns: The resulting condition.
func && <L, R>(lhs: L, rhs: R) -> AndDiagnosticCondition<L, R>
where L: DiagnosticCondition, R: DiagnosticCondition {
return .init(lhs: lhs, rhs: rhs)
}

/// Creates `OrDiagnosticCondition` with provided conditions.
///
/// - Parameters:
Expand Down

0 comments on commit a28bb9c

Please sign in to comment.