Skip to content

Commit 6534b9b

Browse files
authored
[Swiftify] Copy doc comment from clang node (swiftlang#81584)
Swift nodes imported from clang don't have doc comments carried over, but IDEs are clever enough to fetch the comments from the associated clang node. The swift node in the macro expansion from _SwiftifyImport doesn't have a clang node directly associated with it however. This patch adds the same comment from the clang node to the _SwiftifyImport macro invocation node. Since the macro has access to this node, it can easily copy over its leading trivia. For now the comment is not altered at all, meaning @param still remains even if the parmeter is removed. rdar://151346977
1 parent 3ec3421 commit 6534b9b

File tree

11 files changed

+352
-9
lines changed

11 files changed

+352
-9
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9281,10 +9281,28 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
92819281
attachMacro = true;
92829282
printer.printAvailability();
92839283
printer.printTypeMapping(typeMapping);
9284+
92849285
}
92859286

9286-
if (attachMacro)
9287-
importNontrivialAttribute(MappedDecl, MacroString);
9287+
if (attachMacro) {
9288+
if (clang::RawComment *raw =
9289+
getClangASTContext().getRawCommentForDeclNoCache(ClangDecl)) {
9290+
// swift::RawDocCommentAttr doesn't contain its text directly, but instead
9291+
// references the source range of the parsed comment. Instead of creating
9292+
// a new source file just to parse the doc comment, we can add the
9293+
// comment to the macro invocation attribute, which the macro has access
9294+
// to. Waiting until we know that the macro will be attached before
9295+
// emitting the comment to the string, despite the comment occurring
9296+
// first, avoids copying a bunch of potentially long comments for nodes
9297+
// that don't end up with wrappers.
9298+
auto commentString =
9299+
raw->getRawText(getClangASTContext().getSourceManager());
9300+
importNontrivialAttribute(MappedDecl,
9301+
(commentString + "\n" + MacroString).str());
9302+
} else {
9303+
importNontrivialAttribute(MappedDecl, MacroString);
9304+
}
9305+
}
92889306
}
92899307

