Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions lib/ClangImporter/SwiftLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ bool SwiftLookupTable::contextRequiresName(ContextKind kind) {

/// Try to translate the given Clang declaration into a context.
static std::optional<SwiftLookupTable::StoredContext>
translateDeclToContext(clang::NamedDecl *decl) {
translateDeclToContext(const clang::NamedDecl *decl) {
// Tag declaration.
if (auto tag = dyn_cast<clang::TagDecl>(decl)) {
if (tag->getIdentifier())
Expand Down Expand Up @@ -324,22 +324,46 @@ SwiftLookupTable::translateContext(EffectiveClangContext context) {

/// Lookup an unresolved context name and resolve it to a Clang
/// declaration context or typedef name.
clang::NamedDecl *SwiftLookupTable::resolveContext(StringRef unresolvedName) {
const clang::NamedDecl *
SwiftLookupTable::resolveContext(StringRef unresolvedName) {
SmallVector<StringRef, 1> nameComponents;
unresolvedName.split(nameComponents, '.');

EffectiveClangContext parentContext;

// Look for a context with the given Swift name.
for (auto entry :
lookup(SerializedSwiftName(unresolvedName),
std::make_pair(ContextKind::TranslationUnit, StringRef()))) {
if (auto decl = entry.dyn_cast<clang::NamedDecl *>()) {
if (isa<clang::TagDecl>(decl) ||
isa<clang::ObjCInterfaceDecl>(decl) ||
isa<clang::TypedefNameDecl>(decl))
return decl;
for (auto nameComponent : nameComponents) {
auto entries =
parentContext
? lookup(SerializedSwiftName(nameComponent), parentContext)
: lookup(SerializedSwiftName(nameComponent),
std::make_pair(ContextKind::TranslationUnit, StringRef()));
bool entryFound = false;
for (auto entry : entries) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use llvm::find_if

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to refactor that locally, but that means we have to do the casting multiple times, both within the find_if and outside of it. I personally prefer a simple loop here, but I can change it if you feel strongly.

if (auto decl = entry.dyn_cast<clang::NamedDecl *>()) {
if (isa<clang::TagDecl>(decl) ||
isa<clang::ObjCInterfaceDecl>(decl) ||
isa<clang::NamespaceDecl>(decl)) {
entryFound = true;
parentContext = EffectiveClangContext(cast<clang::DeclContext>(decl));
break;
}
if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(decl)) {
entryFound = true;
parentContext = EffectiveClangContext(typedefDecl);
break;
}
}
}
}

// FIXME: Search imported modules to resolve the context.
// If we could not resolve this component of the qualified name, bail.
if (!entryFound)
return nullptr;
}

return nullptr;
return parentContext.getAsDeclContext()
? cast<clang::NamedDecl>(parentContext.getAsDeclContext())
: parentContext.getTypedefName();
}

void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) {
Expand Down
2 changes: 1 addition & 1 deletion lib/ClangImporter/SwiftLookupTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ class SwiftLookupTable {
public:
/// Lookup an unresolved context name and resolve it to a Clang
/// named declaration.
clang::NamedDecl *resolveContext(StringRef unresolvedName);
const clang::NamedDecl *resolveContext(StringRef unresolvedName);

/// Lookup the set of entities with the given base name.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ Functions:
- Name: ZXSpectrumSetMisnamedRegister
SwiftName: 'setter:ZXSpectrum.misnamedRegister(self:newValue:)'
- Name: ZXSpectrumHelperReset
SwiftName: 'ZXSpectrum.Helper.reset()'
SwiftName: 'ZXSpectrum::Helper.reset()'
26 changes: 26 additions & 0 deletions test/Interop/Cxx/namespace/Inputs/import-as-member.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#define SWIFT_NAME(name) __attribute__((swift_name(name)))

namespace MyNS {
struct NestedStruct {
int value = 123;
};
}

int nestedStruct_method(MyNS::NestedStruct p) SWIFT_NAME("MyNS.NestedStruct.method(self:)") { return p.value; }
int nestedStruct_methodConstRef(const MyNS::NestedStruct &p) SWIFT_NAME("MyNS.NestedStruct.methodConstRef(self:)") { return p.value + 1; }

namespace MyNS {
namespace MyDeepNS {
struct DeepNestedStruct {
int value = 456;
};
}
}

int deepNestedStruct_method(MyNS::MyDeepNS::DeepNestedStruct p) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.method(self:)") { return p.value; }
int deepNestedStruct_methodConstRef(const MyNS::MyDeepNS::DeepNestedStruct &p) SWIFT_NAME("MyNS.MyDeepNS.DeepNestedStruct.methodConstRef(self:)") { return p.value + 2; }

typedef MyNS::MyDeepNS::DeepNestedStruct DeepNestedStructTypedef;

int deepNestedStructTypedef_method(DeepNestedStructTypedef p) SWIFT_NAME("DeepNestedStructTypedef.methodTypedef(self:)") { return p.value + 3; }
int deepNestedStructTypedef_methodQualName(MyNS::MyDeepNS::DeepNestedStruct p) SWIFT_NAME("DeepNestedStructTypedef.methodTypedefQualName(self:)") { return p.value + 4; }
6 changes: 6 additions & 0 deletions test/Interop/Cxx/namespace/Inputs/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ module Enums {
requires cplusplus
}

module ImportAsMember {
header "import-as-member.h"
export *
requires cplusplus
}

module MembersDirect {
header "members-direct.h"
requires cplusplus
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=ImportAsMember -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift | %FileCheck %s

// CHECK: extension MyNS.NestedStruct {
// CHECK-NEXT: func method() -> Int32
// CHECK-NEXT: func methodConstRef() -> Int32
// CHECK-NEXT: }

// CHECK: extension MyNS.MyDeepNS.DeepNestedStruct {
// CHECK-NEXT: func method() -> Int32
// CHECK-NEXT: func methodConstRef() -> Int32
// CHECK-NEXT: func methodTypedef() -> Int32
// CHECK-NEXT: func methodTypedefQualName() -> Int32
// CHECK-NEXT: }
19 changes: 19 additions & 0 deletions test/Interop/Cxx/namespace/import-as-member-typechecker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=upcoming-swift

import ImportAsMember

func takesNestedStruct(_ s: MyNS.NestedStruct) {
_ = s.method()
_ = s.methodConstRef()

_ = nestedStruct_method(s) // expected-error {{'nestedStruct_method' has been replaced by instance method 'MyNS.NestedStruct.method()'}}
}

func takesDeepNestedStruct(_ s: MyNS.MyDeepNS.DeepNestedStruct) {
_ = s.method()
_ = s.methodConstRef()
_ = s.methodTypedef()
_ = s.methodTypedefQualName()

_ = deepNestedStruct_method(s) // expected-error {{'deepNestedStruct_method' has been replaced by instance method 'MyNS.MyDeepNS.DeepNestedStruct.method()'}}
}
24 changes: 24 additions & 0 deletions test/Interop/Cxx/namespace/import-as-member.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -cxx-interoperability-mode=upcoming-swift)

// REQUIRES: executable_test

import StdlibUnittest
import ImportAsMember

var NamespacesTestSuite = TestSuite("Import as member of namespace")

NamespacesTestSuite.test("Struct in a namespace") {
let s = MyNS.NestedStruct()
expectEqual(123, s.method())
expectEqual(124, s.methodConstRef())
}

NamespacesTestSuite.test("Struct in a deep namespace") {
let s = MyNS.MyDeepNS.DeepNestedStruct()
expectEqual(456, s.method())
expectEqual(458, s.methodConstRef())
expectEqual(459, s.methodTypedef())
expectEqual(460, s.methodTypedefQualName())
}

runAllTests()