diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 6decfd3405ccc..1666f40e4b8a5 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -220,7 +220,7 @@ bool SwiftLookupTable::contextRequiresName(ContextKind kind) { /// Try to translate the given Clang declaration into a context. static std::optional -translateDeclToContext(clang::NamedDecl *decl) { +translateDeclToContext(const clang::NamedDecl *decl) { // Tag declaration. if (auto tag = dyn_cast(decl)) { if (tag->getIdentifier()) @@ -325,22 +325,49 @@ 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 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()) { - if (isa(decl) || - isa(decl) || - isa(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) { + if (auto decl = entry.dyn_cast()) { + if (isa(decl) || + isa(decl) || + isa(decl)) { + entryFound = true; + parentContext = EffectiveClangContext(cast(decl)); + break; + } + if (auto typedefDecl = dyn_cast(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) + break; + } + + if (!parentContext) + return nullptr; - return nullptr; + return parentContext.getAsDeclContext() + ? cast(parentContext.getAsDeclContext()) + : parentContext.getTypedefName(); } void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) { diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index 535f72a4671ee..5849233c110b6 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -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. /// diff --git a/test/APINotes/Inputs/broken-modules/BrokenAPINotes.apinotes b/test/APINotes/Inputs/broken-modules/BrokenAPINotes.apinotes index ef6e86a96e882..c8a9dd0ecd2b1 100644 --- a/test/APINotes/Inputs/broken-modules/BrokenAPINotes.apinotes +++ b/test/APINotes/Inputs/broken-modules/BrokenAPINotes.apinotes @@ -13,4 +13,4 @@ Functions: - Name: ZXSpectrumSetMisnamedRegister SwiftName: 'setter:ZXSpectrum.misnamedRegister(self:newValue:)' - Name: ZXSpectrumHelperReset - SwiftName: 'ZXSpectrum.Helper.reset()' + SwiftName: 'ZXSpectrum::Helper.reset()' diff --git a/test/Interop/Cxx/namespace/Inputs/import-as-member.h b/test/Interop/Cxx/namespace/Inputs/import-as-member.h new file mode 100644 index 0000000000000..750c26f135ce7 --- /dev/null +++ b/test/Interop/Cxx/namespace/Inputs/import-as-member.h @@ -0,0 +1,32 @@ +#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; } +inline int nestedStruct_methodInline(MyNS::NestedStruct p) SWIFT_NAME("MyNS.NestedStruct.methodInline(self:)") { return p.value + 2; } + +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; } + +namespace MyNS { +int nestedStruct_nestedMethod(MyNS::NestedStruct p) SWIFT_NAME("MyNS.NestedStruct.nestedMethod(self:)") { return p.value + 3; } +inline int nestedStruct_nestedMethodInline(MyNS::NestedStruct p) SWIFT_NAME("MyNS.NestedStruct.nestedMethodInline(self:)") { return p.value + 4; } +} diff --git a/test/Interop/Cxx/namespace/Inputs/module.modulemap b/test/Interop/Cxx/namespace/Inputs/module.modulemap index b2d1808ac2dc5..a2394849f073d 100644 --- a/test/Interop/Cxx/namespace/Inputs/module.modulemap +++ b/test/Interop/Cxx/namespace/Inputs/module.modulemap @@ -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 diff --git a/test/Interop/Cxx/namespace/import-as-member-module-interface.swift b/test/Interop/Cxx/namespace/import-as-member-module-interface.swift new file mode 100644 index 0000000000000..cd6be06ac827d --- /dev/null +++ b/test/Interop/Cxx/namespace/import-as-member-module-interface.swift @@ -0,0 +1,16 @@ +// 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: func methodInline() -> Int32 +// CHECK-NEXT: func nestedMethod() -> Int32 +// CHECK-NEXT: func nestedMethodInline() -> 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: } diff --git a/test/Interop/Cxx/namespace/import-as-member-typechecker.swift b/test/Interop/Cxx/namespace/import-as-member-typechecker.swift new file mode 100644 index 0000000000000..79657309cff3e --- /dev/null +++ b/test/Interop/Cxx/namespace/import-as-member-typechecker.swift @@ -0,0 +1,24 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=upcoming-swift + +import ImportAsMember + +func takesNestedStruct(_ s: MyNS.NestedStruct) { + _ = s.method() + _ = s.methodConstRef() + _ = s.nestedMethod() + _ = s.nestedMethodInline() + + _ = 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()'}} +} + +MyNS.method() // expected-error {{type 'MyNS' has no member 'method'}} +MyNS.nestedMethod() // expected-error {{type of expression is ambiguous without a type annotation}} diff --git a/test/Interop/Cxx/namespace/import-as-member.swift b/test/Interop/Cxx/namespace/import-as-member.swift new file mode 100644 index 0000000000000..6275598d9048b --- /dev/null +++ b/test/Interop/Cxx/namespace/import-as-member.swift @@ -0,0 +1,31 @@ +// 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()) + expectEqual(125, s.methodInline()) +} + +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()) +} + +NamespacesTestSuite.test("Struct and function in a namespace") { + let s = MyNS.NestedStruct() + expectEqual(126, s.nestedMethod()) + expectEqual(127, s.nestedMethodInline()) +} + +runAllTests() diff --git a/test/Interop/Cxx/objc-correctness/appkit-uikit.swift b/test/Interop/Cxx/objc-correctness/appkit-uikit.swift index 2569d66f97cb7..9ad15db16b5af 100644 --- a/test/Interop/Cxx/objc-correctness/appkit-uikit.swift +++ b/test/Interop/Cxx/objc-correctness/appkit-uikit.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs -cxx-interoperability-mode=default %s +// RUN: %target-swift-frontend -typecheck -verify -I %S/Inputs -cxx-interoperability-mode=default %s -swift-version 6 // REQUIRES: objc_interop // REQUIRES: VENDOR=apple @@ -9,6 +10,8 @@ import AppKit var _: AttributeScopes.AppKitAttributes.UnderlineStyleAttribute! = nil +var _ = NSEvent.SpecialKey.upArrow.rawValue + #elseif canImport(UIKit) import UIKit