Skip to content

Commit 13a63f4

Browse files
committed
[interop][SwiftToCxx] incorporate argument labels into Stdlib API names in C++
This allows easier use and more wider API exposure from the Swift stdlib In the future, all functions and method should incorporate argument labels, but it's not yet clear how
1 parent a0e1810 commit 13a63f4

File tree

6 files changed

+97
-54
lines changed

6 files changed

+97
-54
lines changed

lib/AST/SwiftNameTranslation.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616

1717
#include "swift/AST/SwiftNameTranslation.h"
1818
#include "swift/AST/ASTContext.h"
19-
#include "swift/AST/Module.h"
2019
#include "swift/AST/Decl.h"
2120
#include "swift/AST/LazyResolver.h"
21+
#include "swift/AST/Module.h"
22+
#include "swift/AST/ParameterList.h"
2223
#include "swift/Basic/StringExtras.h"
2324

2425
#include "clang/AST/DeclObjC.h"
@@ -162,10 +163,32 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
162163
if (customNamesOnly)
163164
return StringRef();
164165

165-
// FIXME: String.Index should be exposed as String::Index, not _String_Index.
166-
if (VD->getModuleContext()->isStdlibModule() &&
167-
VD->getBaseIdentifier().str() == "Index") {
168-
return "String_Index";
166+
if (VD->getModuleContext()->isStdlibModule()) {
167+
// Incorporate argument labels into Stdlib API names.
168+
// FIXME: This should be done more broadly.
169+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
170+
std::string result;
171+
llvm::raw_string_ostream os(result);
172+
os << VD->getBaseIdentifier().str();
173+
if (!AFD->getParameters())
174+
return os.str();
175+
for (const auto *param : *AFD->getParameters()) {
176+
auto paramName = param->getArgumentName();
177+
if (paramName.empty())
178+
continue;
179+
auto paramNameStr = paramName.str();
180+
os << char(std::toupper(paramNameStr[0]));
181+
os << paramNameStr.drop_front(1);
182+
}
183+
auto r = VD->getASTContext().getIdentifier(os.str());
184+
return r.str();
185+
}
186+
187+
// FIXME: String.Index should be exposed as String::Index, not
188+
// _String_Index.
189+
if (VD->getBaseIdentifier().str() == "Index") {
190+
return "String_Index";
191+
}
169192
}
170193