92909308
static bool isUsingMacroName(clang::SourceManager &SM,

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,7 @@ public struct SwiftifyImportMacro: PeerMacro {
15501550
+ availabilityAttr
15511551
+ lifetimeAttrs
15521552
+ disfavoredOverload)
1553+
.with(\.leadingTrivia, node.leadingTrivia + .docLineComment("/// This is an auto-generated wrapper for safer interop\n"))
15531554
return [DeclSyntax(newFunc)]
15541555
} catch let error as DiagnosticError {
15551556
context.diagnose(
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#define __counted_by(x) __attribute__((__counted_by__(x)))
4+
5+
void begin();
6+
7+
// line comment
8+
void lineComment(int len, int * __counted_by(len) p);
9+
10+
/// line doc comment
11+
///
12+
/// Here's a more complete description.
13+
///
14+
/// @param len the buffer length
15+
/// @param p the buffer
16+
void lineDocComment(int len, int * __counted_by(len) p);
17+
18+
/*
19+
block comment
20+
*/
21+
void blockComment(int len, int * __counted_by(len) p);
22+
23+
/**
24+
* block doc comment
25+
*
26+
* NB: it's very important to pass the correct length to this function
27+
* @param len don't mess this one up
28+
* @param p some integers to play with
29+
*/
30+
void blockDocComment(int len, int * __counted_by(len) p);

test/Interop/C/swiftify-import/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ module SizedByNoEscapeClang {
1414
header "sized-by-noescape.h"
1515
export *
1616
}
17+
module CommentsClang {
18+
header "comments.h"
19+
export *
20+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: %target-swift-ide-test -print-module -module-to-print=CommentsClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s --strict-whitespace --match-full-lines
4+
5+
// Check that doc comments are carried over from clang to the safe macro expansion.
6+
7+
// CHECK:func begin()
8+
// CHECK-NEXT:func lineComment(_ len: Int32, _ p: UnsafeMutablePointer<Int32>!)
9+
10+
// CHECK-NEXT:/// line doc comment
11+
// CHECK-NEXT:///
12+
// CHECK-NEXT:/// Here's a more complete description.
13+
// CHECK-NEXT:///
14+
// CHECK-NEXT:/// @param len the buffer length
15+
// CHECK-NEXT:/// @param p the buffer
16+
// CHECK-NEXT:func lineDocComment(_ len: Int32, _ p: UnsafeMutablePointer<Int32>!)
17+
18+
// CHECK-NEXT:func blockComment(_ len: Int32, _ p: UnsafeMutablePointer<Int32>!)
19+
20+
// CHECK-NEXT:/**
21+
// CHECK-NEXT: * block doc comment
22+
// CHECK-NEXT: *
23+
// CHECK-NEXT: * NB: it's very important to pass the correct length to this function
24+
// CHECK-NEXT: * @param len don't mess this one up
25+
// CHECK-NEXT: * @param p some integers to play with
26+
// CHECK-NEXT: */
27+
// CHECK-NEXT:func blockDocComment(_ len: Int32, _ p: UnsafeMutablePointer<Int32>!)
28+
29+
// CHECK-NEXT:/// This is an auto-generated wrapper for safer interop
30+
// CHECK-NEXT:@_alwaysEmitIntoClient public func blockComment(_ p: UnsafeMutableBufferPointer<Int32>)
31+
32+
// CHECK-NEXT:/**
33+
// CHECK-NEXT: * block doc comment
34+
// CHECK-NEXT: *
35+
// CHECK-NEXT: * NB: it's very important to pass the correct length to this function
36+
// CHECK-NEXT: * @param len don't mess this one up
37+
// CHECK-NEXT: * @param p some integers to play with
38+
// CHECK-NEXT: */
39+
// CHECK-NEXT:/// This is an auto-generated wrapper for safer interop
40+
// CHECK-NEXT:@_alwaysEmitIntoClient public func blockDocComment(_ p: UnsafeMutableBufferPointer<Int32>)
41+
42+
// CHECK-NEXT:/// This is an auto-generated wrapper for safer interop
43+
// CHECK-NEXT:@_alwaysEmitIntoClient public func lineComment(_ p: UnsafeMutableBufferPointer<Int32>)
44+
45+
// CHECK-NEXT:/// line doc comment
46+
// CHECK-NEXT:///
47+
// CHECK-NEXT:/// Here's a more complete description.
48+
// CHECK-NEXT:///
49+
// CHECK-NEXT:/// @param len the buffer length
50+
// CHECK-NEXT:/// @param p the buffer
51+
// CHECK-NEXT:/// This is an auto-generated wrapper for safer interop
52+
// CHECK-NEXT:@_alwaysEmitIntoClient public func lineDocComment(_ p: UnsafeMutableBufferPointer<Int32>)

test/Interop/C/swiftify-import/counted-by-noescape.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,52 @@
1111

1212
import CountedByNoEscapeClang
1313

14-
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
14+
// CHECK: /// This is an auto-generated wrapper for safer interop
15+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1516
// CHECK-NEXT: @lifetime(_param1: copy _param1)
1617
// CHECK-NEXT: @_alwaysEmitIntoClient public func anonymous(_ _param1: inout MutableSpan<Int32>?)
17-
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
18+
19+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
20+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1821
// CHECK-NEXT: @lifetime(p: copy p)
1922
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int32, _ offset: Int32, _ p: inout MutableSpan<Int32>)
23+
24+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2025
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2126
// CHECK-NEXT: @lifetime(p: copy p)
2227
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: inout MutableSpan<Int32>)
28+
29+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2330
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2431
// CHECK-NEXT: @lifetime(p: copy p)
2532
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: inout MutableSpan<Int32>)
33+
34+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2635
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2736
// CHECK-NEXT: @lifetime(p: copy p)
2837
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: inout MutableSpan<Int32>?)
38+
39+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2940
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3041
// CHECK-NEXT: @lifetime(copy p)
3142
// CHECK-NEXT: @lifetime(p: copy p)
3243
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnLifetimeBound(_ len1: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
44+
45+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
3346
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int32) -> UnsafeMutableBufferPointer<Int32>
47+
48+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
3449
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3550
// CHECK-NEXT: @lifetime(p1: copy p1)
3651
// CHECK-NEXT: @lifetime(p2: copy p2)
3752
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int32, _ p1: inout MutableSpan<Int32>, _ p2: inout MutableSpan<Int32>)
53+
54+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
3855
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3956
// CHECK-NEXT: @lifetime(p: copy p)
4057
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: inout MutableSpan<Int32>)
58+
59+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
4160
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
4261
// CHECK-NEXT: @lifetime(p: copy p)
4362
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: inout MutableSpan<Int32>)

