Skip to content

Commit a861a73

Browse files
committed
Clang importer: introduce "importFullName" to centralize name-mapping logic.
The Swift lookup tables are the primary client and test vehicle right now. This change adds the capability to use the swift_name attribute to rename C functions when they are imported into Swift, as well as handling the swift_private attribute more uniformly. There are a few obvious places where I've applied this API to eliminate redundancy. Expect it to broaden as the API fills out more.
1 parent c2bf16c commit a861a73

File tree

5 files changed

+231
-55
lines changed

5 files changed

+231
-55
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 202 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -743,8 +743,8 @@ bool ClangImporter::Implementation::importHeader(
743743

744744
if (UseSwiftLookupTables) {
745745
if (auto named = dyn_cast<clang::NamedDecl>(D)) {
746-
Identifier name = importName(named);
747-
if (!name.empty())
746+
bool hasCustomName;
747+
if (DeclName name = importFullName(named, hasCustomName))
748748
BridgingHeaderLookupTable.addEntry(name, named);
749749
}
750750
}
@@ -1288,6 +1288,206 @@ ClangImporter::Implementation::exportName(Identifier name) {
12881288
return ident;
12891289
}
12901290

1291+
/// Parse a stringified Swift DeclName, e.g. "init(frame:)".
1292+
static DeclName parseDeclName(ASTContext &ctx, StringRef Name) {
1293+
if (Name.back() != ')') {
1294+
if (Lexer::isIdentifier(Name) && Name != "_")
1295+
return ctx.getIdentifier(Name);
1296+
1297+
return {};
1298+
}
1299+
1300+
StringRef BaseName, Parameters;
1301+
std::tie(BaseName, Parameters) = Name.split('(');
1302+
if (!Lexer::isIdentifier(BaseName) || BaseName == "_")
1303+
return {};
1304+
1305+
if (Parameters.empty())
1306+
return {};
1307+
Parameters = Parameters.drop_back(); // ')'
1308+
1309+
Identifier BaseID = ctx.getIdentifier(BaseName);
1310+
if (Parameters.empty())
1311+
return DeclName(ctx, BaseID, {});
1312+
1313+
if (Parameters.back() != ':')
1314+
return {};
1315+
1316+
SmallVector<Identifier, 4> ParamIDs;
1317+
do {
1318+
StringRef NextParam;
1319+
std::tie(NextParam, Parameters) = Parameters.split(':');
1320+
1321+
if (!Lexer::isIdentifier(NextParam))
1322+
return {};
1323+
Identifier NextParamID;
1324+
if (NextParam != "_")
1325+
NextParamID = ctx.getIdentifier(NextParam);
1326+
ParamIDs.push_back(NextParamID);
1327+
} while (!Parameters.empty());
1328+
1329+
return DeclName(ctx, BaseID, ParamIDs);
1330+
}
1331+
1332+
DeclName ClangImporter::Implementation::importFullName(
1333+
const clang::NamedDecl *D,
1334+
bool &hasCustomName) {
1335+
// If we have a swift_name attribute, use that.
1336+
if (auto *nameAttr = D->getAttr<clang::SwiftNameAttr>()) {
1337+
hasCustomName = true;
1338+
return parseDeclName(SwiftContext, nameAttr->getName());
1339+
}
1340+
1341+
// We don't have a customized name.
1342+
hasCustomName = false;
1343+
1344+
// For empty names, there is nothing to do.
1345+
if (D->getDeclName().isEmpty()) return { };
1346+
1347+
/// Whether the result is a function name.
1348+
bool isFunction = false;
1349+
StringRef baseName;
1350+
SmallVector<StringRef, 4> argumentNames;
1351+
switch (D->getDeclName().getNameKind()) {
1352+
case clang::DeclarationName::CXXConstructorName:
1353+
case clang::DeclarationName::CXXConversionFunctionName:
1354+
case clang::DeclarationName::CXXDestructorName:
1355+
case clang::DeclarationName::CXXLiteralOperatorName:
1356+
case clang::DeclarationName::CXXOperatorName:
1357+
case clang::DeclarationName::CXXUsingDirective:
1358+
// Handling these is part of C++ interoperability.
1359+
return { };
1360+
1361+
case clang::DeclarationName::Identifier:
1362+
// Map the identifier.
1363+
baseName = D->getDeclName().getAsIdentifierInfo()->getName();
1364+
break;
1365+
1366+
case clang::DeclarationName::ObjCMultiArgSelector:
1367+
case clang::DeclarationName::ObjCOneArgSelector:
1368+
case clang::DeclarationName::ObjCZeroArgSelector: {
1369+
// Map the Objective-C selector directly.
1370+
auto selector = D->getDeclName().getObjCSelector();
1371+
baseName = selector.getNameForSlot(0);
1372+
for (unsigned index = 0, numArgs = selector.getNumArgs(); index != numArgs;
1373+
++index) {
1374+
if (index == 0)
1375+
argumentNames.push_back("");
1376+
else
1377+
argumentNames.push_back(selector.getNameForSlot(index));
1378+
}
1379+
1380+
isFunction = true;
1381+
break;
1382+
}
1383+
}
1384+
1385+
// Local function to determine whether the given declaration is subject to
1386+
// a swift_private attribute.
1387+
auto hasSwiftPrivate = [this](const clang::NamedDecl *D) {
1388+
if (D->hasAttr<clang::SwiftPrivateAttr>())
1389+
return true;
1390+
1391+
// Enum constants that are not imported as members should be considered
1392+
// private if the parent enum is marked private.
1393+
if (auto *ECD = dyn_cast<clang::EnumConstantDecl>(D)) {
1394+
auto *ED = cast<clang::EnumDecl>(ECD->getDeclContext());
1395+
switch (classifyEnum(ED)) {
1396+
case EnumKind::Constants:
1397+
case EnumKind::Unknown:
1398+
if (ED->hasAttr<clang::SwiftPrivateAttr>())
1399+
return true;
1400+
if (auto *enumTypedef = ED->getTypedefNameForAnonDecl())
1401+
if (enumTypedef->hasAttr<clang::SwiftPrivateAttr>())
1402+
return true;
1403+
break;
1404+
1405+
case EnumKind::Enum:
1406+
case EnumKind::Options:
1407+
break;
1408+
}
1409+
}
1410+
1411+
return false;
1412+
};
1413+
1414+
// Omit needless words.
1415+
StringScratchSpace omitNeedlessWordsScratch;
1416+
if (OmitNeedlessWords) {
1417+
// Objective-C properties.
1418+
if (auto objcProperty = dyn_cast<clang::ObjCPropertyDecl>(D)) {
1419+
auto contextType = getClangDeclContextType(D->getDeclContext());
1420+
if (!contextType.isNull()) {
1421+
auto contextTypeName = getClangTypeNameForOmission(contextType);
1422+
auto propertyTypeName = getClangTypeNameForOmission(
1423+
objcProperty->getType());
1424+
// Find the property names.
1425+
const InheritedNameSet *allPropertyNames = nullptr;
1426+
if (!contextType.isNull()) {
1427+
if (auto objcPtrType = contextType->getAsObjCInterfacePointerType())
1428+
if (auto objcClassDecl = objcPtrType->getInterfaceDecl())
1429+
allPropertyNames = SwiftContext.getAllPropertyNames(
1430+
objcClassDecl,
1431+
/*forInstance=*/true);
1432+
}
1433+
1434+
(void)omitNeedlessWords(baseName, { }, "", propertyTypeName,
1435+
contextTypeName, { }, /*returnsSelf=*/false,
1436+
/*isProperty=*/true, allPropertyNames,
1437+
omitNeedlessWordsScratch);
1438+
}
1439+
}
1440+
}
1441+
1442+
// If this declaration has the swift_private attribute, prepend "__" to the
1443+
// appropriate place.
1444+
SmallString<16> swiftPrivateScratch;
1445+
if (hasSwiftPrivate(D)) {
1446+
swiftPrivateScratch = "__";
1447+
1448+
if (baseName == "init") {
1449+
// For initializers, prepend "__" to the first argument name.
1450+
if (argumentNames.empty()) {
1451+
// swift_private cannot actually do anything here. Just drop the
1452+
// declaration.
1453+
// FIXME: Diagnose this?
1454+
return { };
1455+
}
1456+
1457+
swiftPrivateScratch += argumentNames[0];
1458+
argumentNames[0] = swiftPrivateScratch;
1459+
} else {
1460+
// For all other entities, prepend "__" to the base name.
1461+
swiftPrivateScratch += baseName;
1462+
baseName = swiftPrivateScratch;
1463+
}
1464+
}
1465+
1466+
// We cannot import when the base name is not an identifier.
1467+
if (!Lexer::isIdentifier(baseName))
1468+
return { };
1469+
1470+
// Get the identifier for the base name.
1471+
Identifier baseNameId = SwiftContext.getIdentifier(baseName);
1472+
1473+
// If we have a non-function name, just return the base name.
1474+
if (!isFunction) return baseNameId;
1475+
1476+
// Convert the argument names.
1477+
SmallVector<Identifier, 4> argumentNameIds;
1478+
for (auto argName : argumentNames) {
1479+
if (argumentNames.empty() || !Lexer::isIdentifier(argName)) {
1480+
argumentNameIds.push_back(Identifier());
1481+
continue;
1482+
}
1483+
1484+
argumentNameIds.push_back(SwiftContext.getIdentifier(argName));
1485+
}
1486+
1487+
// Build the result.
1488+
return DeclName(SwiftContext, baseNameId, argumentNameIds);
1489+
}
1490+
12911491
Identifier
12921492
ClangImporter::Implementation::importDeclName(clang::DeclarationName name,
12931493
StringRef removePrefix) {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 4 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2715,18 +2715,8 @@ namespace {
27152715
return nullptr;
27162716

27172717
// Determine the name of the function.
2718-
DeclName name;
27192718
bool hasCustomName;
2720-
if (auto *customNameAttr = decl->getAttr<clang::SwiftNameAttr>()) {
2721-
name = parseDeclName(customNameAttr->getName());
2722-
hasCustomName = true;
2723-
}
2724-
2725-
if (!name) {
2726-
name = Impl.importName(decl);
2727-
hasCustomName = false;
2728-
}
2729-
2719+
DeclName name = Impl.importFullName(decl, hasCustomName);
27302720
if (!name)
27312721
return nullptr;
27322722

@@ -2998,43 +2988,6 @@ namespace {
29982988
return result;
29992989
}
30002990

3001-
/// Parse a stringified Swift DeclName, e.g. "init(frame:)".
3002-
DeclName parseDeclName(StringRef Name) {
3003-
if (Name.back() != ')')
3004-
return {};
3005-
3006-
StringRef BaseName, Parameters;
3007-
std::tie(BaseName, Parameters) = Name.split('(');
3008-
if (!Lexer::isIdentifier(BaseName) || BaseName == "_")
3009-
return {};
3010-
3011-
if (Parameters.empty())
3012-
return {};
3013-
Parameters = Parameters.drop_back(); // ')'
3014-
3015-
Identifier BaseID = Impl.SwiftContext.getIdentifier(BaseName);
3016-
if (Parameters.empty())
3017-
return DeclName(Impl.SwiftContext, BaseID, {});
3018-
3019-
if (Parameters.back() != ':')
3020-
return {};
3021-
3022-
SmallVector<Identifier, 4> ParamIDs;
3023-
do {
3024-
StringRef NextParam;
3025-
std::tie(NextParam, Parameters) = Parameters.split(':');
3026-
3027-
if (!Lexer::isIdentifier(NextParam))
3028-
return {};
3029-
Identifier NextParamID;
3030-
if (NextParam != "_")
3031-
NextParamID = Impl.SwiftContext.getIdentifier(NextParam);
3032-
ParamIDs.push_back(NextParamID);
3033-
} while (!Parameters.empty());
3034-
3035-
return DeclName(Impl.SwiftContext, BaseID, ParamIDs);
3036-
}
3037-
30382991
/// If the given method is a factory method, import it as a constructor
30392992
Optional<ConstructorDecl *>
30402993
importFactoryMethodAsConstructor(Decl *member,
@@ -3056,9 +3009,8 @@ namespace {
30563009
// Check whether we're allowed to try.
30573010
switch (Impl.getFactoryAsInit(objcClass, decl)) {
30583011
case FactoryAsInitKind::AsInitializer:
3059-
if (auto *customNameAttr = decl->getAttr<clang::SwiftNameAttr>()) {
3060-
initName = parseDeclName(customNameAttr->getName());
3061-
hasCustomName = true;
3012+
if (decl->hasAttr<clang::SwiftNameAttr>()) {
3013+
initName = Impl.importFullName(decl, hasCustomName);
30623014
break;
30633015
}
30643016
// FIXME: We probably should stop using this codepath. It won't ever
@@ -3170,8 +3122,7 @@ namespace {
31703122
bool hasCustomName;
31713123
if (auto *customNameAttr = decl->getAttr<clang::SwiftNameAttr>()) {
31723124
if (!customNameAttr->getName().startswith("init(")) {
3173-
name = parseDeclName(customNameAttr->getName());
3174-
hasCustomName = true;
3125+
name = Impl.importFullName(decl, hasCustomName);
31753126
}
31763127
}
31773128
if (!name) {

lib/ClangImporter/ImporterImpl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,13 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
718718
/// \brief Converts the given Swift identifier for Clang.
719719
clang::DeclarationName exportName(Identifier name);
720720

721+
/// Imports the full name of the given Clang declaration into Swift.
722+
///
723+
/// Note that this may result in a name very different from the Clang name,
724+
/// so it should not be used when referencing Clang symbols.
725+
DeclName importFullName(const clang::NamedDecl *D,
726+
bool &hasCustomName);
727+
721728
/// Imports the name of the given Clang decl into Swift.
722729
///
723730
/// Note that this may result in a name different from the Clang name, so it

test/IDE/Inputs/swift_name.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))
22

3+
// Renaming global variables.
34
int SNFoo SWIFT_NAME(Bar);
45

6+
// Renaming tags and fields.
57
struct SWIFT_NAME(SomeStruct) SNSomeStruct {
68
double X SWIFT_NAME(x);
79
};
10+
11+
// Renaming C functions
12+
struct SNSomeStruct SNMakeSomeStruct(double X, double Y) SWIFT_NAME(makeSomeStruct(x:y:));
13+
14+
struct SNSomeStruct SNMakeSomeStructForX(double X) SWIFT_NAME(makeSomeStruct(x:));
15+
16+
// swift_private attribute
17+
void SNTransposeInPlace(struct SNSomeStruct *value) __attribute__((swift_private));

test/IDE/dump_swift_lookup_tables.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
// CHECK: Base -> full name mappings:
55
// CHECK-NEXT: Bar --> Bar
66
// CHECK-NEXT: SomeStruct --> SomeStruct
7+
// CHECK-NEXT: __SNTransposeInPlace --> __SNTransposeInPlace
8+
// CHECK-NEXT: makeSomeStruct --> makeSomeStruct(x:y:), makeSomeStruct(x:)
79

810
// CHECK: Full name -> entry mappings:
911
// CHECK-NEXT: Bar:
1012
// CHECK-NEXT: TU: SNFoo
1113
// CHECK-NEXT: SomeStruct:
1214
// CHECK-NEXT: TU: SNSomeStruct
15+
// CHECK-NEXT: __SNTransposeInPlace:
16+
// CHECK-NEXT: TU: SNTransposeInPlace
17+
// CHECK-NEXT: makeSomeStruct(x:):
18+
// CHECK-NEXT: TU: SNMakeSomeStructForX
19+
// CHECK-NEXT: makeSomeStruct(x:y:):
20+
// CHECK-NEXT: TU: SNMakeSomeStruct

0 commit comments

Comments
 (0)