mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #27682 from ChristopherRogers/master
[ClangImporter] Fix edge cases where custom name matches native name
This commit is contained in:
@@ -1354,7 +1354,7 @@ bool ClangImporter::importHeader(StringRef header, ModuleDecl *adapter,
|
||||
|
||||
// If we've made it to here, this is some header other than the bridging
|
||||
// header, which means we can no longer rely on one file's modification time
|
||||
// to invalid code completion caches. :-(
|
||||
// to invalidate code completion caches. :-(
|
||||
Impl.setSinglePCHImport(None);
|
||||
|
||||
if (!cachedContents.empty() && cachedContents.back() == '\0')
|
||||
@@ -3702,8 +3702,16 @@ EffectiveClangContext ClangImporter::Implementation::getEffectiveClangContext(
|
||||
(nominal->getAttrs().hasAttribute<ObjCAttr>() ||
|
||||
(!nominal->getParentSourceFile() && nominal->isObjC()))) {
|
||||
// Map the name. If we can't represent the Swift name in Clang.
|
||||
// FIXME: We should be using the Objective-C name here!
|
||||
auto clangName = exportName(nominal->getName());
|
||||
Identifier name = nominal->getName();
|
||||
if (auto objcAttr = nominal->getAttrs().getAttribute<ObjCAttr>()) {
|
||||
if (auto objcName = objcAttr->getName()) {
|
||||
if (objcName->getNumArgs() == 0) {
|
||||
// This is an error if not 0, but it should be caught later.
|
||||
name = objcName->getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
auto clangName = exportName(name);
|
||||
if (!clangName)
|
||||
return EffectiveClangContext();
|
||||
|
||||
|
||||
@@ -4535,26 +4535,66 @@ namespace {
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
T *resolveSwiftDeclImpl(const U *decl, Identifier name, ModuleDecl *overlay) {
|
||||
T *resolveSwiftDeclImpl(const U *decl, Identifier name,
|
||||
bool hasKnownSwiftName, ModuleDecl *overlay) {
|
||||
const auto &languageVersion =
|
||||
Impl.SwiftContext.LangOpts.EffectiveLanguageVersion;
|
||||
|
||||
auto isMatch = [&](const T *singleResult, bool baseNameMatches) -> bool {
|
||||
const DeclAttributes &attrs = singleResult->getAttrs();
|
||||
|
||||
// Skip versioned variants.
|
||||
if (attrs.isUnavailableInSwiftVersion(languageVersion))
|
||||
return false;
|
||||
|
||||
// Skip if type not exposed to Objective-C.
|
||||
// If the base name doesn't match, then a matching
|
||||
// custom name in an @objc attribute is required.
|
||||
if (baseNameMatches && !singleResult->isObjC())
|
||||
return false;
|
||||
|
||||
// If Clang decl has a custom Swift name, then we know that
|
||||
// `name` is the base name we're looking for.
|
||||
if (hasKnownSwiftName)
|
||||
return baseNameMatches;
|
||||
|
||||
// Skip if a different name is used for Objective-C.
|
||||
if (auto objcAttr = attrs.getAttribute<ObjCAttr>())
|
||||
if (auto objcName = objcAttr->getName())
|
||||
return objcName->getSimpleName() == name;
|
||||
|
||||
return baseNameMatches;
|
||||
};
|
||||
|
||||
// First look at Swift types with the same name.
|
||||
SmallVector<ValueDecl *, 4> results;
|
||||
overlay->lookupValue(name, NLKind::QualifiedLookup, results);
|
||||
T *found = nullptr;
|
||||
for (auto result : results) {
|
||||
if (auto singleResult = dyn_cast<T>(result)) {
|
||||
// Skip versioned variants.
|
||||
const DeclAttributes &attrs = singleResult->getAttrs();
|
||||
if (attrs.isUnavailableInSwiftVersion(languageVersion))
|
||||
continue;
|
||||
|
||||
if (isMatch(singleResult, /*baseNameMatches=*/true)) {
|
||||
if (found)
|
||||
return nullptr;
|
||||
|
||||
found = singleResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !hasKnownSwiftName) {
|
||||
// Try harder to find a match looking at just custom Objective-C names.
|
||||
SmallVector<Decl *, 64> results;
|
||||
overlay->getTopLevelDecls(results);
|
||||
for (auto result : results) {
|
||||
if (auto singleResult = dyn_cast<T>(result)) {
|
||||
// The base name _could_ match but it's irrelevant here.
|
||||
if (isMatch(singleResult, /*baseNameMatches=*/false)) {
|
||||
if (found)
|
||||
return nullptr;
|
||||
found = singleResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
Impl.ImportedDecls[{decl->getCanonicalDecl(),
|
||||
@@ -4565,15 +4605,16 @@ namespace {
|
||||
|
||||
template <typename T, typename U>
|
||||
T *resolveSwiftDecl(const U *decl, Identifier name,
|
||||
ClangModuleUnit *clangModule) {
|
||||
bool hasKnownSwiftName, ClangModuleUnit *clangModule) {
|
||||
if (auto overlay = clangModule->getOverlayModule())
|
||||
return resolveSwiftDeclImpl<T>(decl, name, overlay);
|
||||
return resolveSwiftDeclImpl<T>(decl, name, hasKnownSwiftName, overlay);
|
||||
if (clangModule == Impl.ImportedHeaderUnit) {
|
||||
// Use an index-based loop because new owners can come in as we're
|
||||
// iterating.
|
||||
for (size_t i = 0; i < Impl.ImportedHeaderOwners.size(); ++i) {
|
||||
ModuleDecl *owner = Impl.ImportedHeaderOwners[i];
|
||||
if (T *result = resolveSwiftDeclImpl<T>(decl, name, owner))
|
||||
if (T *result = resolveSwiftDeclImpl<T>(decl, name,
|
||||
hasKnownSwiftName, owner))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -4586,7 +4627,8 @@ namespace {
|
||||
if (!importer::hasNativeSwiftDecl(decl))
|
||||
return false;
|
||||
auto wrapperUnit = cast<ClangModuleUnit>(dc->getModuleScopeContext());
|
||||
swiftDecl = resolveSwiftDecl<T>(decl, name, wrapperUnit);
|
||||
swiftDecl = resolveSwiftDecl<T>(decl, name, /*hasCustomSwiftName=*/true,
|
||||
wrapperUnit);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4615,6 +4657,7 @@ namespace {
|
||||
*correctSwiftName);
|
||||
|
||||
Identifier name = importedName.getDeclName().getBaseIdentifier();
|
||||
bool hasKnownSwiftName = importedName.hasCustomName();
|
||||
|
||||
// FIXME: Figure out how to deal with incomplete protocols, since that
|
||||
// notion doesn't exist in Swift.
|
||||
@@ -4622,6 +4665,7 @@ namespace {
|
||||
// Check if this protocol is implemented in its overlay.
|
||||
if (auto clangModule = Impl.getClangModuleForDecl(decl, true))
|
||||
if (auto native = resolveSwiftDecl<ProtocolDecl>(decl, name,
|
||||
hasKnownSwiftName,
|
||||
clangModule))
|
||||
return native;
|
||||
|
||||
@@ -4733,11 +4777,13 @@ namespace {
|
||||
*correctSwiftName);
|
||||
|
||||
auto name = importedName.getDeclName().getBaseIdentifier();
|
||||
bool hasKnownSwiftName = importedName.hasCustomName();
|
||||
|
||||
if (!decl->hasDefinition()) {
|
||||
// Check if this class is implemented in its overlay.
|
||||
if (auto clangModule = Impl.getClangModuleForDecl(decl, true)) {
|
||||
if (auto native = resolveSwiftDecl<ClassDecl>(decl, name,
|
||||
hasKnownSwiftName,
|
||||
clangModule)) {
|
||||
return native;
|
||||
}
|
||||
|
||||
@@ -1781,9 +1781,11 @@ ImportedName NameImporter::importName(const clang::NamedDecl *decl,
|
||||
ImportNameVersion version,
|
||||
clang::DeclarationName givenName) {
|
||||
CacheKeyType key(decl, version);
|
||||
if (importNameCache.count(key) && !givenName) {
|
||||
if (!givenName) {
|
||||
if (auto cachedRes = importNameCache[key]) {
|
||||
++ImportNameNumCacheHits;
|
||||
return importNameCache[key];
|
||||
return cachedRes;
|
||||
}
|
||||
}
|
||||
++ImportNameNumCacheMisses;
|
||||
auto res = importNameImpl(decl, version, givenName);
|
||||
|
||||
@@ -1393,7 +1393,7 @@ IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const {
|
||||
// Classes can be @objc.
|
||||
|
||||
// Protocols and enums can also be @objc, but this is covered by the
|
||||
// isObjC() check a the beginning.;
|
||||
// isObjC() check at the beginning.
|
||||
isObjC = shouldMarkAsObjC(VD, /*allowImplicit=*/false);
|
||||
} else if (auto enumDecl = dyn_cast<EnumDecl>(VD)) {
|
||||
// Enums can be @objc so long as they have a raw type that is representable
|
||||
|
||||
@@ -68,6 +68,62 @@ SWIFT_PROTOCOL("SwiftProto")
|
||||
id<SwiftProtoWithCustomName> _Nonnull
|
||||
convertToProto(SwiftClassWithCustomName *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS("ObjCClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface ObjCClass
|
||||
@end
|
||||
|
||||
SWIFT_CLASS("ImplicitlyObjCClass")
|
||||
@interface ImplicitlyObjCClass : ObjCClass
|
||||
@end
|
||||
void consumeImplicitlyObjCClass(ImplicitlyObjCClass *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS("ExplicitlyObjCClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface ExplicitlyObjCClass
|
||||
@end
|
||||
void consumeExplicitlyObjCClass(ExplicitlyObjCClass *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS_NAMED("HasSameCustomNameClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface HasSameCustomNameClass
|
||||
@end
|
||||
void consumeHasSameCustomNameClass(HasSameCustomNameClass *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS_NAMED("SwiftNativeTypeHasDifferentCustomNameClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface NativeTypeHasDifferentCustomNameClass
|
||||
@end
|
||||
SWIFT_CLASS_NAMED("NativeTypeHasDifferentCustomNameClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface ObjCNativeTypeHasDifferentCustomNameClass
|
||||
@end
|
||||
void consumeNativeTypeHasDifferentCustomNameClass(NativeTypeHasDifferentCustomNameClass *_Nonnull obj);
|
||||
void consumeObjCNativeTypeHasDifferentCustomNameClass(ObjCNativeTypeHasDifferentCustomNameClass *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS_NAMED("SwiftNativeTypeIsNonObjCClass")
|
||||
__attribute__((objc_root_class))
|
||||
@interface NativeTypeIsNonObjCClass
|
||||
@end
|
||||
void consumeNativeTypeIsNonObjCClass(NativeTypeIsNonObjCClass *_Nonnull obj);
|
||||
|
||||
@class ForwardImplicitlyObjCClass;
|
||||
void consumeForwardImplicitlyObjCClass(ForwardImplicitlyObjCClass *_Nonnull obj);
|
||||
|
||||
@class ForwardExplicitlyObjCClass;
|
||||
void consumeForwardExplicitlyObjCClass(ForwardExplicitlyObjCClass *_Nonnull obj);
|
||||
|
||||
@class ForwardHasSameCustomNameClass;
|
||||
void consumeForwardHasSameCustomNameClass(ForwardHasSameCustomNameClass *_Nonnull obj);
|
||||
|
||||
@class ForwardNativeTypeHasDifferentCustomNameClass;
|
||||
@class ObjCForwardNativeTypeHasDifferentCustomNameClass;
|
||||
void consumeForwardNativeTypeHasDifferentCustomNameClass(ForwardNativeTypeHasDifferentCustomNameClass *_Nonnull obj);
|
||||
void consumeObjCForwardNativeTypeHasDifferentCustomNameClass(ObjCForwardNativeTypeHasDifferentCustomNameClass *_Nonnull obj);
|
||||
|
||||
@class ForwardNativeTypeIsNonObjCClass;
|
||||
void consumeForwardNativeTypeIsNonObjCClass(ForwardNativeTypeIsNonObjCClass *_Nonnull obj);
|
||||
|
||||
SWIFT_CLASS("BOGUS")
|
||||
@interface BogusClass
|
||||
@end
|
||||
|
||||
@@ -31,3 +31,70 @@ public class CustomNameClass : CustomName {
|
||||
@objc func protoMethod()
|
||||
@objc var protoProperty: Int { get }
|
||||
}
|
||||
|
||||
@objc
|
||||
public class ObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public class ImplicitlyObjCClass : ObjCClass {
|
||||
public override init() { super.init() }
|
||||
}
|
||||
|
||||
@objc
|
||||
public class ExplicitlyObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
@objc(HasSameCustomNameClass)
|
||||
public class HasSameCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
@objc(ObjCNativeTypeHasDifferentCustomNameClass)
|
||||
public class NativeTypeHasDifferentCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
@objc(NativeTypeHasDifferentCustomNameClass)
|
||||
public class SwiftNativeTypeHasDifferentCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public class NativeTypeIsNonObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
@objc(NativeTypeIsNonObjCClass)
|
||||
public class SwiftNativeTypeIsNonObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public class ForwardImplicitlyObjCClass : ObjCClass {
|
||||
public override init() { super.init() }
|
||||
}
|
||||
|
||||
@objc
|
||||
public class ForwardExplicitlyObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
@objc(ForwardHasSameCustomNameClass)
|
||||
public class ForwardHasSameCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
@objc(ObjCForwardNativeTypeHasDifferentCustomNameClass)
|
||||
public class ForwardNativeTypeHasDifferentCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
@objc(ForwardNativeTypeHasDifferentCustomNameClass)
|
||||
public class SwiftForwardNativeTypeHasDifferentCustomNameClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public class ForwardNativeTypeIsNonObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
@objc(ForwardNativeTypeIsNonObjCClass)
|
||||
public class SwiftForwardNativeTypeIsNonObjCClass {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
@@ -32,3 +32,31 @@ func testAnyObject(_ obj: AnyObject) {
|
||||
obj.protoMethod()
|
||||
_ = obj.protoProperty
|
||||
}
|
||||
|
||||
consumeImplicitlyObjCClass(ImplicitlyObjCClass())
|
||||
|
||||
consumeExplicitlyObjCClass(ExplicitlyObjCClass())
|
||||
|
||||
consumeHasSameCustomNameClass(HasSameCustomNameClass())
|
||||
|
||||
consumeNativeTypeHasDifferentCustomNameClass(SwiftNativeTypeHasDifferentCustomNameClass())
|
||||
consumeObjCNativeTypeHasDifferentCustomNameClass(NativeTypeHasDifferentCustomNameClass())
|
||||
consumeNativeTypeHasDifferentCustomNameClass(NativeTypeHasDifferentCustomNameClass()) // expected-error {{cannot convert value of type 'NativeTypeHasDifferentCustomNameClass' to expected argument type 'SwiftNativeTypeHasDifferentCustomNameClass'}}
|
||||
consumeObjCNativeTypeHasDifferentCustomNameClass(SwiftNativeTypeHasDifferentCustomNameClass()) // expected-error {{cannot convert value of type 'SwiftNativeTypeHasDifferentCustomNameClass' to expected argument type 'NativeTypeHasDifferentCustomNameClass'}}
|
||||
|
||||
consumeNativeTypeIsNonObjCClass(SwiftNativeTypeIsNonObjCClass())
|
||||
consumeNativeTypeIsNonObjCClass(NativeTypeIsNonObjCClass()) // expected-error {{cannot convert value of type 'NativeTypeIsNonObjCClass' to expected argument type 'SwiftNativeTypeIsNonObjCClass'}}
|
||||
|
||||
consumeForwardImplicitlyObjCClass(ForwardImplicitlyObjCClass())
|
||||
|
||||
consumeForwardExplicitlyObjCClass(ForwardExplicitlyObjCClass())
|
||||
|
||||
consumeForwardHasSameCustomNameClass(ForwardHasSameCustomNameClass())
|
||||
|
||||
consumeForwardNativeTypeHasDifferentCustomNameClass(SwiftForwardNativeTypeHasDifferentCustomNameClass())
|
||||
consumeObjCForwardNativeTypeHasDifferentCustomNameClass(ForwardNativeTypeHasDifferentCustomNameClass())
|
||||
consumeForwardNativeTypeHasDifferentCustomNameClass(ForwardNativeTypeHasDifferentCustomNameClass()) // expected-error {{cannot convert value of type 'ForwardNativeTypeHasDifferentCustomNameClass' to expected argument type 'SwiftForwardNativeTypeHasDifferentCustomNameClass'}}
|
||||
consumeObjCForwardNativeTypeHasDifferentCustomNameClass(SwiftForwardNativeTypeHasDifferentCustomNameClass()) // expected-error {{cannot convert value of type 'SwiftForwardNativeTypeHasDifferentCustomNameClass' to expected argument type 'ForwardNativeTypeHasDifferentCustomNameClass'}}
|
||||
|
||||
consumeForwardNativeTypeIsNonObjCClass(SwiftForwardNativeTypeIsNonObjCClass())
|
||||
consumeForwardNativeTypeIsNonObjCClass(ForwardNativeTypeIsNonObjCClass()) // expected-error {{cannot convert value of type 'ForwardNativeTypeIsNonObjCClass' to expected argument type 'SwiftForwardNativeTypeIsNonObjCClass'}}
|
||||
|
||||
Reference in New Issue
Block a user