From f77570035436ff5d4b054c7783401180d2886054 Mon Sep 17 00:00:00 2001 From: Mads Odgaard Date: Tue, 21 Apr 2026 09:14:58 +0200 Subject: [PATCH 1/4] fix doc parsing --- .../SwiftDocumentationParsing.swift | 11 +++- .../SwiftDocumentationParsingTests.swift | 54 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift index dd85a675c..1d4ff09d5 100644 --- a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift +++ b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift @@ -46,8 +46,15 @@ enum SwiftDocumentationParser { var comments = [String]() var pieces = syntax.leadingTrivia.pieces - // We always expect a newline follows a docline comment - while case .newlines(1) = pieces.popLast(), case .docLineComment(let text) = pieces.popLast() { + // Strip trailing indentation (spaces/tabs before the declaration keyword itself) + while case .spaces(_) = pieces.last { pieces.removeLast() } + while case .tabs(_) = pieces.last { pieces.removeLast() } + + // Walk backwards: each doc line is preceded by newlines(1) then optional indentation + while case .newlines(1) = pieces.popLast() { + while case .spaces(_) = pieces.last { pieces.removeLast() } + while case .tabs(_) = pieces.last { pieces.removeLast() } + guard case .docLineComment(let text) = pieces.popLast() else { break } comments.append(text) } diff --git a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift index a605478e7..78fe9f7bd 100644 --- a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift +++ b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift @@ -18,6 +18,60 @@ import Testing @Suite struct SwiftDocumentationParsingTests { + @Test( + "Indented Swift func documentation (inside extension)", + arguments: [ + ( + JExtractGenerationMode.jni, + [ + """ + /** + * Simple summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f() + * } + */ + public static void f() { + """ + ] + ), + ( + JExtractGenerationMode.ffm, + [ + """ + /** + * Simple summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f() + * } + */ + public static void f() { + """ + ] + ), + ] + ) + func indented(mode: JExtractGenerationMode, expectedJavaChunks: [String]) throws { + let text = + """ + public class MyClass { + /// Simple summary + public func f() {} + } + """ + + try assertOutput( + input: text, + mode, + .java, + expectedChunks: expectedJavaChunks + ) + } + @Test( "Simple Swift func documentation", arguments: [ From 95d58d963ac44f6c8370324fa89e81c3b59e7b65 Mon Sep 17 00:00:00 2001 From: Mads Odgaard Date: Tue, 21 Apr 2026 10:19:59 +0200 Subject: [PATCH 2/4] fixes --- .../SwiftDocumentationParsing.swift | 10 ++-- .../SwiftDocumentationParsingTests.swift | 60 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift index 1d4ff09d5..d47f92a4c 100644 --- a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift +++ b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift @@ -50,12 +50,14 @@ enum SwiftDocumentationParser { while case .spaces(_) = pieces.last { pieces.removeLast() } while case .tabs(_) = pieces.last { pieces.removeLast() } - // Walk backwards: each doc line is preceded by newlines(1) then optional indentation + // Walk backwards. The backwards pattern is: + // newlines(1), docLineComment, spaces/tabs(indent), newlines(1), docLineComment, spaces/tabs, … + // Spaces/tabs are stripped *after* consuming each docLineComment (they precede it in source order). while case .newlines(1) = pieces.popLast() { - while case .spaces(_) = pieces.last { pieces.removeLast() } - while case .tabs(_) = pieces.last { pieces.removeLast() } guard case .docLineComment(let text) = pieces.popLast() else { break } comments.append(text) + while case .spaces(_) = pieces.last { pieces.removeLast() } + while case .tabs(_) = pieces.last { pieces.removeLast() } } guard !comments.isEmpty else { return nil } @@ -88,7 +90,7 @@ enum SwiftDocumentationParser { description: content ) ) - state = .parameter(doc.parameters.count > 0 ? doc.parameters.count : 0) + state = .parameter(doc.parameters.count - 1) case "parameters": state = .parameter(0) diff --git a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift index 78fe9f7bd..89df05540 100644 --- a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift +++ b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift @@ -72,6 +72,66 @@ struct SwiftDocumentationParsingTests { ) } + @Test( + "Multi-line parameter description continuation", + arguments: [ + ( + JExtractGenerationMode.jni, + [ + """ + /** + * Summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f(arg0: String) + * } + * + * @param arg0 First line of description. + * Continuation line. + */ + public static void f(java.lang.String arg0) { + """ + ] + ), + ( + JExtractGenerationMode.ffm, + [ + """ + /** + * Summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f(arg0: String) + * } + * + * @param arg0 First line of description. + * Continuation line. + */ + public static void f(java.lang.String arg0) { + """ + ] + ), + ] + ) + func parameterContinuationLine(mode: JExtractGenerationMode, expectedJavaChunks: [String]) throws { + let text = + """ + /// Summary + /// - Parameter arg0: First line of description. + /// Continuation line. + public func f(arg0: String) {} + """ + + try assertOutput( + input: text, + mode, + .java, + expectedChunks: expectedJavaChunks + ) + } + @Test( "Simple Swift func documentation", arguments: [ From 54bfa917ebd07a6e5f1f70a4fedaab12f4367372 Mon Sep 17 00:00:00 2001 From: Mads Odgaard Date: Tue, 21 Apr 2026 10:26:26 +0200 Subject: [PATCH 3/4] add throws support --- .../SwiftDocumentationParsing.swift | 9 +++ .../TranslatedDocumentation.swift | 4 ++ .../SwiftDocumentationParsingTests.swift | 61 +++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift index d47f92a4c..43ccb1ee1 100644 --- a/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift +++ b/Sources/JExtractSwiftLib/SwiftDocumentationParsing.swift @@ -25,6 +25,7 @@ struct SwiftDocumentation: Equatable { var discussion: String? var parameters: [Parameter] = [] var returns: String? + var throwsDescription: String? } enum SwiftDocumentationParser { @@ -33,6 +34,7 @@ enum SwiftDocumentationParser { case discussion case parameter(Int) case returns + case throwsDescription } // TODO: Replace with Regex @@ -99,6 +101,12 @@ enum SwiftDocumentationParser { doc.returns = content state = .returns + case "throws": + if !content.isEmpty { + append(&doc.throwsDescription, content) + } + state = .throwsDescription + default: // Parameter names are marked like // - myString: description @@ -142,6 +150,7 @@ enum SwiftDocumentationParser { case .summary: append(&doc.summary, line) case .discussion: append(&doc.discussion, line) case .returns: append(&doc.returns, line) + case .throwsDescription: append(&doc.throwsDescription, line) case .parameter(let index): if index < doc.parameters.count { append(&doc.parameters[index].description, line) diff --git a/Sources/JExtractSwiftLib/TranslatedDocumentation.swift b/Sources/JExtractSwiftLib/TranslatedDocumentation.swift index 2db9d3270..bab21fdd9 100644 --- a/Sources/JExtractSwiftLib/TranslatedDocumentation.swift +++ b/Sources/JExtractSwiftLib/TranslatedDocumentation.swift @@ -91,6 +91,10 @@ enum TranslatedDocumentation { annotationsGroup.append("@param \(param.name) \(param.description)") } + if let throwsDescription = parsedDocumentation?.throwsDescription { + annotationsGroup.append("@throws Exception \(throwsDescription)") + } + if let returns = parsedDocumentation?.returns { annotationsGroup.append("@return \(returns)") } diff --git a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift index 89df05540..16e3e1c9b 100644 --- a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift +++ b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift @@ -72,6 +72,67 @@ struct SwiftDocumentationParsingTests { ) } + @Test( + "Throws documentation", + arguments: [ + ( + JExtractGenerationMode.jni, + [ + """ + /** + * Summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f() + * } + * + * @throws Exception - An error if something fails. + * - Another error case. + */ + public static void f() { + """ + ] + ), + ( + JExtractGenerationMode.ffm, + [ + """ + /** + * Summary + * + *

Downcall to Swift: + * {@snippet lang=swift : + * public func f() + * } + * + * @throws Exception - An error if something fails. + * - Another error case. + */ + public static void f() { + """ + ] + ), + ] + ) + func throwsDocumentation(mode: JExtractGenerationMode, expectedJavaChunks: [String]) throws { + let text = + """ + /// Summary + /// - Throws: + /// - An error if something fails. + /// - Another error case. + public func f() {} + """ + + try assertOutput( + input: text, + mode, + .java, + expectedChunks: expectedJavaChunks + ) + } + @Test( "Multi-line parameter description continuation", arguments: [ From 94345c83702cd0db4aa2cf7fed4fd28bc5ac2a05 Mon Sep 17 00:00:00 2001 From: Mads Odgaard Date: Tue, 21 Apr 2026 11:15:39 +0200 Subject: [PATCH 4/4] fix tests --- .../JExtractSwiftTests/SwiftDocumentationParsingTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift index 16e3e1c9b..1cd085e6c 100644 --- a/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift +++ b/Tests/JExtractSwiftTests/SwiftDocumentationParsingTests.swift @@ -30,7 +30,7 @@ struct SwiftDocumentationParsingTests { * *

Downcall to Swift: * {@snippet lang=swift : - * public func f() + * public static func f() * } */ public static void f() { @@ -46,7 +46,7 @@ struct SwiftDocumentationParsingTests { * *

Downcall to Swift: * {@snippet lang=swift : - * public func f() + * public static func f() * } */ public static void f() { @@ -60,7 +60,7 @@ struct SwiftDocumentationParsingTests { """ public class MyClass { /// Simple summary - public func f() {} + public static func f() {} } """