text: //===--- SwiftNameTranslation.cpp - Swift to ObjC Name Translation APIs ---===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  //  This file contains utilities for translating Swift names to ObjC.
  //
  //===----------------------------------------------------------------------===//
  
  #include "swift/AST/SwiftNameTranslation.h"
  #include "swift/AST/ASTContext.h"
  #include "swift/AST/Decl.h"
  #include "swift/AST/LazyResolver.h"
  #include "swift/Basic/StringExtras.h"
  
  #include "clang/AST/DeclObjC.h"
  #include "llvm/ADT/SmallString.h"
  
  using namespace swift;
  
  StringRef swift::objc_translation::
  getNameForObjC(const ValueDecl *VD, CustomNamesOnly_t customNamesOnly) {
    assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) || isa<StructDecl>(VD) ||
           isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD) ||
           isa<TypeAliasDecl>(VD));
    if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>()) {
      if (auto name = objc->getName()) {
        assert(name->getNumSelectorPieces() == 1);
        return name->getSelectorPieces().front().str();
      }
    }
  
    if (customNamesOnly)
      return StringRef();
  
    if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl())) {
      if (const clang::IdentifierInfo *II = clangDecl->getIdentifier())
        return II->getName();
      if (auto *anonDecl = dyn_cast<clang::TagDecl>(clangDecl))
        if (auto *anonTypedef = anonDecl->getTypedefNameForAnonDecl())
          return anonTypedef->getIdentifier()->getName();
    }
  
    return VD->getBaseName().getIdentifier().str();
  }
  
  bool swift::objc_translation::
  printSwiftEnumElemNameInObjC(const EnumElementDecl *EL, llvm::raw_ostream &OS,
                               Identifier PreferredName) {
    StringRef ElemName = getNameForObjC(EL, CustomNamesOnly);
    if (!ElemName.empty()) {
      OS << ElemName;
      return true;
    }
    OS << getNameForObjC(EL->getDeclContext()->getAsEnumOrEnumExtensionContext());
    if (PreferredName.empty())
      ElemName = EL->getName().str();
    else
      ElemName = PreferredName.str();
  
    SmallString<64> Scratch;
    OS << camel_case::toSentencecase(ElemName, Scratch);
    return false;
  }
  
  std::pair<Identifier, ObjCSelector> swift::objc_translation::
  getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
    ASTContext &Ctx = VD->getASTContext();
    LazyResolver *Resolver = Ctx.getLazyResolver();
    if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
      return {Identifier(), FD->getObjCSelector(Resolver, PreferredName)};
    } else if (auto *VAD = dyn_cast<VarDecl>(VD)) {
      if (PreferredName)
        return {PreferredName.getBaseIdentifier(), ObjCSelector()};
      return {VAD->getObjCPropertyName(), ObjCSelector()};
    } else if (auto *SD = dyn_cast<SubscriptDecl>(VD)) {
      return getObjCNameForSwiftDecl(SD->getGetter(), PreferredName);
    } else if (auto *EL = dyn_cast<EnumElementDecl>(VD)) {
      SmallString<64> Buffer;
      {
        llvm::raw_svector_ostream OS(Buffer);
        printSwiftEnumElemNameInObjC(EL, OS, PreferredName.getBaseIdentifier());
      }
      return {Ctx.getIdentifier(Buffer.str()), ObjCSelector()};
    } else {
      // @objc(ExplicitName) > PreferredName > Swift name.
      StringRef Name = getNameForObjC(VD, CustomNamesOnly);
      if (!Name.empty())
        return {Ctx.getIdentifier(Name), ObjCSelector()};
      if (!PreferredName.getBaseName().empty())
        return {PreferredName.getBaseIdentifier(), ObjCSelector()};
      return {Ctx.getIdentifier(getNameForObjC(VD)), ObjCSelector()};
    }
  }
  
  bool swift::objc_translation::
  isVisibleToObjC(const ValueDecl *VD, AccessLevel minRequiredAccess,
                  bool checkParent) {
    if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
      return false;
    if (VD->hasAccess() && VD->getFormalAccess() >= minRequiredAccess) {
      return true;
    } else if (checkParent) {
      if (auto ctor = dyn_cast<ConstructorDecl>(VD)) {
        // Check if we're overriding an initializer that is visible to obj-c
        if (auto parent = ctor->getOverriddenDecl())
          return isVisibleToObjC(parent, minRequiredAccess, false);
      }
    }
    return false;
  }
  