171194
return VD->getBaseIdentifier().str();

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,7 +2700,7 @@ static bool isStringNestedType(const ValueDecl *VD, StringRef Typename) {
27002700

27012701
static bool hasExposeAttr(const ValueDecl *VD, bool isExtension = false) {
27022702
if (isa<NominalTypeDecl>(VD) && VD->getModuleContext()->isStdlibModule()) {
2703-
if (VD == VD->getASTContext().getStringDecl() && !isExtension)
2703+
if (VD == VD->getASTContext().getStringDecl())
27042704
return true;
27052705
if (VD == VD->getASTContext().getArrayDecl())
27062706
return true;
@@ -2721,47 +2721,24 @@ static bool hasExposeAttr(const ValueDecl *VD, bool isExtension = false) {
27212721
// FIXME: Do not expose 'index' methods as the overloads are conflicting.
27222722
// this should either be prohibited in the stdlib module, or the overloads
27232723
// should be renamed automatically or using the expose attribute.
2724-
if (ED->getExtendedNominal() == VD->getASTContext().getArrayDecl()) {
2725-
if (isa<AbstractFunctionDecl>(VD) &&
2726-
!cast<AbstractFunctionDecl>(VD)
2727-
->getName()
2728-
.getBaseName()
2729-
.isSpecial() &&
2730-
cast<AbstractFunctionDecl>(VD)
2731-
->getName()
2732-
.getBaseName()
2733-
.getIdentifier()
2734-
.str()
2735-
.contains_insensitive("index"))
2736-
return false;
2737-
}
2724+
if ((ED->getExtendedNominal() == VD->getASTContext().getArrayDecl() ||
2725+
ED->getExtendedNominal() == VD->getASTContext().getStringDecl()) &&
2726+
(isa<AbstractFunctionDecl>(VD) &&
2727+
!cast<AbstractFunctionDecl>(VD)->getName().getBaseName().isSpecial() &&
2728+
cast<AbstractFunctionDecl>(VD)
2729+
->getName()
2730+
.getBaseName()
2731+
.getIdentifier()
2732+
.str()
2733+
.contains_insensitive("index")))
2734+
return false;
2735+
// Limit exposition of String constructors as there's overloading conflict.
2736+
// FIXME: resolve it in some other way.
27382737
if (ED->getExtendedNominal() == VD->getASTContext().getStringDecl()) {
2739-
if (isa<ValueDecl>(VD) &&
2740-
!cast<ValueDecl>(VD)->getName().getBaseName().isSpecial() &&
2741-
cast<ValueDecl>(VD)
2742-
->getName()
2743-
.getBaseName()
2744-
.getIdentifier()
2745-
.str()
2746-
.contains_insensitive("utf8"))
2747-
return true;
2748-
}
2749-
if (isStringNestedType(ED->getExtendedNominal(), "UTF8View")) {
2750-
// Do not expose ambiguous 'index(after:' / 'index(before:' overloads.
2751-
if (isa<AbstractFunctionDecl>(VD) &&
2752-
cast<AbstractFunctionDecl>(VD)->getParameters()->size() == 1 &&
2753-
!cast<AbstractFunctionDecl>(VD)
2754-
->getName()
2755-
.getBaseName()
2756-
.isSpecial() &&
2757-
cast<AbstractFunctionDecl>(VD)
2758-
->getName()
2759-
.getBaseName()
2760-
.getIdentifier()
2761-
.str()
2762-
.contains_insensitive("index"))
2738+
if (isa<ConstructorDecl>(VD))
27632739
return false;
27642740
}
2741+
27652742
return hasExposeAttr(ED->getExtendedNominal(), /*isExtension=*/true);
27662743
}
27672744
return false;

lib/PrintAsClang/_SwiftStdlibCxxOverlay.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ SWIFT_INLINE_THUNK String::operator std::string() const {
6363
using IndexType = decltype(u.getStartIndex());
6464
for (auto s = u.getStartIndex().getEncodedOffset(),
6565
e = u.getEndIndex().getEncodedOffset();
66-
s != e; s = u.index(IndexType::init(s), 1).getEncodedOffset()) {
66+
s != e; s = u.indexOffsetBy(IndexType::init(s), 1).getEncodedOffset()) {
6767
result.push_back(u[IndexType::init(s)]);
6868
}
6969
return result;

test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ int main() {
5353
assert(val.getCapacity() >= 1);
5454
auto zeroInt = val[0];
5555
assert(zeroInt == -11);
56-
auto firstInt = val.remove(0);
56+
auto firstInt = val.removeAt(0);
5757
assert(firstInt == -11);
5858
assert(val.getCount() == 0);
5959
UseArray::printArray(val);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck %t/print-string.swift -typecheck -module-name Stringer -enable-experimental-cxx-interop -emit-clang-header-path %t/Stringer.h
5+
6+
// RUN: %target-interop-build-clangxx -std=gnu++20 -c %t/string-conversions.cpp -I %t -o %t/swift-stdlib-execution.o
7+
// RUN: %target-build-swift %t/print-string.swift -o %t/swift-stdlib-execution -Xlinker %t/swift-stdlib-execution.o -module-name Stringer -Xfrontend -entry-point-function-name -Xfrontend swiftMain %target-cxx-lib
8+
// RUN: %target-codesign %t/swift-stdlib-execution
9+
// RUN: %target-run %t/swift-stdlib-execution | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
13+
//--- print-string.swift
14+
15+
@_expose(Cxx)
16+
public func printString(_ s: String) {
17+
print("'''\(s)'''")
18+
}
19+
20+
//--- string-conversions.cpp
21+
22+
#include <cassert>
23+
#include "Stringer.h"
24+
25+
int main() {
26+
using namespace Swift;
27+
using namespace Stringer;
28+
29+
{
30+
auto s = String("Hello world");
31+
assert(s.getCount() == 11);
32+
printString(s);
33+
s.append(String("!test"));
34+
printString(s);
35+
printString(s.lowercased());
36+
printString(s.uppercased());
37+
}
38+
// CHECK: '''Hello world'''
39+
// CHECK: '''Hello world!test'''
40+
// CHECK: '''hello world!test'''
41+
// CHECK: '''HELLO WORLD!TEST'''
42+
return 0;
43+
}

test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
// CHECK: }
3636
// CHECK: static SWIFT_INLINE_THUNK Array<T_0_0> init() SWIFT_SYMBOL({{.*}});
3737
// CHECK: SWIFT_INLINE_THUNK void append(const T_0_0& newElement) SWIFT_SYMBOL({{.*}});
38-
// CHECK: SWIFT_INLINE_THUNK T_0_0 remove(swift::Int index) SWIFT_SYMBOL({{.*}});
38+
// CHECK: SWIFT_INLINE_THUNK T_0_0 removeAt(swift::Int index) SWIFT_SYMBOL({{.*}});
3939
// CHECK: SWIFT_INLINE_THUNK T_0_0 operator [](swift::Int index) const SWIFT_SYMBOL({{.*}});
4040
// CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}});
4141
// CHECK: SWIFT_INLINE_THUNK swift::Int getCapacity() const SWIFT_SYMBOL({{.*}});
@@ -73,10 +73,11 @@
7373
// CHECK: }
7474
// CHECK-NEXT: SWIFT_INLINE_THUNK String(String &&) { abort(); }
7575
// CHECK-NEXT: static SWIFT_INLINE_THUNK String init() SWIFT_SYMBOL({{.*}});
76-
// CHECK-NEXT: SWIFT_INLINE_THUNK UTF8View getUtf8() const SWIFT_SYMBOL({{.*}});
76+
// CHECK: SWIFT_INLINE_THUNK void append(const String& other)
77+
// CHECK: SWIFT_INLINE_THUNK UTF8View getUtf8() const SWIFT_SYMBOL({{.*}});
7778
// CHECK-NEXT: SWIFT_INLINE_THUNK void setUtf8(const UTF8View& newValue) SWIFT_SYMBOL({{.*}});
78-
// CHECK-NEXT: SWIFT_INLINE_THUNK bool isContiguousUTF8() const SWIFT_SYMBOL({{.*}});
79-
// CHECK-NEXT: #if defined(__OBJC__)
79+
// CHECK: SWIFT_INLINE_THUNK bool isContiguousUTF8() const SWIFT_SYMBOL({{.*}});
80+
// CHECK: #if defined(__OBJC__)
8081
// CHECK-NEXT: SWIFT_INLINE_THUNK operator NSString * _Nonnull () const noexcept {
8182
// CHECK-NEXT: return (__bridge_transfer NSString *)(_impl::$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF(_impl::swift_interop_passDirect_Swift_String(_getOpaquePointer())));
8283
// CHECK-NEXT: }
@@ -106,10 +107,9 @@
106107
// CHECK: SWIFT_INLINE_THUNK UTF8View(UTF8View &&) { abort(); }
107108
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getStartIndex() const SWIFT_SYMBOL({{.*}});
108109
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getEndIndex() const SWIFT_SYMBOL({{.*}});
109-
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index index(const String_Index& i, swift::Int n) const SWIFT_SYMBOL({{.*}});
110-
// CHECK-NEXT: SWIFT_INLINE_THUNK Swift::Optional<String_Index> index(const String_Index& i, swift::Int n, const String_Index& limit) const SWIFT_SYMBOL({{.*}});
111-
// CHECK-NEXT: SWIFT_INLINE_THUNK swift::Int distance(const String_Index& i, const String_Index& j) const SWIFT_SYMBOL({{.*}});
112-
// CHECK-NEXT: SWIFT_INLINE_THUNK uint8_t operator [](const String_Index& i) const SWIFT_SYMBOL({{.*}});
110+
// CHECK: SWIFT_INLINE_THUNK Swift::Optional<String_Index> indexOffsetByLimitedBy(const String_Index& i, swift::Int n, const String_Index& limit) const SWIFT_SYMBOL({{.*}});
111+
// CHECK: SWIFT_INLINE_THUNK swift::Int distanceFromTo(const String_Index& i, const String_Index& j) const SWIFT_SYMBOL({{.*}});
112+
// CHECK: SWIFT_INLINE_THUNK uint8_t operator [](const String_Index& i) const SWIFT_SYMBOL({{.*}});
113113
// CHECK: SWIFT_INLINE_THUNK String getDescription() const SWIFT_SYMBOL({{.*}});
114114
// CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}});
115115
// CHECK-NEXT: private:

0 commit comments

Comments
 (0)