mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ClangImporter] Compute initializer kinds up front (#27870)
Previously we only did this for factory methods, but there's no reason why we can't do it for regular init methods too, and doing so simplifies the signature of SwiftDeclConverter::importConstructor. Also remove some indirection through helper functions in ClangAdapter. These were more useful back when Swift looked directly at API notes instead of relying on Clang turning them into attributes; now they're just an extra hop for no reason.
This commit is contained in:
@@ -601,29 +601,6 @@ OptionalTypeKind importer::translateNullability(clang::NullabilityKind kind) {
|
||||
llvm_unreachable("Invalid NullabilityKind.");
|
||||
}
|
||||
|
||||
bool importer::hasDesignatedInitializers(
|
||||
const clang::ObjCInterfaceDecl *classDecl) {
|
||||
if (classDecl->hasDesignatedInitializers())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool importer::isDesignatedInitializer(
|
||||
const clang::ObjCInterfaceDecl *classDecl,
|
||||
const clang::ObjCMethodDecl *method) {
|
||||
// If the information is on the AST, use it.
|
||||
if (classDecl->hasDesignatedInitializers()) {
|
||||
auto *methodParent = method->getClassInterface();
|
||||
if (!methodParent ||
|
||||
methodParent->getCanonicalDecl() == classDecl->getCanonicalDecl()) {
|
||||
return method->hasAttr<clang::ObjCDesignatedInitializerAttr>();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool importer::isRequiredInitializer(const clang::ObjCMethodDecl *method) {
|
||||
// FIXME: No way to express this in Objective-C.
|
||||
return false;
|
||||
|
||||
@@ -111,15 +111,6 @@ bool hasNativeSwiftDecl(const clang::Decl *decl);
|
||||
/// Translation API nullability from an API note into an optional kind.
|
||||
OptionalTypeKind translateNullability(clang::NullabilityKind kind);
|
||||
|
||||
/// Determine whether the given class has designated initializers,
|
||||
/// consulting
|
||||
bool hasDesignatedInitializers(const clang::ObjCInterfaceDecl *classDecl);
|
||||
|
||||
/// Determine whether the given method is a designated initializer
|
||||
/// of the given class.
|
||||
bool isDesignatedInitializer(const clang::ObjCInterfaceDecl *classDecl,
|
||||
const clang::ObjCMethodDecl *method);
|
||||
|
||||
/// Determine whether the given method is a required initializer
|
||||
/// of the given class.
|
||||
bool isRequiredInitializer(const clang::ObjCMethodDecl *method);
|
||||
|
||||
@@ -4415,7 +4415,7 @@ namespace {
|
||||
ConstructorDecl *importConstructor(const clang::ObjCMethodDecl *objcMethod,
|
||||
DeclContext *dc,
|
||||
bool implicit,
|
||||
Optional<CtorInitializerKind> kindIn,
|
||||
CtorInitializerKind kind,
|
||||
bool required,
|
||||
ObjCSelector selector,
|
||||
ImportedName importedName,
|
||||
@@ -6081,9 +6081,10 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
|
||||
}
|
||||
|
||||
bool redundant;
|
||||
auto result =
|
||||
importConstructor(objcMethod, dc, implicit, kind, required, selector,
|
||||
importedName, params, variadic, redundant);
|
||||
auto result = importConstructor(objcMethod, dc, implicit,
|
||||
kind.getValueOr(importedName.getInitKind()),
|
||||
required, selector, importedName, params,
|
||||
variadic, redundant);
|
||||
|
||||
// If this is a compatibility stub, mark it as such.
|
||||
if (result && correctSwiftName)
|
||||
@@ -6193,7 +6194,7 @@ bool SwiftDeclConverter::existingConstructorIsWorse(
|
||||
/// constructor declaration appropriately.
|
||||
ConstructorDecl *SwiftDeclConverter::importConstructor(
|
||||
const clang::ObjCMethodDecl *objcMethod, DeclContext *dc, bool implicit,
|
||||
Optional<CtorInitializerKind> kindIn, bool required, ObjCSelector selector,
|
||||
CtorInitializerKind kind, bool required, ObjCSelector selector,
|
||||
ImportedName importedName, ArrayRef<const clang::ParmVarDecl *> args,
|
||||
bool variadic, bool &redundant) {
|
||||
redundant = false;
|
||||
@@ -6202,35 +6203,6 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
|
||||
auto ownerNominal = dc->getSelfNominalTypeDecl();
|
||||
assert(ownerNominal && "Method in non-type context?");
|
||||
|
||||
// Find the interface, if we can.
|
||||
const clang::ObjCInterfaceDecl *interface = nullptr;
|
||||
if (auto classDecl = dyn_cast<ClassDecl>(ownerNominal)) {
|
||||
interface =
|
||||
dyn_cast_or_null<clang::ObjCInterfaceDecl>(classDecl->getClangDecl());
|
||||
}
|
||||
|
||||
// If we weren't told what kind of initializer this should be,
|
||||
// figure it out now.
|
||||
CtorInitializerKind kind;
|
||||
|
||||
if (kindIn) {
|
||||
kind = *kindIn;
|
||||
|
||||
// If we know this is a designated initializer, mark it as such.
|
||||
if (interface && hasDesignatedInitializers(interface) &&
|
||||
isDesignatedInitializer(interface, objcMethod))
|
||||
kind = CtorInitializerKind::Designated;
|
||||
} else {
|
||||
// If the owning Objective-C class has designated initializers and this
|
||||
// is not one of them, treat it as a convenience initializer.
|
||||
if (interface && hasDesignatedInitializers(interface) &&
|
||||
!isDesignatedInitializer(interface, objcMethod)) {
|
||||
kind = CtorInitializerKind::Convenience;
|
||||
} else {
|
||||
kind = CtorInitializerKind::Designated;
|
||||
}
|
||||
}
|
||||
|
||||
// Import the type that this method will have.
|
||||
Optional<ForeignErrorConvention> errorConvention;
|
||||
ParameterList *bodyParams;
|
||||
@@ -7274,9 +7246,9 @@ void SwiftDeclConverter::importInheritedConstructors(
|
||||
};
|
||||
|
||||
// The kind of initializer to import. If this class has designated
|
||||
// initializers, everything it imports is a convenience initializer.
|
||||
// initializers, everything it inherits is a convenience initializer.
|
||||
Optional<CtorInitializerKind> kind;
|
||||
if (hasDesignatedInitializers(curObjCClass))
|
||||
if (curObjCClass->hasDesignatedInitializers())
|
||||
kind = CtorInitializerKind::Convenience;
|
||||
|
||||
|
||||
|
||||
@@ -740,9 +740,7 @@ getFactoryAsInit(const clang::ObjCInterfaceDecl *classDecl,
|
||||
/// should be stripped from the first selector piece, e.g., "init"
|
||||
/// or the restated name of the class in a factory method.
|
||||
///
|
||||
/// \param kind Will be set to the kind of initializer being
|
||||
/// imported. Note that this does not distinguish designated
|
||||
/// vs. convenience; both will be classified as "designated".
|
||||
/// \param kind Will be set to the kind of initializer being imported.
|
||||
static bool shouldImportAsInitializer(const clang::ObjCMethodDecl *method,
|
||||
ImportNameVersion version,
|
||||
unsigned &prefixLength,
|
||||
@@ -750,7 +748,17 @@ static bool shouldImportAsInitializer(const clang::ObjCMethodDecl *method,
|
||||
/// Is this an initializer?
|
||||
if (isInitMethod(method)) {
|
||||
prefixLength = 4;
|
||||
kind = CtorInitializerKind::Designated;
|
||||
|
||||
// If the owning Objective-C class has designated initializers and this
|
||||
// is not one of them, treat it as a convenience initializer.
|
||||
const clang::ObjCInterfaceDecl *interface = method->getClassInterface();
|
||||
if (interface && interface->hasDesignatedInitializers() &&
|
||||
!method->hasAttr<clang::ObjCDesignatedInitializerAttr>()) {
|
||||
kind = CtorInitializerKind::Convenience;
|
||||
} else {
|
||||
kind = CtorInitializerKind::Designated;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user