Skip to content

Commit 23ed6e8

Browse files
committed
[interop][SwiftToCxx] support instance property setters in C++
1 parent 5b05d3d commit 23ed6e8

File tree

5 files changed

+213
-24
lines changed

5 files changed

+213
-24
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,8 @@ class DeclAndTypePrinter::Implementation
13721372
return;
13731373
auto *getter = VD->getOpaqueAccessor(AccessorKind::Get);
13741374
printAbstractFunctionAsMethod(getter, /*isStatic=*/false);
1375+
if (auto *setter = VD->getOpaqueAccessor(AccessorKind::Set))
1376+
printAbstractFunctionAsMethod(setter, /*isStatic=*/false);
13751377
return;
13761378
}
13771379

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -480,34 +480,27 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
480480
void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
481481
const NominalTypeDecl *typeDeclContext, const AccessorDecl *accessor,
482482
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
483-
assert(accessor->getParameters()->size() == 0);
483+
assert(accessor->isSetter() || accessor->getParameters()->size() == 0);
484484
os << " inline ";
485485

486-
OptionalTypeKind retKind;
487-
Type objTy;
488-
std::tie(objTy, retKind) =
489-
DeclAndTypePrinter::getObjectTypeAndOptionality(accessor, resultTy);
490-
CFunctionSignatureTypePrinter typePrinter(
491-
os, cPrologueOS, typeMapping, OutputLanguageMode::Cxx, interopContext,
492-
CFunctionSignatureTypePrinterModifierDelegate(),
493-
accessor->getModuleContext(), FunctionSignatureTypeUse::ReturnType);
494-
typePrinter.visit(objTy, retKind, /*isInOut=*/false);
495-
496-
ClangSyntaxPrinter printer(os);
497-
os << ' ';
498-
if (isDefinition) {
499-
// FIXME: Full qualifiers for nested types?
500-
printer.printBaseName(typeDeclContext);
501-
os << "::";
502-
}
503-
504-
StringRef name;
486+
StringRef propertyName;
505487
// For a getter or setter, go through the variable or subscript decl.
506-
name = accessor->getStorage()->getBaseIdentifier().str();
488+
propertyName = accessor->getStorage()->getBaseIdentifier().str();
507489

