From 9a838bf7b89cc53d9dc0a8ed5d255f8a210d762f Mon Sep 17 00:00:00 2001 From: Iceman Date: Thu, 5 Dec 2024 16:06:19 +0900 Subject: [PATCH 1/4] Fix annotation cannot detect when attributes attached above it --- .../Parsers/SwiftSyntaxExtensions.swift | 5 +++-- Tests/TestActor/ActorTests.swift | 5 +++++ Tests/TestActor/FixtureGlobalActor.swift | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index 62410e25..dbfc65a0 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -670,6 +670,7 @@ final class EntityVisitor: SyntaxVisitor { override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { let metadata = node.annotationMetadata(with: annotation) + ?? node.protocolKeyword.leadingTrivia.annotationMetadata(with: annotation) if let ent = Entity.node(with: node, filepath: path, isPrivate: node.isPrivate, isFinal: false, metadata: metadata, processed: false) { entities.append(ent) } @@ -863,9 +864,9 @@ extension Trivia { // See metadata(with:, in:) for more info on the annotation arguments. func annotationMetadata(with annotation: String) -> AnnotationMetadata? { guard !annotation.isEmpty else { return nil } + var ret: AnnotationMetadata? - for i in 0.. Date: Thu, 5 Dec 2024 16:10:33 +0900 Subject: [PATCH 2/4] Fix fragile output --- Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index dbfc65a0..c0014e6a 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -259,7 +259,7 @@ extension IfConfigDeclSyntax { in: subModels, exclude: [:], fullnames: [] - ).map({ $0 }) + ).sorted(path: \.value.offset, fallback: \.key) let macroModel = IfMacroModel(name: name, offset: self.offset, entities: uniqueSubModels) return (macroModel, attrDesc, hasInit) From 7c7241a4990e03fe3d8fec4a7a7dcd6be7043ef7 Mon Sep 17 00:00:00 2001 From: Iceman Date: Fri, 6 Dec 2024 09:56:59 +0900 Subject: [PATCH 3/4] Also support class --- .../Parsers/SwiftSyntaxExtensions.swift | 5 ++--- Tests/TestActor/ActorTests.swift | 3 ++- Tests/TestActor/FixtureGlobalActor.swift | 13 ++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index c0014e6a..7d320108 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -300,7 +300,7 @@ extension ProtocolDeclSyntax: EntityNode { } func annotationMetadata(with annotation: String) -> AnnotationMetadata? { - return leadingTrivia.annotationMetadata(with: annotation) + return leadingTrivia.annotationMetadata(with: annotation) ?? protocolKeyword.leadingTrivia.annotationMetadata(with: annotation) } var hasBlankInit: Bool { @@ -358,7 +358,7 @@ extension ClassDeclSyntax: EntityNode { } func annotationMetadata(with annotation: String) -> AnnotationMetadata? { - return leadingTrivia.annotationMetadata(with: annotation) + return leadingTrivia.annotationMetadata(with: annotation) ?? classKeyword.leadingTrivia.annotationMetadata(with: annotation) } func subContainer(metadata: AnnotationMetadata?, declKind: NominalTypeDeclKind, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { @@ -670,7 +670,6 @@ final class EntityVisitor: SyntaxVisitor { override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { let metadata = node.annotationMetadata(with: annotation) - ?? node.protocolKeyword.leadingTrivia.annotationMetadata(with: annotation) if let ent = Entity.node(with: node, filepath: path, isPrivate: node.isPrivate, isFinal: false, metadata: metadata, processed: false) { entities.append(ent) } diff --git a/Tests/TestActor/ActorTests.swift b/Tests/TestActor/ActorTests.swift index 5615aa58..2f195c84 100644 --- a/Tests/TestActor/ActorTests.swift +++ b/Tests/TestActor/ActorTests.swift @@ -16,6 +16,7 @@ final class ActorTests: MockoloTestCase { func testAttributeAboveAnnotationComment() { verify(srcContent: attributeAboveAnnotationComment, - dstContent: attributeAboveAnnotationCommentMock) + dstContent: attributeAboveAnnotationCommentMock, + declType: .all) } } diff --git a/Tests/TestActor/FixtureGlobalActor.swift b/Tests/TestActor/FixtureGlobalActor.swift index 340207aa..f9745326 100644 --- a/Tests/TestActor/FixtureGlobalActor.swift +++ b/Tests/TestActor/FixtureGlobalActor.swift @@ -48,14 +48,21 @@ class RootBuildableMock: RootBuildable { let attributeAboveAnnotationComment = """ @MainActor /// \(String.mockAnnotation) -protocol AttributeAboveAnnotationComment { +protocol AttributeAboveAnnotationCommentProtocol { +} + +@MainActor +/// \(String.mockAnnotation) +class AttributeAboveAnnotationCommentClass { } """ let attributeAboveAnnotationCommentMock = """ -class AttributeAboveAnnotationCommentMock: AttributeAboveAnnotationComment { +class AttributeAboveAnnotationCommentProtocolMock: AttributeAboveAnnotationCommentProtocol { init() { } +} - +class AttributeAboveAnnotationCommentClassMock: AttributeAboveAnnotationCommentClass { + init() { } } """ From b95cd120cff3002338215cdea89ae1cc506b5226 Mon Sep 17 00:00:00 2001 From: kenta okamura Date: Sat, 7 Dec 2024 19:47:49 +0900 Subject: [PATCH 4/4] search more trivia --- .../Parsers/SwiftSyntaxExtensions.swift | 15 +++++++++++++-- Tests/TestActor/FixtureGlobalActor.swift | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift index 7d320108..add245d7 100644 --- a/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift +++ b/Sources/MockoloFramework/Parsers/SwiftSyntaxExtensions.swift @@ -14,6 +14,7 @@ // limitations under the License. // +import Algorithms import Foundation import SwiftSyntax import SwiftParser @@ -300,7 +301,12 @@ extension ProtocolDeclSyntax: EntityNode { } func annotationMetadata(with annotation: String) -> AnnotationMetadata? { - return leadingTrivia.annotationMetadata(with: annotation) ?? protocolKeyword.leadingTrivia.annotationMetadata(with: annotation) + let trivias = [ + leadingTrivia, + protocolKeyword.leadingTrivia, + modifiers.leadingTrivia, + ] + attributes.map(\.leadingTrivia) + return trivias.firstNonNil { $0.annotationMetadata(with: annotation) } } var hasBlankInit: Bool { @@ -358,7 +364,12 @@ extension ClassDeclSyntax: EntityNode { } func annotationMetadata(with annotation: String) -> AnnotationMetadata? { - return leadingTrivia.annotationMetadata(with: annotation) ?? classKeyword.leadingTrivia.annotationMetadata(with: annotation) + let trivias = [ + leadingTrivia, + classKeyword.leadingTrivia, + modifiers.leadingTrivia, + ] + attributes.map(\.leadingTrivia) + return trivias.firstNonNil { $0.annotationMetadata(with: annotation) } } func subContainer(metadata: AnnotationMetadata?, declKind: NominalTypeDeclKind, path: String?, isProcessed: Bool) -> EntityNodeSubContainer { diff --git a/Tests/TestActor/FixtureGlobalActor.swift b/Tests/TestActor/FixtureGlobalActor.swift index f9745326..288485a1 100644 --- a/Tests/TestActor/FixtureGlobalActor.swift +++ b/Tests/TestActor/FixtureGlobalActor.swift @@ -48,21 +48,30 @@ class RootBuildableMock: RootBuildable { let attributeAboveAnnotationComment = """ @MainActor /// \(String.mockAnnotation) -protocol AttributeAboveAnnotationCommentProtocol { +protocol P0 { } @MainActor /// \(String.mockAnnotation) -class AttributeAboveAnnotationCommentClass { +@available(iOS 18.0, *) protocol P1 { +} + +@MainActor +/// \(String.mockAnnotation) +public class C0 { } """ let attributeAboveAnnotationCommentMock = """ -class AttributeAboveAnnotationCommentProtocolMock: AttributeAboveAnnotationCommentProtocol { +class P0Mock: P0 { init() { } } -class AttributeAboveAnnotationCommentClassMock: AttributeAboveAnnotationCommentClass { +class P1Mock: P1 { init() { } } + +public class C0Mock: C0 { + public init() { } +} """