Skip to content

Commit 4c50598

Browse files
committed
Clang importer: switch method name import to importFullName().
This lets us kill the redundant Objective-C selector to DeclName mapping used only for methods.
1 parent 3102e23 commit 4c50598

File tree

3 files changed

+50
-214
lines changed

3 files changed

+50
-214
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 33 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
#include "clang/Rewrite/Frontend/Rewriters.h"
5252
#include "clang/Sema/Lookup.h"
5353
#include "clang/Sema/Sema.h"
54-
#include "llvm/ADT/Statistic.h"
5554
#include "llvm/ADT/STLExtras.h"
5655
#include "llvm/Support/CrashRecoveryContext.h"
5756
#include "llvm/Support/Path.h"
@@ -60,27 +59,6 @@
6059

6160
using namespace swift;
6261

63-
//===--------------------------------------------------------------------===//
64-
// Importer statistics
65-
//===--------------------------------------------------------------------===//
66-
#define DEBUG_TYPE "Clang module importer"
67-
STATISTIC(NumNullaryMethodNames,
68-
"nullary selectors imported");
69-
STATISTIC(NumUnaryMethodNames,
70-
"unary selectors imported");
71-
STATISTIC(NumNullaryInitMethodsMadeUnary,
72-
"nullary Objective-C init methods turned into unary initializers");
73-
STATISTIC(NumMultiMethodNames,
74-
"multi-part selector method names imported");
75-
STATISTIC(NumMethodsMissingFirstArgName,
76-
"selectors where the first argument name is missing");
77-
STATISTIC(NumInitsDroppedWith,
78-
"# of initializer selectors from which \"with\" was dropped");
79-
STATISTIC(NumInitsPrepositionSplit,
80-
"# of initializer selectors where the split was on a preposition");
81-
STATISTIC(NumInitsNonPrepositionSplit,
82-
"# of initializer selectors where the split wasn't on a preposition");
83-
8462
// Commonly-used Clang classes.
8563
using clang::CompilerInstance;
8664
using clang::CompilerInvocation;
@@ -725,7 +703,7 @@ void ClangImporter::Implementation::addEntryToLookupTable(
725703
if (!suppressDecl) {
726704
// If we have a name to import as, add this entry to the table.
727705
clang::DeclContext *effectiveContext;
728-
if (DeclName name = importFullName(named, &effectiveContext)) {
706+
if (DeclName name = importFullName(named, None, &effectiveContext)) {
729707
table.addEntry(name, named, effectiveContext);
730708
}
731709
}
@@ -1636,6 +1614,7 @@ static bool shouldMakeSelectorNonVariadic(clang::Selector selector) {
16361614

16371615
auto ClangImporter::Implementation::importFullName(
16381616
const clang::NamedDecl *D,
1617+
ImportNameOptions options,
16391618
clang::DeclContext **effectiveContext) -> ImportedName {
16401619
ImportedName result;
16411620

@@ -1680,20 +1659,36 @@ auto ClangImporter::Implementation::importFullName(
16801659

16811660
// If we have a swift_name attribute, use that.
16821661
if (auto *nameAttr = D->getAttr<clang::SwiftNameAttr>()) {
1662+
bool skipCustomName = false;
1663+
16831664
// If we have an Objective-C method that is being mapped to an
16841665
// initializer (e.g., a factory method whose name doesn't fit the
16851666
// convention for factory methods), make sure that it can be
16861667
// imported as an initializer.
16871668
if (auto method = dyn_cast<clang::ObjCMethodDecl>(D)) {
16881669
unsigned initPrefixLength;
1689-
if (nameAttr->getName().startswith("init(") &&
1690-
!shouldImportAsInitializer(method, initPrefixLength, result.InitKind))
1691-
return { };
1670+
if (nameAttr->getName().startswith("init(")) {
1671+
if (!shouldImportAsInitializer(method, initPrefixLength,
1672+
result.InitKind)) {
1673+
// We cannot import this as an initializer anyway.
1674+
return { };
1675+
}
1676+
1677+
// If this swift_name attribute maps a factory method to an
1678+
// initializer and we were asked not to do so, ignore the
1679+
// custom name.
1680+
if (options.contains(ImportNameFlags::SuppressFactoryMethodAsInit) &&
1681+
(result.InitKind == CtorInitializerKind::Factory ||
1682+
result.InitKind == CtorInitializerKind::ConvenienceFactory))
1683+
skipCustomName = true;
1684+
}
16921685
}
16931686

1694-
result.HasCustomName = true;
1695-
result.Imported = parseDeclName(SwiftContext, nameAttr->getName());
1696-
return result;
1687+
if (!skipCustomName) {
1688+
result.HasCustomName = true;
1689+
result.Imported = parseDeclName(SwiftContext, nameAttr->getName());
1690+
return result;
1691+
}
16971692
}
16981693

16991694
// For empty names, there is nothing to do.
@@ -1728,6 +1723,15 @@ auto ClangImporter::Implementation::importFullName(
17281723
isInitializer = shouldImportAsInitializer(objcMethod, initializerPrefixLen,
17291724
result.InitKind);
17301725

1726+
// If we would import a factory method as an initializer but were
1727+
// asked not to, don't consider this as an initializer.
1728+
if (isInitializer &&
1729+
options.contains(ImportNameFlags::SuppressFactoryMethodAsInit) &&
1730+
(result.InitKind == CtorInitializerKind::Factory ||
1731+
result.InitKind == CtorInitializerKind::ConvenienceFactory)) {
1732+
isInitializer = false;
1733+
}
1734+
17311735
// Map the Objective-C selector directly.
17321736
auto selector = D->getDeclName().getObjCSelector();
17331737
if (isInitializer)
@@ -1997,139 +2001,6 @@ ClangImporter::Implementation::importIdentifier(
19972001
return SwiftContext.getIdentifier(name);
19982002
}
19992003

2000-
/// Import an argument name.
2001-
static Identifier importArgName(ASTContext &ctx, StringRef name,
2002-
bool dropWith, bool isSwiftPrivate) {
2003-
// Simple case: empty name.
2004-
if (name.empty()) {
2005-
if (isSwiftPrivate)
2006-
return ctx.getIdentifier("__");
2007-
return Identifier();
2008-
}
2009-
2010-
SmallString<32> scratch;
2011-
auto words = camel_case::getWords(name);
2012-
auto firstWord = *words.begin();
2013-
StringRef argName = name;
2014-
2015-
// If we're dropping "with", handle that now.
2016-
if (dropWith) {
2017-
// If the first word is "with"...
2018-
if (name.size() > 4 &&
2019-
camel_case::sameWordIgnoreFirstCase(firstWord, "with")) {
2020-
// Drop it.
2021-
++NumInitsDroppedWith;
2022-
2023-
auto iter = words.begin();
2024-
++iter;
2025-
2026-
argName = name.substr(iter.getPosition());
2027-
// Don't drop "with" if the resulting arg is a reserved name.
2028-
if (ClangImporter::Implementation::isSwiftReservedName(
2029-
camel_case::toLowercaseWord(argName, scratch))) {
2030-
argName = name;
2031-
}
2032-
} else {
2033-
// If we're tracking statistics, check whether the name starts with
2034-
// a preposition.
2035-
if (llvm::AreStatisticsEnabled()) {
2036-
if (getPrepositionKind(firstWord))
2037-
++NumInitsPrepositionSplit;
2038-
else
2039-
++NumInitsNonPrepositionSplit;
2040-
}
2041-
2042-
argName = name;
2043-
}
2044-
}
2045-
2046-
/// Lowercase the first word to form the argument name.
2047-
argName = camel_case::toLowercaseWord(argName, scratch);
2048-
if (!isSwiftPrivate)
2049-
return ctx.getIdentifier(argName);
2050-
2051-
SmallString<32> prefixed{"__"};
2052-
prefixed.append(argName);
2053-
return ctx.getIdentifier(prefixed.str());
2054-
}
2055-
2056-
/// Map an Objective-C selector name to a Swift method name.
2057-
static DeclName mapSelectorName(ASTContext &ctx,
2058-
ObjCSelector selector,
2059-
bool isInitializer,
2060-
bool isSwiftPrivate) {
2061-
// Zero-argument selectors.
2062-
if (selector.getNumArgs() == 0) {
2063-
++NumNullaryMethodNames;
2064-
2065-
auto name = selector.getSelectorPieces()[0];
2066-
StringRef nameText = name.empty()? "" : name.str();
2067-
2068-
if (!isInitializer) {
2069-
if (!isSwiftPrivate)
2070-
return DeclName(ctx, name, {});
2071-
2072-
SmallString<32> newName{"__"};
2073-
newName.append(nameText);
2074-
return DeclName(ctx, ctx.getIdentifier(newName.str()), {});
2075-
}
2076-
2077-
// Simple case for initializers.
2078-
if (nameText == "init" && !isSwiftPrivate)
2079-
return DeclName(ctx, name, { });
2080-
2081-
// This is an initializer with no parameters but a name that
2082-
// contains more than 'init', so synthesize an argument to capture
2083-
// what follows 'init'.
2084-
++NumNullaryInitMethodsMadeUnary;
2085-
assert(camel_case::getFirstWord(nameText).equals("init"));
2086-
auto baseName = ctx.Id_init;
2087-
auto argName = importArgName(ctx, nameText.substr(4), /*dropWith=*/true,
2088-
isSwiftPrivate);
2089-
return DeclName(ctx, baseName, argName);
2090-
}
2091-
2092-
// Determine the base name and first argument name.
2093-
Identifier baseName;
2094-
SmallVector<Identifier, 2> argumentNames;
2095-
Identifier firstPiece = selector.getSelectorPieces()[0];
2096-
StringRef firstPieceText = firstPiece.empty()? "" : firstPiece.str();
2097-
if (isInitializer) {
2098-
assert(camel_case::getFirstWord(firstPieceText).equals("init"));
2099-
baseName = ctx.Id_init;
2100-
argumentNames.push_back(importArgName(ctx, firstPieceText.substr(4),
2101-
/*dropWith=*/true, isSwiftPrivate));
2102-
} else {
2103-
baseName = firstPiece;
2104-
if (isSwiftPrivate) {
2105-
SmallString<32> newName{"__"};
2106-
newName.append(firstPieceText);
2107-
baseName = ctx.getIdentifier(newName);
2108-
}
2109-
argumentNames.push_back(Identifier());
2110-
}
2111-
2112-
if (argumentNames[0].empty())
2113-
++NumMethodsMissingFirstArgName;
2114-
2115-
// Determine the remaining argument names.
2116-
unsigned n = selector.getNumArgs();
2117-
if (n == 1)
2118-
++NumUnaryMethodNames;
2119-
else
2120-
++NumMultiMethodNames;
2121-
2122-
for (auto piece : selector.getSelectorPieces().slice(1)) {
2123-
if (piece.empty())
2124-
argumentNames.push_back(piece);
2125-
else
2126-
argumentNames.push_back(importArgName(ctx, piece.str(),
2127-
/*dropWith=*/false,
2128-
/*isSwiftPrivate=*/false));
2129-
}
2130-
return DeclName(ctx, baseName, argumentNames);
2131-
}
2132-
21332004
namespace {
21342005
/// Function object used to create Clang selectors from strings.
21352006
class CreateSelector {
@@ -2230,26 +2101,6 @@ ClangImporter::Implementation::exportSelector(ObjCSelector selector) {
22302101
pieces.data());
22312102
}
22322103

2233-
2234-
DeclName
2235-
ClangImporter::Implementation::mapSelectorToDeclName(ObjCSelector selector,
2236-
bool isInitializer,
2237-
bool isSwiftPrivate)
2238-
{
2239-
// Check whether we've already mapped this selector.
2240-
auto known = SelectorMappings.find({selector, isInitializer});
2241-
if (known != SelectorMappings.end())
2242-
return known->second;
2243-
2244-
// Map the selector.
2245-
auto result = mapSelectorName(SwiftContext, selector, isInitializer,
2246-
isSwiftPrivate);
2247-
2248-
// Cache the result and return.
2249-
SelectorMappings[{selector, isInitializer}] = result;
2250-
return result;
2251-
}
2252-
22532104
/// Translate the "nullability" notion from API notes into an optional type
22542105
/// kind.
22552106
OptionalTypeKind ClangImporter::Implementation::translateNullability(

lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,22 +2854,11 @@ namespace {
28542854
if (methodAlreadyImported(selector, isInstance, dc))
28552855
return nullptr;
28562856

2857-
DeclName name;
2858-
bool hasCustomName;
2859-
if (auto *customNameAttr = decl->getAttr<clang::SwiftNameAttr>()) {
2860-
if (!customNameAttr->getName().startswith("init(")) {
2861-
auto importedName = Impl.importFullName(decl);
2862-
name = importedName.Imported;
2863-
hasCustomName = importedName.HasCustomName;
2864-
}
2865-
}
2866-
if (!name) {
2867-
hasCustomName = false;
2868-
bool isSwiftPrivate = decl->hasAttr<clang::SwiftPrivateAttr>();
2869-
name = Impl.mapSelectorToDeclName(selector, /*isInitializer=*/false,
2870-
isSwiftPrivate);
2871-
}
2872-
if (!name)
2857+
auto importedName
2858+
= Impl.importFullName(decl,
2859+
ClangImporter::Implementation::ImportNameFlags
2860+
::SuppressFactoryMethodAsInit);
2861+
if (!importedName)
28732862
return nullptr;
28742863

28752864
assert(dc->getDeclaredTypeOfContext() && "Method in non-type context?");
@@ -2897,6 +2886,7 @@ namespace {
28972886
kind = SpecialMethodKind::NSDictionarySubscriptGetter;
28982887

28992888
// Import the type that this method will have.
2889+
DeclName name = importedName.Imported;
29002890
Optional<ForeignErrorConvention> errorConvention;
29012891
auto type = Impl.importMethodType(decl,
29022892
decl->getReturnType(),
@@ -2905,7 +2895,7 @@ namespace {
29052895
decl->isVariadic(),
29062896
decl->hasAttr<clang::NoReturnAttr>(),
29072897
isInSystemModule(dc),
2908-
hasCustomName,
2898+
importedName.HasCustomName,
29092899
bodyPatterns,
29102900
name,
29112901
errorConvention,

lib/ClangImporter/ImporterImpl.h

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
310310
llvm::SmallDenseMap<const clang::TypedefNameDecl *, MappedTypeNameKind, 16>
311311
SpecialTypedefNames;
312312

313-
/// Mapping from Objective-C selectors to method names.
314-
llvm::DenseMap<std::pair<ObjCSelector, char>, DeclName> SelectorMappings;
315-
316313
/// Is the given identifier a reserved name in Swift?
317314
static bool isSwiftReservedName(StringRef name);
318315

@@ -769,6 +766,15 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
769766
explicit operator bool() const { return static_cast<bool>(Imported); }
770767
};
771768

769+
/// Flags that control the import of names in importFullName.
770+
enum class ImportNameFlags {
771+
/// Suppress the factory-method-as-initializer transformation.
772+
SuppressFactoryMethodAsInit = 0x01,
773+
};
774+
775+
/// Options that control the import of names in importFullName.
776+
typedef OptionSet<ImportNameFlags> ImportNameOptions;
777+
772778
/// Imports the full name of the given Clang declaration into Swift.
773779
///
774780
/// Note that this may result in a name very different from the Clang name,
@@ -781,6 +787,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
781787
/// This can differ from D's redeclaration context when the Clang importer
782788
/// introduces nesting, e.g., for enumerators within an NS_ENUM.
783789
ImportedName importFullName(const clang::NamedDecl *D,
790+
ImportNameOptions options = None,
784791
clang::DeclContext **effectiveContext = nullptr);
785792

786793
/// \brief Import the given Clang identifier into Swift.
@@ -802,18 +809,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
802809
/// Export a Swift Objective-C selector as a Clang Objective-C selector.
803810
clang::Selector exportSelector(ObjCSelector selector);
804811

805-
/// Map the given selector to a declaration name.
806-
///
807-
/// \param selector The selector to map.
808-
///
809-
/// \param isInitializer Whether this name should be mapped as an
810-
/// initializer.
811-
///
812-
/// \param isSwiftPrivate Whether this name is for a declaration marked with
813-
/// the 'swift_private' attribute.
814-
DeclName mapSelectorToDeclName(ObjCSelector selector, bool isInitializer,
815-
bool isSwiftPrivate);
816-
817812
/// \brief Import the given Swift source location into Clang.
818813
clang::SourceLocation exportSourceLoc(SourceLoc loc);
819814

0 commit comments

Comments
 (0)