490+
std::string name;
491+
llvm::raw_string_ostream nameOS(name);
508492
// FIXME: some names are remapped differently. (e.g. isX).
509-
os << "get" << char(std::toupper(name[0])) << name.drop_front();
510-
os << "() const";
493+
nameOS << (accessor->isSetter() ? "set" : "get")
494+
<< char(std::toupper(propertyName[0])) << propertyName.drop_front();
495+
496+
FunctionSignatureModifiers modifiers;
497+
if (isDefinition)
498+
modifiers.qualifierContext = typeDeclContext;
499+
printFunctionSignature(accessor, nameOS.str(), resultTy,
500+
FunctionSignatureKind::CxxInlineThunk, {}, modifiers);
501+
if (accessor->isGetter()) {
502+
os << " const";
503+
}
511504
if (!isDefinition) {
512505
os << ";\n";
513506
return;
@@ -518,7 +511,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
518511
accessor->getParameters(),
519512
{AdditionalParam{AdditionalParam::Role::Self,
520513
typeDeclContext->getDeclaredType(),
521-
/*isIndirect=*/false}});
514+
/*isIndirect=*/accessor->isSetter()}});
522515
os << " }\n";
523516
}
524517

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %S/setter-in-cxx.swift -typecheck -module-name Properties -clang-header-expose-public-decls -emit-clang-header-path %t/properties.h
4+
5+
// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-props-execution.o
6+
// RUN: %target-interop-build-swift %S/setter-in-cxx.swift -o %t/swift-props-execution -Xlinker %t/swift-props-execution.o -module-name Properties -Xfrontend -entry-point-function-name -Xfrontend swiftMain
7+
8+
// RUN: %target-codesign %t/swift-props-execution
9+
// RUN: %target-run %t/swift-props-execution | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
13+
#include <assert.h>
14+
#include "properties.h"
15+
16+
int main() {
17+
using namespace Properties;
18+
19+
auto smallStructWithProps = createSmallStructWithProps();
20+
smallStructWithProps.setStoredInt(12);
21+
assert(smallStructWithProps.getStoredInt() == 12);
22+
assert(smallStructWithProps.getComputedInt() == 14);
23+
smallStructWithProps.setComputedInt(45);
24+
assert(smallStructWithProps.getStoredInt() == 43);
25+
assert(smallStructWithProps.getComputedInt() == 45);
26+
27+
auto largeStructWithProps = smallStructWithProps.getLargeStructWithProps();
28+
assert(largeStructWithProps.getStoredSmallStruct().getX() == 0xFAE);
29+
largeStructWithProps.setStoredSmallStruct(createFirstSmallStruct(999));
30+
assert(largeStructWithProps.getStoredSmallStruct().getX() == 999);
31+
32+
auto firstSmallStruct = largeStructWithProps.getStoredSmallStruct();
33+
assert(firstSmallStruct.getX() == 999);
34+
firstSmallStruct.setX(42);
35+
assert(firstSmallStruct.getX() == 42);
36+
37+
largeStructWithProps.setStoredLargeStruct(largeStructWithProps.getStoredLargeStruct());
38+
39+
smallStructWithProps.setLargeStructWithProps(largeStructWithProps);
40+
// CHECK: SET: LargeStruct(x1: 90, x2: 1, x3: 2, x4: 3, x5: 4, x6: 5), FirstSmallStruct(x: 999)
41+
42+
auto largeStruct = largeStructWithProps.getStoredLargeStruct();
43+
largeStruct.setX1(0);
44+
largeStruct.setX2(largeStruct.getX2() * 2);
45+
largeStruct.setX3(-72);
46+
largeStructWithProps.setStoredLargeStruct(largeStruct);
47+
48+
smallStructWithProps.setLargeStructWithProps(largeStructWithProps);
49+
// CHECK-NEXT: SET: LargeStruct(x1: 0, x2: 2, x3: -72, x4: 3, x5: 4, x6: 5), FirstSmallStruct(x: 999)
50+
return 0;
51+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -typecheck -module-name Properties -clang-header-expose-public-decls -emit-clang-header-path %t/properties.h
3+
// RUN: %FileCheck %s < %t/properties.h
4+
5+
// RUN: %check-interop-cxx-header-in-clang(%t/properties.h)
6+
7+
public struct FirstSmallStruct {
8+
public var x: UInt32
9+
}
10+
11+
// CHECK: class FirstSmallStruct final {
12+
// CHECK: public:
13+
// CHECK: inline FirstSmallStruct(FirstSmallStruct &&) = default;
14+
// CHECK-NEXT: inline uint32_t getX() const;
15+
// CHECK-NEXT: inline void setX(uint32_t value);
16+
// CHECK-NEXT: private:
17+
18+
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
19+
// CHECK-NEXT: return _impl::$s10Properties16FirstSmallStructV1xs6UInt32Vvg(_impl::swift_interop_passDirect_Properties_FirstSmallStruct(_getOpaquePointer()));
20+
// CHECK-NEXT: }
21+
// CHECK-NEXT: inline void FirstSmallStruct::setX(uint32_t value) {
22+
// CHECK-NEXT: return _impl::$s10Properties16FirstSmallStructV1xs6UInt32Vvs(value, _getOpaquePointer());
23+
// CHECK-NEXT: }
24+
25+
public struct LargeStruct {
26+
public var x1, x2, x3, x4, x5, x6: Int
27+
}
28+
29+
// CHECK: class LargeStruct final {
30+
// CHECK: public:
31+
// CHECK: inline LargeStruct(LargeStruct &&) = default;
32+
// CHECK-NEXT: inline swift::Int getX1() const;
33+
// CHECK-NEXT: inline void setX1(swift::Int value);
34+
// CHECK-NEXT: inline swift::Int getX2() const;
35+
// CHECK-NEXT: inline void setX2(swift::Int value);
36+
// CHECK-NEXT: inline swift::Int getX3() const;
37+
// CHECK-NEXT: inline void setX3(swift::Int value);
38+
// CHECK-NEXT: inline swift::Int getX4() const;
39+
// CHECK-NEXT: inline void setX4(swift::Int value);
40+
// CHECK-NEXT: inline swift::Int getX5() const;
41+
// CHECK-NEXT: inline void setX5(swift::Int value);
42+
// CHECK-NEXT: inline swift::Int getX6() const;
43+
// CHECK-NEXT: inline void setX6(swift::Int value);
44+
// CHECK-NEXT: private:
45+
46+
// CHECK: inline swift::Int LargeStruct::getX1() const {
47+
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x1Sivg(_getOpaquePointer());
48+
// CHECK-NEXT: }
49+
// CHECK-NEXT: inline void LargeStruct::setX1(swift::Int value) {
50+
// CHECK-NEXT: return _impl::$s10Properties11LargeStructV2x1Sivs(value, _getOpaquePointer());
51+
// CHECK-NEXT: }
52+
53+
public struct LargeStructWithProps {
54+
public var storedLargeStruct: LargeStruct
55+
public var storedSmallStruct: FirstSmallStruct
56+
}
57+
58+
// CHECK: class LargeStructWithProps final {
59+
// CHECK-NEXT: public:
60+
// CHECK: inline LargeStruct getStoredLargeStruct() const;
61+
// CHECK-NEXT: inline void setStoredLargeStruct(const LargeStruct& value);
62+
// CHECK-NEXT: inline FirstSmallStruct getStoredSmallStruct() const;
63+
// CHECK-NEXT: inline void setStoredSmallStruct(const FirstSmallStruct& value);
64+
65+
// CHECK: inline LargeStruct LargeStructWithProps::getStoredLargeStruct() const {
66+
// CHECK-NEXT: return _impl::_impl_LargeStruct::returnNewValue([&](void * _Nonnull result) {
67+
// CHECK-NEXT: _impl::$s10Properties20LargeStructWithPropsV06storedbC0AA0bC0Vvg(result, _getOpaquePointer());
68+
// CHECK-NEXT: });
69+
// CHECK-NEXT: }
70+
// CHECK-NEXT: inline void LargeStructWithProps::setStoredLargeStruct(const LargeStruct& value) {
71+
// CHECK-NEXT: return _impl::$s10Properties20LargeStructWithPropsV06storedbC0AA0bC0Vvs(_impl::_impl_LargeStruct::getOpaquePointer(value), _getOpaquePointer());
72+
// CHECK-NEXT: }
73+
// CHECK-NEXT: inline FirstSmallStruct LargeStructWithProps::getStoredSmallStruct() const {
74+
// CHECK-NEXT: return _impl::_impl_FirstSmallStruct::returnNewValue([&](char * _Nonnull result) {
75+
// CHECK-NEXT: _impl::swift_interop_returnDirect_Properties_FirstSmallStruct(result, _impl::$s10Properties20LargeStructWithPropsV011storedSmallC0AA05FirstgC0Vvg(_getOpaquePointer()));
76+
// CHECK-NEXT: });
77+
// CHECK-NEXT: }
78+
// CHECK-NEXT: inline void LargeStructWithProps::setStoredSmallStruct(const FirstSmallStruct& value) {
79+
// CHECK-NEXT: return _impl::$s10Properties20LargeStructWithPropsV011storedSmallC0AA05FirstgC0Vvs(_impl::swift_interop_passDirect_Properties_FirstSmallStruct(_impl::_impl_FirstSmallStruct::getOpaquePointer(value)), _getOpaquePointer());
80+
// CHECK-NEXT: }
81+
82+
public struct SmallStructWithProps {
83+
public var storedInt: UInt32
84+
public var computedInt: Int {
85+
get {
86+
return Int(storedInt) + 2
87+
} set {
88+
storedInt = UInt32(newValue - 2)
89+
}
90+
}
91+
92+
public var largeStructWithProps: LargeStructWithProps {
93+
get {
94+
return LargeStructWithProps(storedLargeStruct: LargeStruct(x1: computedInt * 2, x2: 1, x3: 2, x4: 3, x5: 4, x6: 5),
95+
storedSmallStruct:FirstSmallStruct(x: 0xFAE))
96+
} set {
97+
print("SET: \(newValue.storedLargeStruct), \(newValue.storedSmallStruct)")
98+
}
99+
}
100+
}
101+
102+
// CHECK: class SmallStructWithProps final {
103+
// CHECK: public:
104+
// CHECK: inline SmallStructWithProps(SmallStructWithProps &&) = default;
105+
// CHECK-NEXT: inline uint32_t getStoredInt() const;
106+
// CHECK-NEXT: inline void setStoredInt(uint32_t value);
107+
// CHECK-NEXT: inline swift::Int getComputedInt() const;
108+
// CHECK-NEXT: inline void setComputedInt(swift::Int newValue);
109+
// CHECK-NEXT: inline LargeStructWithProps getLargeStructWithProps() const;
110+
// CHECK-NEXT: inline void setLargeStructWithProps(const LargeStructWithProps& newValue);
111+
// CHECK-NEXT: private:
112+
113+
// CHECK: inline uint32_t SmallStructWithProps::getStoredInt() const {
114+
// CHECK-NEXT: return _impl::$s10Properties20SmallStructWithPropsV9storedInts6UInt32Vvg(_impl::swift_interop_passDirect_Properties_SmallStructWithProps(_getOpaquePointer()));
115+
// CHECK-NEXT: }
116+
// CHECK-NEXT: inline void SmallStructWithProps::setStoredInt(uint32_t value) {
117+
// CHECK-NEXT: return _impl::$s10Properties20SmallStructWithPropsV9storedInts6UInt32Vvs(value, _getOpaquePointer());
118+
// CHECK-NEXT: }
119+
// CHECK-NEXT: inline swift::Int SmallStructWithProps::getComputedInt() const {
120+
// CHECK-NEXT: return _impl::$s10Properties20SmallStructWithPropsV11computedIntSivg(_impl::swift_interop_passDirect_Properties_SmallStructWithProps(_getOpaquePointer()));
121+
// CHECK-NEXT: }
122+
// CHECK-NEXT: inline void SmallStructWithProps::setComputedInt(swift::Int newValue) {
123+
// CHECK-NEXT: return _impl::$s10Properties20SmallStructWithPropsV11computedIntSivs(newValue, _getOpaquePointer());
124+
// CHECK-NEXT: }
125+
// CHECK-NEXT: inline LargeStructWithProps SmallStructWithProps::getLargeStructWithProps() const {
126+
// CHECK-NEXT: return _impl::_impl_LargeStructWithProps::returnNewValue([&](void * _Nonnull result) {
127+
// CHECK-NEXT: _impl::$s10Properties20SmallStructWithPropsV05largecdE0AA05LargecdE0Vvg(result, _impl::swift_interop_passDirect_Properties_SmallStructWithProps(_getOpaquePointer()));
128+
// CHECK-NEXT: });
129+
// CHECK-NEXT: }
130+
// CHECK-NEXT: inline void SmallStructWithProps::setLargeStructWithProps(const LargeStructWithProps& newValue) {
131+
// CHECK-NEXT: return _impl::$s10Properties20SmallStructWithPropsV05largecdE0AA05LargecdE0Vvs(_impl::_impl_LargeStructWithProps::getOpaquePointer(newValue), _getOpaquePointer());
132+
// CHECK-NEXT: }
133+
134+
public func createSmallStructWithProps() -> SmallStructWithProps {
135+
return SmallStructWithProps(storedInt: 21)
136+
}
137+
138+
public func createFirstSmallStruct(_ x: UInt32) -> FirstSmallStruct {
139+
return FirstSmallStruct(x: x)
140+
}

test/Interop/SwiftToCxx/structs/resilient-struct-in-cxx.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public struct FirstSmallStruct {
5555
// CHECK: inline uint32_t FirstSmallStruct::getX() const {
5656
// CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV1xs6UInt32Vvg(_getOpaquePointer());
5757
// CHECK-NEXT: }
58+
// CHECK: inline void FirstSmallStruct::setX(uint32_t value) {
59+
// CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV1xs6UInt32Vvs(value, _getOpaquePointer());
60+
// CHECK-NEXT: }
5861
// CHECK-NEXT: inline void FirstSmallStruct::dump() const {
5962
// CHECK-NEXT: return _impl::$s7Structs16FirstSmallStructV4dumpyyF(_getOpaquePointer());
6063
// CHECK-NEXT: }

0 commit comments

Comments
 (0)