Skip to content

Commit 444775f

Browse files
author
Nathan Hawes
authored
Merge pull request #7670 from nathawes/rdar16271632
Use clang-style USRs for swift decls that are exposed to Objective C
2 parents 69b3712 + 0223be2 commit 444775f

File tree

11 files changed

+362
-145
lines changed

11 files changed

+362
-145
lines changed

include/swift/AST/SwiftNameTranslation.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_NAME_TRANSLATION_H
1515

1616
#include "swift/AST/Identifier.h"
17+
#include "swift/AST/AttrKind.h"
1718

1819
namespace swift {
1920
class ValueDecl;
@@ -44,6 +45,11 @@ namespace objc_translation {
4445
std::pair<Identifier, ObjCSelector>
4546
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName = DeclName());
4647

48+
/// Returns true if the given value decl D is visible to ObjC of its
49+
/// own accord (i.e. without considering its context)
50+
bool isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess,
51+
bool checkParent = true);
52+
4753
} // end namespace objc_translation
4854
} // end namespace swift
4955

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_swift_library(swiftAST STATIC
4949
Substitution.cpp
5050
SubstitutionList.cpp
5151
SubstitutionMap.cpp
52+
SwiftNameTranslation.cpp
5253
Type.cpp
5354
TypeJoinMeet.cpp
5455
TypeRefinementContext.cpp

lib/AST/Decl.cpp

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4976,77 +4976,3 @@ void ClassDecl::setSuperclass(Type superclass) {
49764976
&& "superclass must be interface type");
49774977
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
49784978
}
4979-
4980-
StringRef swift::objc_translation::
4981-
getNameForObjC(const ValueDecl *VD, CustomNamesOnly_t customNamesOnly) {
4982-
assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) || isa<StructDecl>(VD) ||
4983-
isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD));
4984-
if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>()) {
4985-
if (auto name = objc->getName()) {
4986-
assert(name->getNumSelectorPieces() == 1);
4987-
return name->getSelectorPieces().front().str();
4988-
}
4989-
}
4990-
4991-
if (customNamesOnly)
4992-
return StringRef();
4993-
4994-
if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl())) {
4995-
if (const clang::IdentifierInfo *II = clangDecl->getIdentifier())
4996-
return II->getName();
4997-
if (auto *anonDecl = dyn_cast<clang::TagDecl>(clangDecl))
4998-
if (auto *anonTypedef = anonDecl->getTypedefNameForAnonDecl())
4999-
return anonTypedef->getIdentifier()->getName();
5000-
}
5001-
5002-
return VD->getName().str();
5003-
}
5004-
5005-
bool swift::objc_translation::
5006-
printSwiftEnumElemNameInObjC(const EnumElementDecl *EL, llvm::raw_ostream &OS,
5007-
Identifier PreferredName) {
5008-
StringRef ElemName = getNameForObjC(EL, CustomNamesOnly);
5009-
if (!ElemName.empty()) {
5010-
OS << ElemName;
5011-
return true;
5012-
}
5013-
OS << getNameForObjC(EL->getDeclContext()->getAsEnumOrEnumExtensionContext());
5014-
if (PreferredName.empty())
5015-
ElemName = EL->getName().str();
5016-
else
5017-
ElemName = PreferredName.str();
5018-
5019-
SmallString<64> Scratch;
5020-
OS << camel_case::toSentencecase(ElemName, Scratch);
5021-
return false;
5022-
}
5023-
5024-
std::pair<Identifier, ObjCSelector> swift::objc_translation::
5025-
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
5026-
ASTContext &Ctx = VD->getASTContext();
5027-
LazyResolver *Resolver = Ctx.getLazyResolver();
5028-
if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
5029-
return {Identifier(), FD->getObjCSelector(Resolver, PreferredName)};
5030-
} else if (auto *VAD = dyn_cast<VarDecl>(VD)) {
5031-
if (PreferredName)
5032-
return {PreferredName.getBaseName(), ObjCSelector()};
5033-
return {VAD->getObjCPropertyName(), ObjCSelector()};
5034-
} else if (auto *SD = dyn_cast<SubscriptDecl>(VD)) {
5035-
return getObjCNameForSwiftDecl(SD->getGetter(), PreferredName);
5036-
} else if (auto *EL = dyn_cast<EnumElementDecl>(VD)) {
5037-
SmallString<64> Buffer;
5038-
{
5039-
llvm::raw_svector_ostream OS(Buffer);
5040-
printSwiftEnumElemNameInObjC(EL, OS, PreferredName.getBaseName());
5041-
}
5042-
return {Ctx.getIdentifier(Buffer.str()), ObjCSelector()};
5043-
} else {
5044-
// @objc(ExplicitName) > PreferredName > Swift name.
5045-
StringRef Name = getNameForObjC(VD, CustomNamesOnly);
5046-
if (!Name.empty())
5047-
return {Ctx.getIdentifier(Name), ObjCSelector()};
5048-
if (!PreferredName.getBaseName().empty())
5049-
return {PreferredName.getBaseName(), ObjCSelector()};
5050-
return {Ctx.getIdentifier(getNameForObjC(VD)), ObjCSelector()};
5051-
}
5052-
}

