[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:
Jordan Rose
2019-10-25 15:16:14 -07:00
committed by GitHub
parent 220c4771cf
commit 42f72cb0d0
4 changed files with 20 additions and 72 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}