ImportedName NameImporter::importNameImpl()

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