Skip to content

Commit 30dbf22

Browse files
slavapestovtkremenek
authored andcommitted
Add support for Clang availability replacement attribute (#2837)
* Sema: Clean up availability code a bit, NFC * ClangImporter: Add support for __attribute__((availability(..., replacement=""))) We map clang::AvailabilityAttr::getReplacement() to swift::AvailableAttr::Rename, transforming the replacement name using by looking up the named Clang replacement, and importing its name. Fixes <rdar://problem/26301742>.
1 parent 1c3483c commit 30dbf22

File tree

8 files changed

+100
-50
lines changed

8 files changed

+100
-50
lines changed

lib/AST/Attr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,9 +696,9 @@ ObjCAttr *ObjCAttr::clone(ASTContext &context) const {
696696

697697
AvailableAttr *
698698
AvailableAttr::createUnconditional(ASTContext &C,
699-
StringRef Message,
700-
StringRef Rename,
701-
UnconditionalAvailabilityKind Reason) {
699+
StringRef Message,
700+
StringRef Rename,
701+
UnconditionalAvailabilityKind Reason) {
702702
assert(Reason != UnconditionalAvailabilityKind::None);
703703
clang::VersionTuple NoVersion;
704704
return new (C) AvailableAttr(

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,7 @@ printFullContextPrefix(ClangImporter::Implementation::ImportedName name,
19301930
}
19311931

19321932
void ClangImporter::Implementation::printSwiftName(ImportedName name,
1933+
bool fullyQualified,
19331934
llvm::raw_ostream &os) {
19341935
// Property accessors.
19351936
bool isGetter = false;
@@ -1951,9 +1952,7 @@ void ClangImporter::Implementation::printSwiftName(ImportedName name,
19511952
break;
19521953
}
19531954

1954-
// If we're importing a global as a member, we need to provide the
1955-
// effective context.
1956-
if (name.ImportAsMember)
1955+
if (fullyQualified)
19571956
printFullContextPrefix(name, os, *this);
19581957

19591958
// Base name.

lib/ClangImporter/ImportDecl.cpp

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,12 @@ namespace {
12761276
{
12771277
// Render a swift_name string.
12781278
llvm::raw_svector_ostream os(renamed);
1279-
Impl.printSwiftName(swift3Name, os);
1279+
1280+
// If we're importing a global as a member, we need to provide the
1281+
// effective context.
1282+
Impl.printSwiftName(swift3Name,
1283+
/*fullyQualified=*/swift3Name.ImportAsMember,
1284+
os);
12801285
}
12811286

12821287
auto attr = AvailableAttr::createUnconditional(
@@ -6073,6 +6078,38 @@ clang::SwiftNewtypeAttr *ClangImporter::Implementation::getSwiftNewtypeAttr(
60736078
return decl->getAttr<clang::SwiftNewtypeAttr>();
60746079
}
60756080

6081+
StringRef ClangImporter::Implementation::
6082+
getSwiftNameFromClangName(StringRef replacement) {
6083+
auto &clangSema = getClangSema();
6084+
6085+
clang::IdentifierInfo *identifier =
6086+
&clangSema.getASTContext().Idents.get(replacement);
6087+
clang::LookupResult lookupResult(clangSema, identifier,
6088+
clang::SourceLocation(),
6089+
clang::Sema::LookupOrdinaryName);
6090+
if (!clangSema.LookupName(lookupResult, nullptr))
6091+
return "";
6092+
6093+
auto clangDecl = lookupResult.getAsSingle<clang::NamedDecl>();
6094+
if (!clangDecl)
6095+
return "";
6096+
6097+
auto importedName = importFullName(clangDecl, None, &clangSema);
6098+
if (!importedName)
6099+
return "";
6100+
6101+
llvm::SmallString<64> renamed;
6102+
{
6103+
// Render a swift_name string.
6104+
llvm::raw_svector_ostream os(renamed);
6105+
printSwiftName(importedName,
6106+
/*fullyQualified=*/true,
6107+
os);
6108+
}
6109+
6110+
return SwiftContext.AllocateCopy(StringRef(renamed));
6111+
}
6112+
60766113
/// Import Clang attributes as Swift attributes.
60776114
void ClangImporter::Implementation::importAttributes(
60786115
const clang::NamedDecl *ClangDecl,
@@ -6091,7 +6128,7 @@ void ClangImporter::Implementation::importAttributes(
60916128
for (clang::NamedDecl::attr_iterator AI = ClangDecl->attr_begin(),
60926129
AE = ClangDecl->attr_end(); AI != AE; ++AI) {
60936130
//
6094-
// __attribute__((unavailable)
6131+
// __attribute__((unavailable))
60956132
//
60966133
// Mapping: @available(*,unavailable)
60976134
//
@@ -6137,8 +6174,13 @@ void ClangImporter::Implementation::importAttributes(
61376174

61386175
// Is this our special "availability(swift, unavailable)" attribute?
61396176
if (Platform == "swift") {
6177+
auto replacement = avail->getReplacement();
6178+
StringRef swiftReplacement = "";
6179+
if (!replacement.empty())
6180+
swiftReplacement = getSwiftNameFromClangName(replacement);
6181+
61406182
auto attr = AvailableAttr::createUnconditional(
6141-
C, avail->getMessage(), /*renamed*/"",
6183+
C, avail->getMessage(), swiftReplacement,
61426184
UnconditionalAvailabilityKind::UnavailableInSwift);
61436185
MappedDecl->getAttrs().add(attr);
61446186
AnyUnavailable = true;
@@ -6191,12 +6233,17 @@ void ClangImporter::Implementation::importAttributes(
61916233

61926234
const auto &obsoleted = avail->getObsoleted();
61936235
const auto &introduced = avail->getIntroduced();
6236+
const auto &replacement = avail->getReplacement();
6237+
6238+
StringRef swiftReplacement = "";
6239+
if (!replacement.empty())
6240+
swiftReplacement = getSwiftNameFromClangName(replacement);
61946241

61956242
auto AvAttr = new (C) AvailableAttr(SourceLoc(), SourceRange(),
6196-
platformK.getValue(),
6197-
message, /*rename*/StringRef(),
6198-
introduced, deprecated, obsoleted,
6199-
Unconditional, /*implicit=*/false);
6243+
platformK.getValue(),
6244+
message, swiftReplacement,
6245+
introduced, deprecated, obsoleted,
6246+
Unconditional, /*implicit=*/false);
62006247

62016248
MappedDecl->getAttrs().add(AvAttr);
62026249
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -940,8 +940,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
940940
const clang::MacroInfo *macro,
941941
clang::ASTContext &clangCtx);
942942

943-
/// Print an imported name as a string suitable for the swift_name attribute.
944-
void printSwiftName(ImportedName, llvm::raw_ostream &os);
943+
/// Print an imported name as a string suitable for the swift_name attribute,
944+
/// or the 'Rename' field of AvailableAttr.
945+
void printSwiftName(ImportedName, bool fullyQualified, llvm::raw_ostream &os);
945946

946947
/// Retrieve the property type as determined by the given accessor.
947948
static clang::QualType
@@ -987,6 +988,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
987988
const clang::TypedefNameDecl *decl,
988989
bool useSwift2Name);
989990

991+
/// Map a Clang identifier name to its imported Swift equivalent.
992+
StringRef getSwiftNameFromClangName(StringRef name);
993+
990994
/// Import attributes from the given Clang declaration to its Swift
991995
/// equivalent.
992996
///

lib/Sema/MiscDiagnostics.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,10 @@ bool TypeChecker::diagnoseExplicitUnavailability(
15531553
case UnconditionalAvailabilityKind::None:
15541554
case UnconditionalAvailabilityKind::Unavailable:
15551555
case UnconditionalAvailabilityKind::UnavailableInCurrentSwift:
1556+
case UnconditionalAvailabilityKind::UnavailableInSwift: {
1557+
bool inSwift = (Attr->getUnconditionalAvailability() ==
1558+
UnconditionalAvailabilityKind::UnavailableInSwift);
1559+
15561560
if (!Attr->Rename.empty()) {
15571561
SmallString<32> newNameBuf;
15581562
Optional<ReplacementDeclKind> replaceKind =
@@ -1567,32 +1571,25 @@ bool TypeChecker::diagnoseExplicitUnavailability(
15671571
newName);
15681572
attachRenameFixIts(diag);
15691573
} else {
1570-
auto diag = diagnose(Loc,diag::availability_decl_unavailable_rename_msg,
1574+
auto diag = diagnose(Loc, diag::availability_decl_unavailable_rename_msg,
15711575
Name, replaceKind.hasValue(), rawReplaceKind,
15721576
newName, Attr->Message);
15731577
attachRenameFixIts(diag);
15741578
}
15751579
} else if (Attr->Message.empty()) {
1576-
diagnose(Loc, diag::availability_decl_unavailable, Name).highlight(R);
1580+
diagnose(Loc, inSwift ? diag::availability_decl_unavailable_in_swift
1581+
: diag::availability_decl_unavailable,
1582+
Name).highlight(R);
15771583
} else {
15781584
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
1579-
diagnose(Loc, diag::availability_decl_unavailable_msg, Name,
1580-
EncodedMessage.Message)
1581-
.highlight(R);
1582-
}
1583-
break;
1584-
1585-
case UnconditionalAvailabilityKind::UnavailableInSwift:
1586-
if (Attr->Message.empty()) {
1587-
diagnose(Loc, diag::availability_decl_unavailable_in_swift, Name)
1585+
diagnose(Loc, inSwift ? diag::availability_decl_unavailable_in_swift_msg
1586+
: diag::availability_decl_unavailable_msg,
1587+
Name, EncodedMessage.Message)
15881588
.highlight(R);
1589-
} else {
1590-
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
1591-
diagnose(Loc, diag::availability_decl_unavailable_in_swift_msg, Name,
1592-
EncodedMessage.Message).highlight(R);
15931589
}
15941590
break;
15951591
}
1592+
}
15961593

15971594
auto MinVersion = Context.LangOpts.getMinPlatformVersion();
15981595
switch (Attr->getMinVersionAvailability(MinVersion)) {

lib/Sema/TypeCheckType.cpp

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,43 +1200,33 @@ static bool checkTypeDeclAvailability(Decl *TypeDecl, IdentTypeRepr *IdType,
12001200

12011201
case UnconditionalAvailabilityKind::Unavailable:
12021202
case UnconditionalAvailabilityKind::UnavailableInCurrentSwift:
1203-
if (!Attr->Rename.empty()) {
1204-
auto diag = TC.diagnose(Loc,
1205-
diag::availability_decl_unavailable_rename,
1206-
CI->getIdentifier(), /*"replaced"*/false,
1207-
/*special kind*/0, Attr->Rename);
1208-
fixItAvailableAttrRename(TC, diag, Loc, Attr, /*call*/nullptr);
1209-
} else if (Attr->Message.empty()) {
1210-
TC.diagnose(Loc, diag::availability_decl_unavailable,
1211-
CI->getIdentifier())
1212-
.highlight(Loc);
1213-
} else {
1214-
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
1215-
TC.diagnose(Loc, diag::availability_decl_unavailable_msg,
1216-
CI->getIdentifier(), EncodedMessage.Message)
1217-
.highlight(Loc);
1218-
}
1219-
break;
1203+
case UnconditionalAvailabilityKind::UnavailableInSwift: {
1204+
bool inSwift = (Attr->getUnconditionalAvailability() ==
1205+
UnconditionalAvailabilityKind::UnavailableInSwift);
12201206

1221-
case UnconditionalAvailabilityKind::UnavailableInSwift:
12221207
if (!Attr->Rename.empty()) {
12231208
auto diag = TC.diagnose(Loc,
12241209
diag::availability_decl_unavailable_rename,
12251210
CI->getIdentifier(), /*"replaced"*/false,
12261211
/*special kind*/0, Attr->Rename);
12271212
fixItAvailableAttrRename(TC, diag, Loc, Attr, /*call*/nullptr);
12281213
} else if (Attr->Message.empty()) {
1229-
TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift,
1214+
TC.diagnose(Loc,
1215+
inSwift ? diag::availability_decl_unavailable_in_swift
1216+
: diag::availability_decl_unavailable,
12301217
CI->getIdentifier())
12311218
.highlight(Loc);
12321219
} else {
12331220
EncodedDiagnosticMessage EncodedMessage(Attr->Message);
1234-
TC.diagnose(Loc, diag::availability_decl_unavailable_in_swift_msg,
1221+
TC.diagnose(Loc,
1222+
inSwift ? diag::availability_decl_unavailable_in_swift_msg
1223+
: diag::availability_decl_unavailable_msg,
12351224
CI->getIdentifier(), EncodedMessage.Message)
12361225
.highlight(Loc);
12371226
}
12381227
break;
12391228
}
1229+
}
12401230

12411231
auto DLoc = TypeDecl->getLoc();
12421232
if (DLoc.isValid())

test/ClangModules/availability.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,8 @@ func testImportAsMember() {
115115
_ = CGColorCreateGenericGray(0.5, 1.0) // expected-error {{'CGColorCreateGenericGray' has been replaced by 'CGColor.init(gray:alpha:)'}} {{7-31=CGColor}} {{32-32=gray: }} {{37-37=alpha: }}
116116
_ = CGColor(gray: 0.5, alpha: 1.0)
117117
}
118+
119+
func testUnavailableRenamedEnum() {
120+
_ = NSClothingStyle.hipster
121+
_ = NSClothingStyleOfficeCasual // expected-error{{'NSClothingStyleOfficeCasual' has been renamed to 'NSClothingStyle.semiFormal'}} {{7-34=NSClothingStyle.semiFormal}}
122+
}

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,3 +1021,11 @@ extern NSString *NSHTTPRequestKey;
10211021

10221022
#define NSTimeIntervalSince1970 978307200.0
10231023
#define NS_DO_SOMETHING 17
1024+
1025+
typedef NS_ENUM(NSUInteger, NSClothingStyle) {
1026+
NSClothingStyleFormal = 0,
1027+
NSClothingStyleSemiFormal,
1028+
NSClothingStyleHipster,
1029+
NSClothingStyleHippie
1030+
};
1031+
static const NSClothingStyle NSClothingStyleOfficeCasual __attribute__((availability(swift,unavailable,replacement="NSClothingStyleSemiFormal"))) = NSClothingStyleSemiFormal;

0 commit comments

Comments
 (0)