lib/AST/SwiftNameTranslation.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===--- SwiftNameTranslation.cpp - Swift to ObjC Name Translation APIs ---===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file contains utilities for translating Swift names to ObjC.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/AST/SwiftNameTranslation.h"
18+
#include "swift/AST/ASTContext.h"
19+
#include "swift/AST/Decl.h"
20+
#include "swift/AST/LazyResolver.h"
21+
#include "swift/Basic/StringExtras.h"
22+
23+
#include "clang/AST/DeclObjC.h"
24+
#include "llvm/ADT/SmallString.h"
25+
26+
using namespace swift;
27+
28+
StringRef swift::objc_translation::
29+
getNameForObjC(const ValueDecl *VD, CustomNamesOnly_t customNamesOnly) {
30+
assert(isa<ClassDecl>(VD) || isa<ProtocolDecl>(VD) || isa<StructDecl>(VD) ||
31+
isa<EnumDecl>(VD) || isa<EnumElementDecl>(VD));
32+
if (auto objc = VD->getAttrs().getAttribute<ObjCAttr>()) {
33+
if (auto name = objc->getName()) {
34+
assert(name->getNumSelectorPieces() == 1);
35+
return name->getSelectorPieces().front().str();
36+
}
37+
}
38+
39+
if (customNamesOnly)
40+
return StringRef();
41+
42+
if (auto clangDecl = dyn_cast_or_null<clang::NamedDecl>(VD->getClangDecl())) {
43+
if (const clang::IdentifierInfo *II = clangDecl->getIdentifier())
44+
return II->getName();
45+
if (auto *anonDecl = dyn_cast<clang::TagDecl>(clangDecl))
46+
if (auto *anonTypedef = anonDecl->getTypedefNameForAnonDecl())
47+
return anonTypedef->getIdentifier()->getName();
48+
}
49+
50+
return VD->getName().str();
51+
}
52+
53+
bool swift::objc_translation::
54+
printSwiftEnumElemNameInObjC(const EnumElementDecl *EL, llvm::raw_ostream &OS,
55+
Identifier PreferredName) {
56+
StringRef ElemName = getNameForObjC(EL, CustomNamesOnly);
57+
if (!ElemName.empty()) {
58+
OS << ElemName;
59+
return true;
60+
}
61+
OS << getNameForObjC(EL->getDeclContext()->getAsEnumOrEnumExtensionContext());
62+
if (PreferredName.empty())
63+
ElemName = EL->getName().str();
64+
else
65+
ElemName = PreferredName.str();
66+
67+
SmallString<64> Scratch;
68+
OS << camel_case::toSentencecase(ElemName, Scratch);
69+
return false;
70+
}
71+
72+
std::pair<Identifier, ObjCSelector> swift::objc_translation::
73+
getObjCNameForSwiftDecl(const ValueDecl *VD, DeclName PreferredName){
74+
ASTContext &Ctx = VD->getASTContext();
75+
LazyResolver *Resolver = Ctx.getLazyResolver();
76+
if (auto *FD = dyn_cast<AbstractFunctionDecl>(VD)) {
77+
return {Identifier(), FD->getObjCSelector(Resolver, PreferredName)};
78+
} else if (auto *VAD = dyn_cast<VarDecl>(VD)) {
79+
if (PreferredName)
80+
return {PreferredName.getBaseName(), ObjCSelector()};
81+
return {VAD->getObjCPropertyName(), ObjCSelector()};
82+
} else if (auto *SD = dyn_cast<SubscriptDecl>(VD)) {
83+
return getObjCNameForSwiftDecl(SD->getGetter(), PreferredName);
84+
} else if (auto *EL = dyn_cast<EnumElementDecl>(VD)) {
85+
SmallString<64> Buffer;
86+
{
87+
llvm::raw_svector_ostream OS(Buffer);
88+
printSwiftEnumElemNameInObjC(EL, OS, PreferredName.getBaseName());
89+
}
90+
return {Ctx.getIdentifier(Buffer.str()), ObjCSelector()};
91+
} else {
92+
// @objc(ExplicitName) > PreferredName > Swift name.
93+
StringRef Name = getNameForObjC(VD, CustomNamesOnly);
94+
if (!Name.empty())
95+
return {Ctx.getIdentifier(Name), ObjCSelector()};
96+
if (!PreferredName.getBaseName().empty())
97+
return {PreferredName.getBaseName(), ObjCSelector()};
98+
return {Ctx.getIdentifier(getNameForObjC(VD)), ObjCSelector()};
99+
}
100+
}
101+
102+
bool swift::objc_translation::
103+
isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess,
104+
bool checkParent) {
105+
if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
106+
return false;
107+
if (VD->hasAccessibility() && VD->getFormalAccess() >= minRequiredAccess) {
108+
return true;
109+
} else if (checkParent) {
110+
if (auto ctor = dyn_cast<ConstructorDecl>(VD)) {
111+
// Check if we're overriding an initializer that is visible to obj-c
112+
if (auto parent = ctor->getOverriddenDecl())
113+
return isVisibleToObjC(parent, minRequiredAccess, false);
114+
}
115+
}
116+
return false;
117+
}

