Skip to content

Commit 14c79d2

Browse files
committed
[ClangImporter] don't emit empty .method()
This updates SwiftifyImportProtocolPrinter such that it no longer emits anything for methods without bounds or lifetime info. Previously we would not attach the macro if no methods in the protocol contained bounds or lifetime info. However if one of the methods did, we would still emit `.method(signature: "func foo()", paramInfo: [])` for the methods without bounds of lifetime info. This would result in overloads being generated, like so: ``` @_alwaysEmitIntoClient @_disfavoredOverload public func foo() { return unsafe foo() } ``` As part of this change, SwiftifyImportPrinter is now an abstract parent type for SwiftifyImportProtocolPrinter, and the new SwiftifyImportFunctionPrinter. Instead of SwiftifyImportProtocolPrinter inheriting the function printing, `printMethod` instead creates a new SwiftifyImportFunctionPrinter each time, with a new output string. If it output anything interesting the result is forwarded, otherwise it is discarded.
1 parent 48ad528 commit 14c79d2

File tree

2 files changed

+190
-79
lines changed

2 files changed

+190
-79
lines changed

lib/ClangImporter/SwiftifyDecl.cpp

Lines changed: 93 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -42,74 +42,25 @@ ValueDecl *getKnownSingleDecl(ASTContext &SwiftContext, StringRef DeclName) {
4242
return decls[0];
4343
}
4444