test/Interop/C/swiftify-import/counted-by.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,59 @@
1010

1111
import CountedByClang
1212

13-
// CHECK: @_alwaysEmitIntoClient public func bitshift(_ m: Int32, _ n: Int32, _ o: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
13+
14+
// CHECK: /// This is an auto-generated wrapper for safer interop
15+
// CHECK-NEXT: @_alwaysEmitIntoClient public func bitshift(_ m: Int32, _ n: Int32, _ o: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
16+
17+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1418
// CHECK-NEXT: @_alwaysEmitIntoClient public func bitwise(_ m: Int32, _ n: Int32, _ o: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
19+
20+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1521
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableBufferPointer<Int{{.*}}>)
22+
23+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1624
// CHECK-NEXT: @_alwaysEmitIntoClient public func constFloatCastedToInt(_ p: UnsafeMutableBufferPointer<Int32>)
25+
26+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1727
// CHECK-NEXT: @_alwaysEmitIntoClient public func constInt(_ p: UnsafeMutableBufferPointer<Int32>)
28+
29+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1830
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
31+
32+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1933
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
34+
35+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2036
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableBufferPointer<Int{{.*}}>?)
37+
38+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2139
// CHECK-NEXT: @_alwaysEmitIntoClient public func offByOne(_ len: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
40+
41+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2242
// CHECK-NEXT: @_alwaysEmitIntoClient public func offBySome(_ len: Int32, _ offset: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
43+
44+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2345
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
46+
47+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2448
// CHECK-NEXT: @_alwaysEmitIntoClient public func scalar(_ m: Int32, _ n: Int32, _ p: UnsafeMutableBufferPointer<Int32>)
49+
50+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2551
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableBufferPointer<Int{{.*}}>, _ p2: UnsafeMutableBufferPointer<Int{{.*}}>)
52+
53+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2654
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
55+
56+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2757
// CHECK-NEXT: @_alwaysEmitIntoClient public func simpleFlipped(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
58+
59+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2860
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofParam(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
61+
62+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2963
// CHECK-NEXT: @_alwaysEmitIntoClient public func sizeofType(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
64+
65+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
3066
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
3167

3268
@inlinable

test/Interop/C/swiftify-import/sized-by-noescape.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,39 @@
99
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __noescape parameters.
1010
import SizedByNoEscapeClang
1111

12-
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
12+
13+
// CHECK: /// This is an auto-generated wrapper for safer interop
14+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1315
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
16+
17+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1418
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1519
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
20+
21+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1622
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1723
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
24+
25+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1826
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1927
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: RawSpan?)
28+
29+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2030
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2131
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
32+
33+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2234
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
35+
36+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2337
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2438
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
39+
40+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2541
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2642
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
43+
44+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2745
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2846
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)
2947

test/Interop/C/swiftify-import/sized-by.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,32 @@
99
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by parameters.
1010
import SizedByClang
1111

12-
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableRawBufferPointer)
12+
13+
// CHECK: /// This is an auto-generated wrapper for safer interop
14+
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: UnsafeMutableRawBufferPointer)
15+
16+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1317
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: UnsafeMutableRawBufferPointer)
18+
19+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1420
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableRawBufferPointer)
21+
22+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1523
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableRawBufferPointer?)
24+
25+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1626
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: UnsafeRawBufferPointer)
27+
28+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1729
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableRawBufferPointer
30+
31+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1832
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableRawBufferPointer, _ p2: UnsafeMutableRawBufferPointer)
33+
34+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
1935
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableRawBufferPointer)
36+
37+
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2038
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableRawBufferPointer)
2139

2240
@inlinable

0 commit comments

Comments
 (0)