lib/AST/USRGeneration.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "swift/AST/USRGeneration.h"
1616
#include "swift/AST/Mangle.h"
1717
#include "swift/AST/ASTMangler.h"
18+
#include "swift/AST/SwiftNameTranslation.h"
1819
#include "llvm/ADT/SmallString.h"
1920
#include "llvm/ADT/StringRef.h"
2021
#include "llvm/Support/raw_ostream.h"
@@ -45,6 +46,97 @@ bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) {
4546
return false;
4647
}
4748

49+
static bool printObjCUSRFragment(const ValueDecl *D, StringRef ObjCName,
50+
raw_ostream &OS) {
51+
if (!D)
52+
return true;
53+
54+
if (isa<ClassDecl>(D)) {
55+
clang::index::generateUSRForObjCClass(ObjCName, OS);
56+
} else if (isa<ProtocolDecl>(D)) {
57+
clang::index::generateUSRForObjCProtocol(ObjCName, OS);
58+
} else if (isa<VarDecl>(D)) {
59+
clang::index::generateUSRForObjCProperty(ObjCName, D->isStatic(), OS);
60+
} else if (isa<AbstractFunctionDecl>(D)) {
61+
clang::index::generateUSRForObjCMethod(ObjCName, D->isInstanceMember(), OS);
62+
} else if (isa<EnumDecl>(D)) {
63+
OS << "@E@" << ObjCName; // FIXME: expose clang API to handle enum names
64+
} else if (isa<EnumElementDecl>(D)) {
65+
OS << "@" << ObjCName;
66+
} else {
67+
llvm_unreachable("Unexpected value decl");
68+
}
69+
return false;
70+
}
71+
72+
static bool printObjCUSRForAccessor(const AbstractStorageDecl *ASD,
73+
AccessorKind Kind,
74+
raw_ostream &OS) {
75+
ObjCSelector Selector;
76+
switch (Kind) {
77+
case swift::AccessorKind::IsGetter:
78+
Selector = ASD->getObjCGetterSelector();
79+
break;
80+
case swift::AccessorKind::IsSetter:
81+
Selector = ASD->getObjCSetterSelector();
82+
break;
83+
default:
84+
llvm_unreachable("invalid accessor kind");
85+
}
86+
assert(Selector);
87+
llvm::SmallString<128> Buf;
88+
clang::index::generateUSRForObjCMethod(Selector.getString(Buf),
89+
ASD->isInstanceMember(), OS);
90+
return false;
91+
}
92+
93+
static bool printObjCUSR(const ValueDecl *D, raw_ostream &OS) {
94+
OS << clang::index::getUSRSpacePrefix();
95+
96+
if (auto *Parent = D->getDeclContext()->
97+
getAsNominalTypeOrNominalTypeExtensionContext()) {
98+
auto ObjCName = objc_translation::getObjCNameForSwiftDecl(Parent);
99+
if (printObjCUSRFragment(Parent, ObjCName.first.str(), OS))
100+
return true;
101+
}
102+
103+
auto ObjCName = objc_translation::getObjCNameForSwiftDecl(D);
104+
105+
if (!ObjCName.first.empty())
106+
return printObjCUSRFragment(D, ObjCName.first.str(), OS);
107+
108+
assert(ObjCName.second);
109+
llvm::SmallString<128> Buf;
110+
return printObjCUSRFragment(D, ObjCName.second.getString(Buf), OS);
111+
}
112+
113+
static bool ShouldUseObjCUSR(const Decl *D) {
114+
// Only the subscript getter/setter are visible to ObjC rather than the
115+
// subscript itself
116+
if (isa<SubscriptDecl>(D))
117+
return false;
118+
119+
auto Parent = D->getDeclContext()->getInnermostDeclarationDeclContext();
120+
if (Parent && (!ShouldUseObjCUSR(Parent) || // parent should be visible too
121+
!D->getDeclContext()->isTypeContext() || // no local decls
122+
isa<TypeDecl>(D))) // nested types aren't supported
123+
return false;
124+
125+
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
126+
if (isa<EnumElementDecl>(VD))
127+
return true;
128+
return objc_translation::isVisibleToObjC(VD, Accessibility::Internal);
129+
}
130+
131+
if (const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D)) {
132+
if (auto ExtendedType = ED->getExtendedType()) {
133+
auto baseClass = ExtendedType->getClassOrBoundGenericClass();
134+
return baseClass && ShouldUseObjCUSR(baseClass) && !baseClass->isForeign();
135+
}
136+
}
137+
return false;
138+
}
139+
48140
bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) {
49141
using namespace Mangle;
50142

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

202+
if (ShouldUseObjCUSR(VD)) {
203+
return printObjCUSR(VD, OS);
204+
}
205+
110206
if (!D->hasInterfaceType())
111207
return true;
112208

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

162258
AbstractStorageDecl *SD = const_cast<AbstractStorageDecl*>(D);
259+
if (ShouldUseObjCUSR(SD)) {
260+
return printObjCUSRForAccessor(SD, AccKind, OS);
261+
}
262+
163263
std::string Old = getUSRSpacePrefix().str();
164264
Mangler Mangler;
165265
Mangler.mangleAccessorEntity(AccKind, AddressorKind::NotAddressor, SD);

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,19 +188,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
188188
os << "@end\n\n";
189189
}
190190

191-
bool shouldInclude(const ValueDecl *VD, bool checkParent = true) {
192-
if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>()))
193-
return false;
194-
if (VD->getFormalAccess() >= minRequiredAccess) {
195-
return true;
196-
} else if (checkParent) {
197-
if (auto ctor = dyn_cast<ConstructorDecl>(VD)) {
198-
// Check if we're overriding an initializer that is visible to obj-c
199-
if (auto parent = ctor->getOverriddenDecl())
200-
return shouldInclude(parent, false);
201-
}
202-
}
203-
return false;
191+
bool shouldInclude(const ValueDecl *VD) {
192+
return isVisibleToObjC(VD, minRequiredAccess);
204193
}
205194

206195
private:

0 commit comments

Comments
 (0)