@@ -99,7 +99,7 @@ public struct EquatableMacro: ExtensionMacro {
9999 " WKExtensionDelegateAdaptor "
100100 ]
101101
102- // swiftlint:disable:next cyclomatic_complexity function_body_length
102+ // swiftlint:disable:next function_body_length
103103 public static func expansion(
104104 of node: AttributeSyntax ,
105105 attachedTo declaration: some DeclGroupSyntax ,
@@ -118,53 +118,35 @@ public struct EquatableMacro: ExtensionMacro {
118118 }
119119
120120 // Extract stored properties
121- let storedProperties = structDecl. memberBlock. members. compactMap { member -> ( name: String , type: TypeSyntax ? ) ? in
121+ var storedProperties : [ ( name: String , type: TypeSyntax ? ) ] = [ ]
122+ for member in structDecl. memberBlock. members {
122123 guard let varDecl = member. decl. as ( VariableDeclSyntax . self) ,
123124 let binding = varDecl. bindings. first,
124125 let identifier = binding. pattern. as ( IdentifierPatternSyntax . self) ? . identifier. text,
125- binding. accessorBlock == nil else {
126- return nil
126+ binding. accessorBlock == nil ,
127+ !varDecl. isStatic else {
128+ continue
127129 }
128130
129- // Skip properties with SwiftUI attributes (like @State, @Binding, etc.) or if they are marked with @EqutableIgnored
130131 if Self . shouldSkip ( varDecl) {
131- return nil
132+ continue
132133 }
133134
134- // Skip static properties
135- if varDecl. isStatic {
136- return nil
135+ if isMarkedWithEquatableIgnoredUnsafeClosure ( varDecl) {
136+ continue
137137 }
138138
139- // Skip computed properties
140- let isStoredProperty = binding. accessorBlock == nil
139+ // Check if it's a closure that should trigger diagnostic
140+ let isClosureProperty = ( binding. typeAnnotation? . type) . map ( isClosure) == true ||
141+ ( binding. initializer? . value. is ( ClosureExprSyntax . self) ?? false )
141142
142- if !isStoredProperty {
143- return nil
143+ if isClosureProperty {
144+ let diagnostic = Self . makeClosureDiagnostic ( for: varDecl)
145+ context. diagnose ( diagnostic)
146+ continue
144147 }
145148
146- // if it's a closure marked with @EquatableIgnoredUnsafeClosure allow it but don't compare
147- if isMarkedWithEquatableIgnoredUnsafeClosure ( varDecl) {
148- return nil
149- } else {
150- // If it's a closure and not marked with @EquatableIgnoredUnsafeClosure throw a diagnostic
151- if let typeAnnotation = binding. typeAnnotation? . type {
152- if isClosure ( type: typeAnnotation) {
153- let diagnostic = Self . makeClosureDiagnostic ( for: varDecl)
154- context. diagnose ( diagnostic)
155- return nil
156- }
157- } else if let initializer = binding. initializer? . value {
158- // Check if the initializer is a closure expression
159- if initializer. is ( ClosureExprSyntax . self) {
160- let diagnostic = Self . makeClosureDiagnostic ( for: varDecl)
161- context. diagnose ( diagnostic)
162- return nil
163- }
164- }
165- }
166-
167- return ( name: identifier, type: binding. typeAnnotation? . type)
149+ storedProperties. append ( ( name: identifier, type: binding. typeAnnotation? . type) )
168150 }
169151
170152 // Sort properties: "id" first, then by type complexity
@@ -179,17 +161,14 @@ public struct EquatableMacro: ExtensionMacro {
179161 return [ ]
180162 }
181163
182- // Check if the type conforms to `Hashable`
164+ // If the type conforms to `Hashable`, always generate a corresponding hash function aligned with the `Equatable` implementation
183165 if structDecl. isHashable {
184- // If the type conforms to `Hashable` we need to generate the `Hashable` conformance to match
185- // the properties used in `Equatable` implementation
186166 guard let hashableExtensionSyntax = Self . generateHashableExtensionSyntax (
187167 sortedProperties: sortedProperties,
188168 type: type
189169 ) else {
190170 return [ extensionSyntax]
191171 }
192-
193172 return [ extensionSyntax, hashableExtensionSyntax]
194173 } else {
195174 return [ extensionSyntax]
@@ -244,7 +223,6 @@ extension EquatableMacro {
244223 if let attributeName = attribute. as ( AttributeSyntax . self) ? . attributeName. as ( IdentifierTypeSyntax . self) ? . name. text {
245224 return attributeName == " EquatableIgnoredUnsafeClosure "
246225 }
247-
248226 return false
249227 } )
250228 }
0 commit comments