Skip to content

Commit 91d1c3b

Browse files
committed
Clang importer: use importFullName for factory methods as initializers.
Eliminates one of the redundant places where we map Objective-C selectors over to Swift names.
1 parent fedb6a8 commit 91d1c3b

File tree

3 files changed

+28
-131
lines changed

3 files changed

+28
-131
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ STATISTIC(NumMultiMethodNames,
7474
"multi-part selector method names imported");
7575
STATISTIC(NumMethodsMissingFirstArgName,
7676
"selectors where the first argument name is missing");
77-
STATISTIC(NumFactoryMethodsNullary,
78-
"# of factory methods not mapped due to nullary with long name");
7977
STATISTIC(NumInitsDroppedWith,
8078
"# of initializer selectors from which \"with\" was dropped");
8179
STATISTIC(NumInitsPrepositionSplit,
@@ -1731,9 +1729,11 @@ auto ClangImporter::Implementation::importFullName(
17311729

17321730
// Set the first argument name to be the name we computed. If
17331731
// there is no first argument, create one for this purpose.
1734-
if (argumentNames.empty() && !argName.empty()) {
1735-
// FIXME: Record what happened here for the caller?
1736-
argumentNames.push_back(argName);
1732+
if (argumentNames.empty()) {
1733+
if (!argName.empty()) {
1734+
// FIXME: Record what happened here for the caller?
1735+
argumentNames.push_back(argName);
1736+
}
17371737
} else {
17381738
argumentNames[0] = argName;
17391739
}
@@ -1881,6 +1881,12 @@ auto ClangImporter::Implementation::importFullName(
18811881
if (isInitializer) {
18821882
// For initializers, prepend "__" to the first argument name.
18831883
if (argumentNames.empty()) {
1884+
// FIXME: ... unless it was from a factory method, for historical
1885+
// reasons.
1886+
if (result.InitKind == CtorInitializerKind::Factory ||
1887+
result.InitKind == CtorInitializerKind::ConvenienceFactory)
1888+
return result;
1889+
18841890
// FIXME: Record that we did this.
18851891
argumentNames.push_back("__");
18861892
} else {
@@ -2196,50 +2202,6 @@ ClangImporter::Implementation::mapSelectorToDeclName(ObjCSelector selector,
21962202
return result;
21972203
}
21982204

2199-
DeclName ClangImporter::Implementation::mapFactorySelectorToInitializerName(
2200-
ObjCSelector selector,
2201-
StringRef className,
2202-
bool isSwiftPrivate) {
2203-
// See if we can match the class name to the beginning of the first selector
2204-
// piece.
2205-
auto firstPiece = selector.getSelectorPieces()[0];
2206-
StringRef firstArgLabel = matchLeadingTypeName(firstPiece.str(), className);
2207-
if (firstArgLabel.size() == firstPiece.str().size())
2208-
return DeclName();
2209-
2210-
// Form the first argument label.
2211-
llvm::SmallString<32> scratch;
2212-
SmallVector<Identifier, 4> argumentNames;
2213-
argumentNames.push_back(
2214-
importArgName(SwiftContext,
2215-
camel_case::toLowercaseWord(firstArgLabel, scratch),
2216-
/*dropWith=*/true,
2217-
isSwiftPrivate));
2218-
2219-
// Handle nullary factory methods.
2220-
if (selector.getNumArgs() == 0) {
2221-
if (argumentNames[0].empty())
2222-
return DeclName(SwiftContext, SwiftContext.Id_init, { });
2223-
2224-
// We don't have a convenience place to put the remaining argument name,
2225-
// so leave it as a factory method.
2226-
++NumFactoryMethodsNullary;
2227-
return DeclName();
2228-
}
2229-
2230-
// Map the remaining selector pieces.
2231-
for (auto piece : selector.getSelectorPieces().slice(1)) {
2232-
if (piece.empty())
2233-
argumentNames.push_back(piece);
2234-
else
2235-
argumentNames.push_back(importArgName(SwiftContext, piece.str(),
2236-
/*dropWith=*/false,
2237-
/*isSwiftPrivate=*/false));
2238-
}
2239-
2240-
return DeclName(SwiftContext, SwiftContext.Id_init, argumentNames);
2241-
}
2242-
22432205
/// Translate the "nullability" notion from API notes into an optional type
22442206
/// kind.
22452207
OptionalTypeKind ClangImporter::Implementation::translateNullability(
@@ -2676,6 +2638,11 @@ bool ClangImporter::Implementation::shouldImportAsInitializer(
26762638
if (firstArgLabel.size() == firstPiece.size())
26772639
return false;
26782640

2641+
// FIXME: Factory methods cannot have dummy parameters added for
2642+
// historical reasons.
2643+
if (!firstArgLabel.empty() && method->getSelector().getNumArgs() == 0)
2644+
return false;
2645+
26792646
// Store the prefix length.
26802647
prefixLength = firstPiece.size() - firstArgLabel.size();
26812648

lib/ClangImporter/ImportDecl.cpp

Lines changed: 12 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@
4848
#define DEBUG_TYPE "Clang module importer"
4949

5050
STATISTIC(NumTotalImportedEntities, "# of imported clang entities");
51-
STATISTIC(NumFactoryMethodsWrongResult,
52-
"# of factory methods not mapped due to an incorrect result type");
5351
STATISTIC(NumFactoryMethodsAsInitializers,
5452
"# of factory methods mapped to initializers");
5553

@@ -2783,75 +2781,22 @@ namespace {
27832781
const clang::ObjCMethodDecl *decl,
27842782
ObjCSelector selector,
27852783
DeclContext *dc) {
2786-
// Only class methods can be mapped to constructors.
2787-
if (!decl->isClassMethod())
2788-
return None;
2789-
2790-
// Said class methods must be in an actual class.
2791-
auto objcClass = decl->getClassInterface();
2792-
if (!objcClass)
2793-
return None;
2794-
2795-
DeclName initName;
2796-
bool hasCustomName;
2797-
2798-
// Check whether we're allowed to try.
2799-
switch (Impl.getFactoryAsInit(objcClass, decl)) {
2800-
case FactoryAsInitKind::AsInitializer:
2801-
if (decl->hasAttr<clang::SwiftNameAttr>()) {
2802-
auto importedName = Impl.importFullName(decl);
2803-
initName = importedName.Imported;
2804-
hasCustomName = importedName.HasCustomName;
2805-
break;
2806-
}
2807-
// FIXME: We probably should stop using this codepath. It won't ever
2808-
// succeed.
2809-
SWIFT_FALLTHROUGH;
2810-
2811-
case FactoryAsInitKind::Infer: {
2812-
// Check whether the name fits the pattern.
2813-
bool isSwiftPrivate = decl->hasAttr<clang::SwiftPrivateAttr>();
2814-
initName =
2815-
Impl.mapFactorySelectorToInitializerName(selector,
2816-
objcClass->getName(),
2817-
isSwiftPrivate);
2818-
hasCustomName = false;
2819-
break;
2820-
}
2821-
case FactoryAsInitKind::AsClassMethod:
2822-
return None;
2823-
}
2784+
// Import the full name of the method.
2785+
auto importedName = Impl.importFullName(decl);
28242786

2825-
if (!initName)
2826-
return None;
2787+
// Check that we imported an initializer name.
2788+
DeclName initName = importedName;
2789+
if (initName.getBaseName() != Impl.SwiftContext.Id_init) return None;
28272790

2828-
// Check the result type to determine what kind of initializer we can
2829-
// create (if any).
2830-
CtorInitializerKind initKind;
2831-
if (decl->hasRelatedResultType()) {
2832-
// instancetype factory methods become convenience factory initializers.
2833-
initKind = CtorInitializerKind::ConvenienceFactory;
2834-
} else if (auto objcPtr = decl->getReturnType()
2835-
->getAs<clang::ObjCObjectPointerType>()) {
2836-
if (objcPtr->getInterfaceDecl() == objcClass) {
2837-
initKind = CtorInitializerKind::Factory;
2838-
} else {
2839-
// FIXME: Could allow a subclass here, but the rest of the compiler
2840-
// isn't prepared for that yet.
2841-
// Not a factory method.
2842-
++NumFactoryMethodsWrongResult;
2843-
return None;
2844-
}
2845-
} else {
2846-
// Not a factory method.
2847-
++NumFactoryMethodsWrongResult;
2791+
// ... that came from a factory method.
2792+
if (importedName.InitKind != CtorInitializerKind::Factory &&
2793+
importedName.InitKind != CtorInitializerKind::ConvenienceFactory)
28482794
return None;
2849-
}
28502795

28512796
bool redundant = false;
2852-
auto result = importConstructor(decl, dc, false, initKind,
2797+
auto result = importConstructor(decl, dc, false, importedName.InitKind,
28532798
/*required=*/false, selector, initName,
2854-
hasCustomName,
2799+
importedName.HasCustomName,
28552800
{decl->param_begin(), decl->param_size()},
28562801
decl->isVariadic(), redundant);
28572802
if (result)
@@ -2865,7 +2810,8 @@ namespace {
28652810
// TODO: Could add a replacement string?
28662811
llvm::SmallString<64> message;
28672812
llvm::raw_svector_ostream os(message);
2868-
os << "use object construction '" << objcClass->getName() << "(";
2813+
os << "use object construction '"
2814+
<< decl->getClassInterface()->getName() << "(";
28692815
for (auto arg : initName.getArgumentNames()) {
28702816
os << arg << ":";
28712817
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -809,22 +809,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
809809
DeclName mapSelectorToDeclName(ObjCSelector selector, bool isInitializer,
810810
bool isSwiftPrivate);
811811

812-
/// Try to map the given selector, which may be the name of a factory method,
813-
/// to the name of an initializer.
814-
///
815-
/// \param selector The selector to map.
816-
///
817-
/// \param className The name of the class in which the method occurs.
818-
///
819-
/// \param isSwiftPrivate Whether this name is for a declaration marked with
820-
/// the 'swift_private' attribute.
821-
///
822-
/// \returns the initializer name for this factory method, or an empty
823-
/// name if this selector does not fit the pattern.
824-
DeclName mapFactorySelectorToInitializerName(ObjCSelector selector,
825-
StringRef className,
826-
bool isSwiftPrivate);
827-
828812
/// \brief Import the given Swift source location into Clang.
829813
clang::SourceLocation exportSourceLoc(SourceLoc loc);
830814

0 commit comments

Comments
 (0)