Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/swift/AST/SwiftNameTranslation.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_NAME_TRANSLATION_H

#include "swift/AST/Identifier.h"
#include "swift/AST/AttrKind.h"

namespace swift {
class ValueDecl;
Expand Down Expand Up @@ -44,6 +45,11 @@ namespace objc_translation {
std::pair<Identifier, ObjCSelector>
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName = DeclName());

/// Returns true if the given value decl D is visible to ObjC of its
/// own accord (i.e. without considering its context)
bool isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess,
bool checkParent = true);

} // end namespace objc_translation
} // end namespace swift

Expand Down
1 change: 1 addition & 0 deletions lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_swift_library(swiftAST STATIC
Substitution.cpp
SubstitutionList.cpp
SubstitutionMap.cpp
SwiftNameTranslation.cpp
Type.cpp
TypeJoinMeet.cpp
TypeRefinementContext.cpp
Expand Down
74 changes: 0 additions & 74 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4968,77 +4968,3 @@ void ClassDecl::setSuperclass(Type superclass) {
&& "superclass must be interface type");
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
}

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));
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->getName().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.getBaseName(), 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.getBaseName());
}
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.getBaseName(), ObjCSelector()};
return {Ctx.getIdentifier(getNameForObjC(VD)), ObjCSelector()};
}
}
117 changes: 117 additions & 0 deletions lib/AST/SwiftNameTranslation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//===--- 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));
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->getName().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.getBaseName(), 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.getBaseName());
}
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.getBaseName(), ObjCSelector()};
return {Ctx.getIdentifier(getNameForObjC(VD)), ObjCSelector()};
}
}

bool swift::objc_translation::
isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess,
bool checkParent) {
if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
return false;
if (VD->hasAccessibility() && 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;
}
100 changes: 100 additions & 0 deletions lib/AST/USRGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "swift/AST/USRGeneration.h"
#include "swift/AST/Mangle.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/SwiftNameTranslation.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -45,6 +46,97 @@ bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
return false;
}

static bool printObjCUSRFragment(const ValueDecl *D, StringRef ObjCName,
raw_ostream &OS) {
if (!D)
return true;

if (isa<ClassDecl>(D)) {
clang::index::generateUSRForObjCClass(ObjCName, OS);
} else if (isa<ProtocolDecl>(D)) {
clang::index::generateUSRForObjCProtocol(ObjCName, OS);
} else if (isa<VarDecl>(D)) {
clang::index::generateUSRForObjCProperty(ObjCName, D->isStatic(), OS);
} else if (isa<AbstractFunctionDecl>(D)) {
clang::index::generateUSRForObjCMethod(ObjCName, D->isInstanceMember(), OS);
} else if (isa<EnumDecl>(D)) {
OS << "@E@" << ObjCName; // FIXME: expose clang API to handle enum names
} else if (isa<EnumElementDecl>(D)) {
OS << "@" << ObjCName;
} else {
llvm_unreachable("Unexpected value decl");
}
return false;
}

static bool printObjCUSRForAccessor(const AbstractStorageDecl *ASD,
AccessorKind Kind,
raw_ostream &OS) {
ObjCSelector Selector;
switch (Kind) {
case swift::AccessorKind::IsGetter:
Selector = ASD->getObjCGetterSelector();
break;
case swift::AccessorKind::IsSetter:
Selector = ASD->getObjCSetterSelector();
break;
default:
llvm_unreachable("invalid accessor kind");
}
assert(Selector);
llvm::SmallString<128> Buf;
clang::index::generateUSRForObjCMethod(Selector.getString(Buf),
ASD->isInstanceMember(), OS);
return false;
}

static bool printObjCUSR(const ValueDecl *D, raw_ostream &OS) {
OS << clang::index::getUSRSpacePrefix();

if (auto *Parent = D->getDeclContext()->
getAsNominalTypeOrNominalTypeExtensionContext()) {
auto ObjCName = objc_translation::getObjCNameForSwiftDecl(Parent);
if (printObjCUSRFragment(Parent, ObjCName.first.str(), OS))
return true;
}

auto ObjCName = objc_translation::getObjCNameForSwiftDecl(D);

if (!ObjCName.first.empty())
return printObjCUSRFragment(D, ObjCName.first.str(), OS);

assert(ObjCName.second);
llvm::SmallString<128> Buf;
return printObjCUSRFragment(D, ObjCName.second.getString(Buf), OS);
}

static bool ShouldUseObjCUSR(const Decl *D) {
// Only the subscript getter/setter are visible to ObjC rather than the
// subscript itself
if (isa<SubscriptDecl>(D))
return false;

auto Parent = D->getDeclContext()->getInnermostDeclarationDeclContext();
if (Parent && (!ShouldUseObjCUSR(Parent) || // parent should be visible too
!D->getDeclContext()->isTypeContext() || // no local decls
isa<TypeDecl>(D))) // nested types aren't supported
return false;

if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
if (isa<EnumElementDecl>(VD))
return true;
return objc_translation::isVisibleToObjC(VD, Accessibility::Internal);
}

if (const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D)) {
if (auto ExtendedType = ED->getExtendedType()) {
auto baseClass = ExtendedType->getClassOrBoundGenericClass();
return baseClass && ShouldUseObjCUSR(baseClass) && !baseClass->isForeign();
}
}
return false;
}

bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
using namespace Mangle;

Expand Down Expand Up @@ -107,6 +199,10 @@ bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
return Ignore;
}

if (ShouldUseObjCUSR(VD)) {
return printObjCUSR(VD, OS);
}

if (!D->hasInterfaceType())
return true;

Expand Down Expand Up @@ -160,6 +256,10 @@ bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind,
// addressor.

AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D);
if (ShouldUseObjCUSR(SD)) {
return printObjCUSRForAccessor(SD, AccKind, OS);
}

std::string Old = getUSRSpacePrefix().str();
Mangler Mangler;
Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, SD);
Expand Down
15 changes: 2 additions & 13 deletions lib/PrintAsObjC/PrintAsObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
os << "@end\n\n";
}

bool shouldInclude(const ValueDecl *VD, bool checkParent = true) {
if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
return false;
if (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 shouldInclude(parent, false);
}
}
return false;
bool shouldInclude(const ValueDecl *VD) {
return isVisibleToObjC(VD, minRequiredAccess);
}

private:
Expand Down
Loading