in lib/ClangImporter/ImportName.cpp [1439:2213]
ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
ImportNameVersion version,
clang::DeclarationName givenName) {
ImportedName result;
/// Whether we want a Swift 3 or later name
bool swift3OrLaterName = version > ImportNameVersion::swift2();
// Objective-C categories and extensions don't have names, despite
// being "named" declarations.
if (isa<clang::ObjCCategoryDecl>(D))
return ImportedName();
// Dig out the definition, if there is one.
if (auto def = getDefinitionForClangTypeDecl(D)) {
if (*def)
D = static_cast<const clang::NamedDecl *>(*def);
}
// Compute the effective context.
auto dc = const_cast<clang::DeclContext *>(D->getDeclContext());
auto effectiveCtx = determineEffectiveContext(D, dc, version);
if (!effectiveCtx)
return ImportedName();
result.effectiveContext = effectiveCtx;
// Gather information from the swift_async attribute, if there is one.
Optional<unsigned> completionHandlerParamIndex;
bool completionHandlerFlagIsZeroOnError = false;
Optional<unsigned> completionHandlerFlagParamIndex;
if (version.supportsConcurrency()) {
if (const auto *swiftAsyncAttr = D->getAttr<clang::SwiftAsyncAttr>()) {
// If this is swift_async(none), don't import as async at all.
if (swiftAsyncAttr->getKind() == clang::SwiftAsyncAttr::None)
return ImportedName();
// Get the completion handler parameter index, if there is one.
completionHandlerParamIndex =
swiftAsyncAttr->getCompletionHandlerIndex().getASTIndex();
}
if (const auto *asyncErrorAttr = D->getAttr<clang::SwiftAsyncErrorAttr>()) {
switch (auto convention = asyncErrorAttr->getConvention()) {
// No flag parameter in these cases.
case clang::SwiftAsyncErrorAttr::NonNullError:
case clang::SwiftAsyncErrorAttr::None:
break;
// Get the flag argument index and polarity from the attribute.
case clang::SwiftAsyncErrorAttr::NonZeroArgument:
case clang::SwiftAsyncErrorAttr::ZeroArgument:
// NB: Attribute is 1-based rather than 0-based.
completionHandlerFlagParamIndex = asyncErrorAttr->getHandlerParamIdx() - 1;
completionHandlerFlagIsZeroOnError =
convention == clang::SwiftAsyncErrorAttr::ZeroArgument;
break;
}
}
}
// FIXME: ugly to check here, instead perform unified check up front in
// containing struct...
if (findSwiftNewtype(D, clangSema, version))
result.info.importAsMember = true;
// Find the original method/property declaration and retrieve the
// name from there.
if (auto method = dyn_cast<clang::ObjCMethodDecl>(D)) {
// Inherit the name from the "originating" declarations, if
// there are any.
SmallVector<std::pair<const clang::ObjCMethodDecl *, ImportedName>, 4>
overriddenNames;
SmallVector<const clang::ObjCMethodDecl *, 4> overriddenMethods;
method->getOverriddenMethods(overriddenMethods);
for (auto overridden : overriddenMethods) {
const auto overriddenName = importName(overridden, version, givenName);
if (overriddenName.getDeclName())
overriddenNames.push_back({overridden, overriddenName});
}
// If we found any names of overridden methods, return those names.
if (!overriddenNames.empty()) {
if (overriddenNames.size() > 1)
mergeOverriddenNames(swiftCtx, method, overriddenNames);
overriddenNames[0].second.effectiveContext = result.effectiveContext;
// Compute the initializer kind from the derived method, though.
if (auto kind = determineCtorInitializerKind(method))
overriddenNames[0].second.info.initKind = *kind;
return overriddenNames[0].second;
}
} else if (auto property = dyn_cast<clang::ObjCPropertyDecl>(D)) {
// Inherit the name from the "originating" declarations, if
// there are any.
if (auto getter = property->getGetterMethodDecl()) {
SmallVector<std::pair<const clang::ObjCPropertyDecl *, ImportedName>, 4>
overriddenNames;
SmallVector<const clang::ObjCMethodDecl *, 4> overriddenMethods;
SmallPtrSet<const clang::ObjCPropertyDecl *, 4> knownProperties;
(void)knownProperties.insert(property);
getter->getOverriddenMethods(overriddenMethods);
for (auto overridden : overriddenMethods) {
if (!overridden->isPropertyAccessor())
continue;
auto overriddenProperty = overridden->findPropertyDecl(true);
if (!overriddenProperty)
continue;
if (!knownProperties.insert(overriddenProperty).second)
continue;
const auto overriddenName = importName(overriddenProperty, version,
givenName);
if (overriddenName.getDeclName())
overriddenNames.push_back({overriddenProperty, overriddenName});
}
// If we found any names of overridden methods, return those names.
if (!overriddenNames.empty()) {
if (overriddenNames.size() > 1)
mergeOverriddenNames(swiftCtx, property, overriddenNames);
overriddenNames[0].second.effectiveContext = result.effectiveContext;
return overriddenNames[0].second;
}
}
}
// If we have a swift_name attribute, use that.
if (auto nameAttr = findSwiftNameAttr(D, version)) {
bool skipCustomName = false;
// Parse the name.
ParsedDeclName parsedName = parseDeclName(nameAttr->name);
if (!parsedName || parsedName.isOperator())
return result;
// If we have an Objective-C method that is being mapped to an
// initializer (e.g., a factory method whose name doesn't fit the
// convention for factory methods), make sure that it can be
// imported as an initializer.
bool isInitializer = false;
auto method = dyn_cast<clang::ObjCMethodDecl>(D);
if (method) {
unsigned initPrefixLength;
if (parsedName.BaseName == "init" && parsedName.IsFunctionName) {
if (!shouldImportAsInitializer(method, version, initPrefixLength)) {
// We cannot import this as an initializer anyway.
return ImportedName();
}
if (auto kind = determineCtorInitializerKind(method))
result.info.initKind = *kind;
// If this swift_name attribute maps a factory method to an
// initializer and we were asked not to do so, ignore the
// custom name.
if (suppressFactoryMethodAsInit(method, version,
result.getInitKind())) {
skipCustomName = true;
} else {
// Note that this is an initializer.
isInitializer = true;
}
}
}
if (!skipCustomName) {
result.info.hasCustomName = true;
result.declName = parsedName.formDeclName(swiftCtx);
// Handle globals treated as members.
if (parsedName.isMember()) {
// FIXME: Make sure this thing is global.
result.effectiveContext = parsedName.ContextName;
if (parsedName.SelfIndex) {
result.info.hasSelfIndex = true;
result.info.selfIndex = *parsedName.SelfIndex;
}
result.info.importAsMember = true;
if (parsedName.BaseName == "init")
result.info.initKind = CtorInitializerKind::Factory;
}
// Map property getters/setters.
if (parsedName.IsGetter)
result.info.accessorKind = ImportedAccessorKind::PropertyGetter;
else if (parsedName.IsSetter)
result.info.accessorKind = ImportedAccessorKind::PropertySetter;
// only allow effectful property imports if through `swift_async_name`
const bool effectfulProperty = parsedName.IsGetter && nameAttr->isAsync;
// Consider throws and async imports.
if (method && (parsedName.IsFunctionName || effectfulProperty)) {
// Get the parameters.
ArrayRef<const clang::ParmVarDecl *> params{method->param_begin(),
method->param_end()};
if (auto errorInfo = considerErrorImport(method, parsedName.BaseName,
parsedName.ArgumentLabels,
params, isInitializer,
/*hasCustomName=*/true)) {
result.info.hasErrorInfo = true;
result.info.errorInfo = *errorInfo;
}
if (version.supportsConcurrency()) {
if (auto asyncInfo = considerAsyncImport(
method, parsedName.BaseName, parsedName.ArgumentLabels,
params, isInitializer,
completionHandlerParamIndex,
nameAttr->isAsync ? CustomAsyncName::SwiftAsyncName
: CustomAsyncName::SwiftName,
completionHandlerFlagParamIndex,
completionHandlerFlagIsZeroOnError,
result.getErrorInfo())) {
result.info.hasAsyncInfo = true;
result.info.asyncInfo = *asyncInfo;
// Update the name to reflect the new parameter labels.
result.declName = formDeclName(
swiftCtx, parsedName.BaseName, parsedName.ArgumentLabels,
/*isFunction=*/true, isInitializer);
} else if (nameAttr->isAsync) {
// The custom name was for an async import, but we didn't in fact
// import as async for some reason. Ignore this import.
return ImportedName();
}
}
}
return result;
}
}
// Spcial case: unnamed/anonymous fields.
if (auto field = dyn_cast<clang::FieldDecl>(D)) {
static_assert((clang::Decl::lastField - clang::Decl::firstField) == 2,
"update logic for new FieldDecl subclasses");
if (isa<clang::ObjCIvarDecl>(D) || isa<clang::ObjCAtDefsFieldDecl>(D))
// These are not ordinary fields and are not imported into Swift.
return result;
if (field->isAnonymousStructOrUnion() || field->getDeclName().isEmpty()) {
// Generate a field name for anonymous fields, this will be used in
// order to be able to expose the indirect fields injected from there
// as computed properties forwarding the access to the subfield.
std::string name;
llvm::raw_string_ostream nameStream(name);
nameStream << "__Anonymous_field" << field->getFieldIndex();
result.setDeclName(swiftCtx.getIdentifier(nameStream.str()));
result.setEffectiveContext(field->getDeclContext());
return result;
}
}
if (D->getDeclName().isEmpty()) {
// If the type has no name and no structure name, but is not anonymous,
// generate a name for it. Specifically this is for cases like:
// struct a {
// struct {} z;
// }
// Where the member z is an unnamed struct, but does have a member-name
// and is accessible as a member of struct a.
if (auto recordDecl = dyn_cast<clang::RecordDecl>(
D->getLexicalDeclContext())) {
for (auto field : recordDecl->fields()) {
auto fieldTagDecl = field->getType()->getAsTagDecl();
if (fieldTagDecl == D) {
// Create a name for the declaration from the field name.
std::string name;
llvm::raw_string_ostream nameStream(name);
const char *kind;
if (fieldTagDecl->isStruct())
kind = "struct";
else if (fieldTagDecl->isUnion())
kind = "union";
else if (fieldTagDecl->isEnum())
kind = "enum";
else
llvm_unreachable("unknown decl kind");
nameStream << "__Unnamed_" << kind << "_";
if (field->isAnonymousStructOrUnion()) {
nameStream << "__Anonymous_field" << field->getFieldIndex();
} else {
assert(!field->getDeclName().isEmpty() &&
"Microsoft anonymous struct extension?");
nameStream << field->getName();
}
result.setDeclName(swiftCtx.getIdentifier(nameStream.str()));
result.setEffectiveContext(D->getDeclContext());
return result;
}
}
}
// Otherwise, for empty names, there is nothing to do.
return result;
}
/// Whether the result is a function name.
bool isFunction = false;
bool isInitializer = false;
unsigned initializerPrefixLen;
StringRef baseName;
SmallVector<StringRef, 4> argumentNames;
SmallString<16> selectorSplitScratch;
ArrayRef<const clang::ParmVarDecl *> params;
switch (D->getDeclName().getNameKind()) {
case clang::DeclarationName::CXXConstructorName: {
isInitializer = true;
isFunction = true;
result.info.initKind = CtorInitializerKind::Designated;
baseName = "init";
auto ctor = dyn_cast<clang::CXXConstructorDecl>(D);
if (auto templateCtor = dyn_cast<clang::FunctionTemplateDecl>(D))
ctor = cast<clang::CXXConstructorDecl>(templateCtor->getAsFunction());
// If we couldn't find a constructor decl, bail.
if (!ctor)
return ImportedName();
addEmptyArgNamesForClangFunction(ctor, argumentNames);
break;
}
case clang::DeclarationName::CXXConversionFunctionName:
case clang::DeclarationName::CXXDestructorName:
case clang::DeclarationName::CXXLiteralOperatorName:
case clang::DeclarationName::CXXUsingDirective:
case clang::DeclarationName::CXXDeductionGuideName:
// TODO: Handling these is part of C++ interoperability.
return ImportedName();
case clang::DeclarationName::CXXOperatorName: {
auto op = D->getDeclName().getCXXOverloadedOperator();
auto functionDecl = dyn_cast<clang::FunctionDecl>(D);
if (auto functionTemplate = dyn_cast<clang::FunctionTemplateDecl>(D))
functionDecl = functionTemplate->getAsFunction();
if (!functionDecl)
return ImportedName();
switch (op) {
case clang::OverloadedOperatorKind::OO_Plus:
case clang::OverloadedOperatorKind::OO_Minus:
case clang::OverloadedOperatorKind::OO_Star:
case clang::OverloadedOperatorKind::OO_Slash:
case clang::OverloadedOperatorKind::OO_Percent:
case clang::OverloadedOperatorKind::OO_Caret:
case clang::OverloadedOperatorKind::OO_Amp:
case clang::OverloadedOperatorKind::OO_Pipe:
case clang::OverloadedOperatorKind::OO_Less:
case clang::OverloadedOperatorKind::OO_Greater:
case clang::OverloadedOperatorKind::OO_LessLess:
case clang::OverloadedOperatorKind::OO_GreaterGreater:
case clang::OverloadedOperatorKind::OO_EqualEqual:
case clang::OverloadedOperatorKind::OO_ExclaimEqual:
case clang::OverloadedOperatorKind::OO_LessEqual:
case clang::OverloadedOperatorKind::OO_GreaterEqual:
case clang::OverloadedOperatorKind::OO_AmpAmp:
case clang::OverloadedOperatorKind::OO_PipePipe:
baseName = clang::getOperatorSpelling(op);
isFunction = true;
argumentNames.resize(
functionDecl->param_size() +
// C++ operators that are implemented as non-static member functions
// get imported into Swift as static member functions that use an
// additional parameter for the left-hand side operand instead of
// the receiver object.
(isa<clang::CXXMethodDecl>(D) ? 1 : 0));
break;
case clang::OverloadedOperatorKind::OO_Call:
baseName = "callAsFunction";
isFunction = true;
addEmptyArgNamesForClangFunction(functionDecl, argumentNames);
break;
case clang::OverloadedOperatorKind::OO_Subscript: {
auto returnType = functionDecl->getReturnType();
if ((!returnType->isReferenceType() && !returnType->isAnyPointerType()) ||
returnType->getPointeeType().isConstQualified()) {
// If we are handling a non-reference return type, treat it as a getter
// so that we do not SILGen the value type operator[] as an rvalue.
baseName = "__operatorSubscriptConst";
result.info.accessorKind = ImportedAccessorKind::SubscriptGetter;
} else if (returnType->isAnyPointerType()) {
baseName = "__operatorSubscript";
result.info.accessorKind = ImportedAccessorKind::SubscriptGetter;
} else {
baseName = "__operatorSubscript";
result.info.accessorKind = ImportedAccessorKind::SubscriptSetter;
}
isFunction = true;
addEmptyArgNamesForClangFunction(functionDecl, argumentNames);
break;
}
default:
// We don't import these yet.
return ImportedName();
}
break;
}
case clang::DeclarationName::Identifier:
// Map the identifier.
baseName = D->getDeclName().getAsIdentifierInfo()->getName();
if (givenName) {
if (!givenName.isIdentifier())
return ImportedName();
baseName = givenName.getAsIdentifierInfo()->getName();
}
// For Objective-C BOOL properties, use the name of the getter
// which, conventionally, has an "is" prefix.
if (swift3OrLaterName) {
if (auto property = dyn_cast<clang::ObjCPropertyDecl>(D)) {
if (isBoolType(clangSema.Context, property->getType()))
baseName = property->getGetterName().getNameForSlot(0);
}
}
if (auto function = dyn_cast<clang::FunctionDecl>(D)) {
isFunction = true;
addEmptyArgNamesForClangFunction(function, argumentNames);
}
break;
case clang::DeclarationName::ObjCMultiArgSelector:
case clang::DeclarationName::ObjCOneArgSelector:
case clang::DeclarationName::ObjCZeroArgSelector: {
auto objcMethod = cast<clang::ObjCMethodDecl>(D);
// Map the Objective-C selector directly.
auto selector = D->getDeclName().getObjCSelector();
// Respect the given name.
if (givenName) {
switch (givenName.getNameKind()) {
case clang::DeclarationName::ObjCOneArgSelector:
case clang::DeclarationName::ObjCMultiArgSelector:
case clang::DeclarationName::ObjCZeroArgSelector:
// Make sure the given name has the right count of arguments.
if (selector.getNumArgs() != givenName.getObjCSelector().getNumArgs())
return ImportedName();
selector = givenName.getObjCSelector();
break;
default:
return ImportedName();
}
}
baseName = selector.getNameForSlot(0);
// We don't support methods with empty first selector pieces.
if (baseName.empty())
return ImportedName();
isInitializer = shouldImportAsInitializer(objcMethod, version,
initializerPrefixLen);
if (isInitializer) {
if (auto kind = determineCtorInitializerKind(objcMethod))
result.info.initKind = *kind;
// If we would import a factory method as an initializer but were
// asked not to, don't consider this as an initializer.
if (suppressFactoryMethodAsInit(objcMethod, version,
result.getInitKind())) {
isInitializer = false;
}
}
if (isInitializer)
baseName = "init";
// Get the parameters.
params = {objcMethod->param_begin(), objcMethod->param_end()};
// If we have a variadic method for which we need to drop the last
// selector piece, do so now.
unsigned numArgs = selector.getNumArgs();
if (objcMethod->isVariadic() && shouldMakeSelectorNonVariadic(selector)) {
--numArgs;
result.info.droppedVariadic = true;
params = params.drop_back(1);
}
for (unsigned index = 0; index != numArgs; ++index) {
if (index == 0) {
argumentNames.push_back(StringRef());
} else {
StringRef argName = selector.getNameForSlot(index);
argumentNames.push_back(argName);
}
}
// For initializers, compute the first argument name.
if (isInitializer) {
// Skip over the prefix.
auto argName = selector.getNameForSlot(0).substr(initializerPrefixLen);
// Drop "With" if present after the "init".
bool droppedWith = false;
if (argName.startswith("With")) {
argName = argName.substr(4);
droppedWith = true;
}
// Lowercase the remaining argument name.
argName = camel_case::toLowercaseWord(argName, selectorSplitScratch);
// If we dropped "with" and ended up with a reserved name,
// put "with" back.
if (droppedWith && isSwiftReservedName(argName)) {
selectorSplitScratch = "with";
selectorSplitScratch +=
selector.getNameForSlot(0).substr(initializerPrefixLen + 4);
argName = selectorSplitScratch;
}
// Set the first argument name to be the name we computed. If
// there is no first argument, create one for this purpose.
if (argumentNames.empty()) {
if (!argName.empty()) {
// FIXME: Record what happened here for the caller?
argumentNames.push_back(argName);
}
} else {
argumentNames[0] = argName;
}
}
if (auto errorInfo = considerErrorImport(
objcMethod, baseName, argumentNames, params, isInitializer,
/*hasCustomName=*/false)) {
result.info.hasErrorInfo = true;
result.info.errorInfo = *errorInfo;
}
isFunction = true;
// Is this one of the accessors for subscripts?
if (objcMethod->getMethodFamily() == clang::OMF_None &&
objcMethod->isInstanceMethod()) {
if (isNonNullarySelector(objcMethod->getSelector(),
{"objectAtIndexedSubscript"}) ||
isNonNullarySelector(objcMethod->getSelector(),
{"objectForKeyedSubscript"}))
result.info.accessorKind = ImportedAccessorKind::SubscriptGetter;
else if (isNonNullarySelector(objcMethod->getSelector(),
{"setObject", "atIndexedSubscript"}) ||
isNonNullarySelector(objcMethod->getSelector(),
{"setObject", "forKeyedSubscript"}))
result.info.accessorKind = ImportedAccessorKind::SubscriptSetter;
}
if (version.supportsConcurrency() &&
result.info.accessorKind == ImportedAccessorKind::None) {
if (auto asyncInfo = considerAsyncImport(
objcMethod, baseName, argumentNames, params, isInitializer,
completionHandlerParamIndex, CustomAsyncName::None,
completionHandlerFlagParamIndex,
completionHandlerFlagIsZeroOnError,
result.getErrorInfo())) {
result.info.hasAsyncInfo = true;
result.info.asyncInfo = *asyncInfo;
}
}
break;
}
}
// Perform automatic name transformations.
// Enumeration constants may have common prefixes stripped.
bool strippedPrefix = false;
if (version != ImportNameVersion::raw() && isa<clang::EnumConstantDecl>(D)) {
auto enumDecl = cast<clang::EnumDecl>(D->getDeclContext());
auto enumInfo = getEnumInfo(enumDecl);
StringRef removePrefix = enumInfo.getConstantNamePrefix();
if (!removePrefix.empty()) {
if (baseName.startswith(removePrefix)) {
baseName = baseName.substr(removePrefix.size());
strippedPrefix = true;
} else if (givenName) {
// Calculate the new prefix.
// What if the preferred name causes longer prefix?
StringRef subPrefix = [](StringRef LHS, StringRef RHS) {
if (LHS.size() > RHS.size())
std::swap(LHS, RHS) ;
return StringRef(LHS.data(), std::mismatch(LHS.begin(), LHS.end(),
RHS.begin()).first - LHS.begin());
}(removePrefix, baseName);
if (!subPrefix.empty()) {
baseName = baseName.substr(subPrefix.size());
strippedPrefix = true;
}
}
}
}
// If the error is an error enum, it will be mapped to the 'Code'
// enum nested within an NSError-containing struct. Strip the word
// "Code" off the end of the name, if it's there, because it's
// redundant.
if (auto enumDecl = dyn_cast<clang::EnumDecl>(D)) {
if (enumDecl->isThisDeclarationADefinition()) {
auto enumInfo = getEnumInfo(enumDecl);
if (enumInfo.isErrorEnum() && baseName.size() > 4 &&
camel_case::getLastWord(baseName) == "Code")
baseName = baseName.substr(0, baseName.size() - 4);
}
}
// Objective-C protocols may have the suffix "Protocol" appended if
// the non-suffixed name would conflict with another entity in the
// same top-level module.
SmallString<16> baseNameWithProtocolSuffix;
if (auto objcProto = dyn_cast<clang::ObjCProtocolDecl>(D)) {
if (objcProto->hasDefinition()) {
if (hasNamingConflict(D, objcProto->getIdentifier(), nullptr)) {
baseNameWithProtocolSuffix = baseName;
baseNameWithProtocolSuffix += SWIFT_PROTOCOL_SUFFIX;
baseName = baseNameWithProtocolSuffix;
}
}
}
// Typedef declarations might be CF types that will drop the "Ref"
// suffix.
clang::ASTContext &clangCtx = clangSema.Context;
if (swift3OrLaterName) {
if (auto typedefNameDecl = dyn_cast<clang::TypedefNameDecl>(D)) {
auto swiftName = getCFTypeName(typedefNameDecl);
if (!swiftName.empty() &&
!hasNamingConflict(D, &clangCtx.Idents.get(swiftName),
typedefNameDecl)) {
// Adopt the requested name.
baseName = swiftName;
}
}
}
if (auto classTemplateSpecDecl =
dyn_cast<clang::ClassTemplateSpecializationDecl>(D)) {
if (!isa<clang::ClassTemplatePartialSpecializationDecl>(D)) {
auto &astContext = classTemplateSpecDecl->getASTContext();
// Itanium mangler produces valid Swift identifiers, use it to generate a name for
// this instantiation.
std::unique_ptr<clang::MangleContext> mangler{
clang::ItaniumMangleContext::create(astContext,
astContext.getDiagnostics())};
llvm::SmallString<128> storage;
llvm::raw_svector_ostream buffer(storage);
mangler->mangleTypeName(astContext.getRecordType(classTemplateSpecDecl),
buffer);
// The Itanium mangler does not provide a way to get the mangled
// representation of a type. Instead, we call mangleTypeName() that
// returns the name of the RTTI typeinfo symbol, and remove the _ZTS
// prefix. Then we prepend __CxxTemplateInst to reduce chances of conflict
// with regular C and C++ structs.
llvm::SmallString<128> mangledNameStorage;
llvm::raw_svector_ostream mangledName(mangledNameStorage);
assert(buffer.str().take_front(4) == "_ZTS");
mangledName << CXX_TEMPLATE_INST_PREFIX << buffer.str().drop_front(4);
baseName = swiftCtx.getIdentifier(mangledName.str()).get();
}
}
// swift_newtype-ed declarations may have common words with the type name
// stripped.
if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) {
result.info.importAsMember = true;
baseName = determineSwiftNewtypeBaseName(baseName, newtypeDecl->getName(),
strippedPrefix);
}
if (!result.isSubscriptAccessor() && swift3OrLaterName) {
// Objective-C properties.
if (auto objcProperty = dyn_cast<clang::ObjCPropertyDecl>(D)) {
auto contextType = getClangDeclContextType(
D->getDeclContext());
if (!contextType.isNull()) {
auto contextTypeName =
getClangTypeNameForOmission(clangCtx, contextType);
auto propertyTypeName =
getClangTypeNameForOmission(clangCtx, objcProperty->getType());
// Find the property names.
const InheritedNameSet *allPropertyNames = nullptr;
if (!contextType.isNull()) {
if (auto objcPtrType = contextType->getAsObjCInterfacePointerType())
if (auto objcClassDecl = objcPtrType->getInterfaceDecl())
allPropertyNames =
getAllPropertyNames(objcClassDecl, /*forInstance=*/true);
}
(void)omitNeedlessWords(baseName, {}, "", propertyTypeName,
contextTypeName, {}, /*returnsSelf=*/false,
/*isProperty=*/true, allPropertyNames,
None, None, scratch);
}
}
// Objective-C methods.
if (auto method = dyn_cast<clang::ObjCMethodDecl>(D)) {
(void)omitNeedlessWordsInFunctionName(
baseName, argumentNames, params, method->getReturnType(),
method->getDeclContext(), getNonNullArgs(method, params),
result.getErrorInfo()
? Optional<unsigned>(result.getErrorInfo()->ErrorParameterIndex)
: None,
method->hasRelatedResultType(), method->isInstanceMethod(),
result.getAsyncInfo().map(
[](const ForeignAsyncConvention::Info &info) {
return info.completionHandlerParamIndex();
}),
result.getAsyncInfo().map(
[&](const ForeignAsyncConvention::Info &info) {
return method->getDeclName().getObjCSelector().getNameForSlot(
info.completionHandlerParamIndex());
}),
*this);
}
// If the result is a value, lowercase it.
if (strippedPrefix && isa<clang::ValueDecl>(D) &&
shouldLowercaseValueName(baseName)) {
baseName = camel_case::toLowercaseInitialisms(baseName, scratch);
}
}
// If this declaration has the swift_private attribute, prepend "__" to the
// appropriate place.
SmallString<16> swiftPrivateScratch;
if (shouldBeSwiftPrivate(*this, D, version, result.info.hasAsyncInfo)) {
// Special case: empty arg factory, "for historical reasons", is not private
if (isInitializer && argumentNames.empty() &&
(result.getInitKind() == CtorInitializerKind::Factory ||
result.getInitKind() == CtorInitializerKind::ConvenienceFactory))
return result;
// Make the given name private.
swiftPrivateScratch = "__";
if (isInitializer) {
// For initializers, prepend "__" to the first argument name.
if (argumentNames.empty()) {
// FIXME: Record that we did this.
argumentNames.push_back("__");
} else {
swiftPrivateScratch += argumentNames[0];
argumentNames[0] = swiftPrivateScratch;
}
} else {
// For all other entities, prepend "__" to the base name.
swiftPrivateScratch += baseName;
baseName = swiftPrivateScratch;
}
}
result.declName = formDeclName(swiftCtx, baseName, argumentNames, isFunction,
isInitializer);
return result;
}