45-
class SwiftifyInfoPrinter {
46-
public:
45+
struct SwiftifyInfoPrinter {
4746
static const ssize_t SELF_PARAM_INDEX = -2;
4847
static const ssize_t RETURN_VALUE_INDEX = -1;
4948
clang::ASTContext &ctx;
5049
ASTContext &SwiftContext;
51-
llvm::raw_ostream &out;
50+
llvm::raw_svector_ostream &out;
5251
MacroDecl &SwiftifyImportDecl;
5352
bool firstParam = true;
54-
llvm::StringMap<std::string> typeMapping;
53+
llvm::StringMap<std::string> &typeMapping;
5554

55+
protected:
5656
SwiftifyInfoPrinter(clang::ASTContext &ctx, ASTContext &SwiftContext,
57-
llvm::raw_ostream &out, MacroDecl &SwiftifyImportDecl)
57+
llvm::raw_svector_ostream &out,
58+
MacroDecl &SwiftifyImportDecl,
59+
llvm::StringMap<std::string> &typeMapping)
5860
: ctx(ctx), SwiftContext(SwiftContext), out(out),
59-
SwiftifyImportDecl(SwiftifyImportDecl) {
60-
out << "(";
61-
}
62-
~SwiftifyInfoPrinter() { out << ")"; }
63-
64-
void printCountedBy(const clang::CountAttributedType *CAT,
65-
ssize_t pointerIndex) {
66-
printSeparator();
67-
clang::Expr *countExpr = CAT->getCountExpr();
68-
bool isSizedBy = CAT->isCountInBytes();
69-
out << ".";
70-
if (isSizedBy)
71-
out << "sizedBy";
72-
else
73-
out << "countedBy";
74-
out << "(pointer: ";
75-
printParamOrReturn(pointerIndex);
76-
out << ", ";
77-
if (isSizedBy)
78-
out << "size";
79-
else
80-
out << "count";
81-
out << ": \"";
82-
countExpr->printPretty(
83-
out, {}, {ctx.getLangOpts()}); // TODO: map clang::Expr to Swift Expr
84-
out << "\")";
85-
}
86-
87-
void printNonEscaping(int idx) {
88-
printSeparator();
89-
out << ".nonescaping(pointer: ";
90-
printParamOrReturn(idx);
91-
out << ")";
92-
}
93-
94-
void printLifetimeboundReturn(int idx, bool borrow) {
95-
printSeparator();
96-
out << ".lifetimeDependence(dependsOn: ";
97-
printParamOrReturn(idx);
98-
out << ", pointer: .return, type: ";
99-
out << (borrow ? ".borrow" : ".copy");
100-
out << ")";
101-
}
102-
103-
bool registerStdSpanTypeMapping(Type swiftType, const clang::QualType clangType) {
104-
const auto *decl = clangType->getAsTagDecl();
105-
if (decl && decl->isInStdNamespace() && decl->getName() == "span") {
106-
typeMapping.insert(std::make_pair(
107-
swiftType->getString(), swiftType->getDesugaredType()->getString()));
108-
return true;
109-
}
110-
return false;
111-
}
61+
SwiftifyImportDecl(SwiftifyImportDecl), typeMapping(typeMapping) {}
11262

63+
public:
11364
void printTypeMapping() {
11465
printSeparator();
11566
out << "typeMappings: [";
@@ -130,7 +81,6 @@ class SwiftifyInfoPrinter {
13081
out << "spanAvailability: ";
13182
printAvailabilityOfType("Span");
13283
}
133-
13484
private:
13585
bool hasMacroParameter(StringRef ParamName) {
13686
for (auto *Param : *SwiftifyImportDecl.parameterList)
@@ -160,6 +110,63 @@ class SwiftifyInfoPrinter {
160110
firstParam = false;
161111
}
162112
}
113+
};
114+
115+
struct SwiftifyInfoFunctionPrinter : public SwiftifyInfoPrinter {
116+
SwiftifyInfoFunctionPrinter(clang::ASTContext &ctx, ASTContext &SwiftContext,
117+
llvm::raw_svector_ostream &out,
118+
MacroDecl &SwiftifyImportDecl,
119+
llvm::StringMap<std::string> &typeMapping)
120+
: SwiftifyInfoPrinter(ctx, SwiftContext, out, SwiftifyImportDecl, typeMapping) {}
121+
122+
void printCountedBy(const clang::CountAttributedType *CAT,
123+
ssize_t pointerIndex) {
124+
printSeparator();
125+
clang::Expr *countExpr = CAT->getCountExpr();
126+
bool isSizedBy = CAT->isCountInBytes();
127+
out << ".";
128+
if (isSizedBy)
129+
out << "sizedBy";
130+
else
131+
out << "countedBy";
132+
out << "(pointer: ";
133+
printParamOrReturn(pointerIndex);
134+
out << ", ";
135+
if (isSizedBy)
136+
out << "size";
137+
else
138+
out << "count";
139+
out << ": \"";
140+
countExpr->printPretty(
141+
out, {}, {ctx.getLangOpts()}); // TODO: map clang::Expr to Swift Expr
142+
out << "\")";
143+
}
144+
145+
void printNonEscaping(int idx) {
146+
printSeparator();
147+
out << ".nonescaping(pointer: ";
148+
printParamOrReturn(idx);
149+
out << ")";
150+
}
151+
152+
void printLifetimeboundReturn(int idx, bool borrow) {
153+
printSeparator();
154+
out << ".lifetimeDependence(dependsOn: ";
155+
printParamOrReturn(idx);
156+
out << ", pointer: .return, type: ";
157+
out << (borrow ? ".borrow" : ".copy");
158+
out << ")";
159+
}
160+
161+
bool registerStdSpanTypeMapping(Type swiftType, const clang::QualType clangType) {
162+
const auto *decl = clangType->getAsTagDecl();
163+
if (decl && decl->isInStdNamespace() && decl->getName() == "span") {
164+
typeMapping.insert(std::make_pair(
165+
swiftType->getString(), swiftType->getDesugaredType()->getString()));
166+
return true;
167+
}
168+
return false;
169+
}
163170

164171
private:
165172
void printParamOrReturn(ssize_t pointerIndex) {
@@ -315,7 +322,7 @@ static size_t getNumParams(const clang::FunctionDecl* D) {
315322

316323
template<typename T>
317324
static bool swiftifyImpl(ClangImporter::Implementation &Self,
318-
SwiftifyInfoPrinter &printer,
325+
SwiftifyInfoFunctionPrinter &printer,
319326
const AbstractFunctionDecl *MappedDecl,
320327
const T *ClangDecl) {
321328
DLOG("Checking " << *ClangDecl << " for bounds and lifetime info\n");
@@ -451,28 +458,29 @@ class SwiftifyProtocolInfoPrinter : public SwiftifyInfoPrinter {
451458
public:
452459
SwiftifyProtocolInfoPrinter(ClangImporter::Implementation &ImporterImpl,
453460
clang::ASTContext &ctx, ASTContext &SwiftContext,
454-
llvm::raw_ostream &out,
455-
MacroDecl &SwiftifyImportDecl)
456-
: SwiftifyInfoPrinter(ctx, SwiftContext, out, SwiftifyImportDecl),
461+
llvm::raw_svector_ostream &out,
462+
MacroDecl &SwiftifyImportDecl,
463+
llvm::StringMap<std::string> &typeMapping)
464+
: SwiftifyInfoPrinter(ctx, SwiftContext, out, SwiftifyImportDecl, typeMapping),
457465
ImporterImpl(ImporterImpl) {}
458466

459467
bool printMethod(const FuncDecl *Method) {
460-
// don't emit .method() if we know it's going to be empty
461468
auto ClangDecl = dyn_cast_or_null<clang::ObjCMethodDecl>(Method->getClangDecl());
462469
if (!ClangDecl)
463470
return false;
464471

465-
printSeparator();
466-
out << ".method(signature: \"";
467-
printMethodSignature(Method);
468-
out << "\", paramInfo: [";
469-
// reset firstParam inside paramInfo array. At this point firstParam will
470-
// always be false, so no need to save the current value.
471-
ASSERT(!firstParam);
472-
firstParam = true;
473-
bool hadAttributes = swiftifyImpl(ImporterImpl, *this, Method, ClangDecl);
474-
firstParam = false;
475-
out << "])";
472+
llvm::SmallString<128> paramInfoString;
473+
llvm::raw_svector_ostream tmpOut(paramInfoString);
474+
475+
SwiftifyInfoFunctionPrinter methodPrinter(ctx, SwiftContext, tmpOut,
476+
SwiftifyImportDecl, typeMapping);
477+
bool hadAttributes = swiftifyImpl(ImporterImpl, methodPrinter, Method, ClangDecl);
478+
if (hadAttributes) {
479+
printSeparator();
480+
out << ".method(signature: \"";
481+
printMethodSignature(Method);
482+
out << "\", paramInfo: [" << paramInfoString << "])";
483+
}
476484
return hadAttributes;
477485
}
478486

@@ -507,13 +515,16 @@ void ClangImporter::Implementation::swiftify(AbstractFunctionDecl *MappedDecl) {
507515
llvm::SmallString<128> MacroString;
508516
{
509517
llvm::raw_svector_ostream out(MacroString);
510-
out << "@_SwiftifyImport";
518+
out << "@_SwiftifyImport(";
511519

512-
SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out, *SwiftifyImportDecl);
520+
llvm::StringMap<std::string> typeMapping;
521+
SwiftifyInfoFunctionPrinter printer(getClangASTContext(), SwiftContext, out,
522+
*SwiftifyImportDecl, typeMapping);
513523
if (!swiftifyImpl(*this, printer, MappedDecl, ClangDecl))
514524
return;
515525
printer.printAvailability();
516526
printer.printTypeMapping();
527+
out << ")";
517528
}
518529

519530
DLOG("Attaching safe interop macro: " << MacroString << "\n");
@@ -553,11 +564,13 @@ void ClangImporter::Implementation::swiftifyProtocol(
553564
llvm::SmallString<128> MacroString;
554565
{
555566
llvm::raw_svector_ostream out(MacroString);
556-
out << "@_SwiftifyImportProtocol";
567+
out << "@_SwiftifyImportProtocol(";
557568

558569
bool hasBoundsAttributes = false;
570+
llvm::StringMap<std::string> typeMapping;
559571
SwiftifyProtocolInfoPrinter printer(*this, getClangASTContext(),
560-
SwiftContext, out, *SwiftifyImportDecl);
572+
SwiftContext, out, *SwiftifyImportDecl,
573+
typeMapping);
561574
for (Decl *SwiftMember :
562575
cast<IterableDeclContext>(MappedDecl)->getAllMembers()) {
563576
FuncDecl *SwiftDecl = dyn_cast<FuncDecl>(SwiftMember);
@@ -570,6 +583,7 @@ void ClangImporter::Implementation::swiftifyProtocol(
570583
return;
571584
printer.printAvailability();
572585
printer.printTypeMapping();
586+
out << ")";
573587
}
574588

575589
DLOG("Attaching safe interop macro: " << MacroString << "\n");
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// REQUIRES: swift_feature_SafeInteropWrappers
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -I %t -enable-experimental-feature SafeInteropWrappers %t/test.swift -verify -Xcc -Wno-nullability-completeness
7+
// RUN: env SWIFT_BACKTRACE="" %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -I %t -enable-experimental-feature SafeInteropWrappers %t/test.swift -dump-macro-expansions 2> %t/expansions.out
8+
// RUN: %diff %t/expansions.out %t/expansions.expected
9+
10+
//--- test.h
11+
#pragma once
12+
13+
#define __counted_by(x) __attribute__((__counted_by__(x)))
14+
15+
@protocol NoBounds
16+
- (void) ignore;
17+
@end
18+
19+
@protocol NoYesNo
20+
- (void) ignore;
21+
- (void) simple:(int)len :(int * __counted_by(len))p;
22+
- (void) ignore2;
23+
@end
24+
25+
@protocol YesNo
26+
- (void) simple:(int)len :(int * __counted_by(len))p;
27+
- (void) ignore;
28+
@end
29+
30+
@protocol YesNoYes
31+
- (void) simple:(int)len :(int * __counted_by(len))p;
32+
- (void) ignore;
33+
- (void) simple2:(int)len :(int * __counted_by(len))p;
34+
@end
35+
36+
//--- expansions.expected
37+
@__swiftmacro_So05NoYesA023_SwiftifyImportProtocolfMe_.swift
38+
------------------------------
39+
extension NoYesNo {
40+
/// This is an auto-generated wrapper for safer interop
41+
@_alwaysEmitIntoClient @_disfavoredOverload public
42+
func simple(_ p: UnsafeMutableBufferPointer<Int32>) {
43+
let len = Int32(exactly: p.count)!
44+
return unsafe simple(len, p.baseAddress!)
45+
}
46+
}
47+
------------------------------
48+
@__swiftmacro_So5YesNo23_SwiftifyImportProtocolfMe_.swift
49+
------------------------------
50+
extension YesNo {
51+
/// This is an auto-generated wrapper for safer interop
52+
@_alwaysEmitIntoClient @_disfavoredOverload public
53+
func simple(_ p: UnsafeMutableBufferPointer<Int32>) {
54+
let len = Int32(exactly: p.count)!
55+
return unsafe simple(len, p.baseAddress!)
56+
}
57+
}
58+
------------------------------
59+
@__swiftmacro_So05YesNoA023_SwiftifyImportProtocolfMe_.swift
60+
------------------------------
61+
extension YesNoYes {
62+
/// This is an auto-generated wrapper for safer interop
63+
@_alwaysEmitIntoClient @_disfavoredOverload public
64+
func simple(_ p: UnsafeMutableBufferPointer<Int32>) {
65+
let len = Int32(exactly: p.count)!
66+
return unsafe simple(len, p.baseAddress!)
67+
}
68+
/// This is an auto-generated wrapper for safer interop
69+
@_alwaysEmitIntoClient @_disfavoredOverload public
70+
func simple2(_ p: UnsafeMutableBufferPointer<Int32>) {
71+
let len = Int32(exactly: p.count)!
72+
return unsafe simple2(len, p.baseAddress!)
73+
}
74+
}
75+
------------------------------
76+
//--- test.swift
77+
import TestClang
78+
79+
@inlinable
80+
public func call(p: UnsafeMutableBufferPointer<CInt>, x: NoBounds, y: NoYesNo, z: YesNo, å: YesNoYes) {
81+
x.ignore()
82+
y.ignore()
83+
y.simple(p)
84+
z.ignore()
85+
z.simple(p)
86+
å.ignore()
87+
å.simple(p)
88+
å.simple2(p)
89+
}
90+
91+
//--- module.modulemap
92+
module TestClang {
93+
header "test.h"
94+
export *
95+
}
96+
97+

0 commit comments

Comments
 (0)