forked from OSchip/llvm-project
Add an optional named argument (replacement = "xxx") to AvailabilityAttr.
This commit adds a named argument to AvailabilityAttr, while r263652 adds an optional string argument to __attribute__((deprecated)). This enables the compiler to provide Fix-Its for deprecated declarations. rdar://20588929 llvm-svn: 263687
This commit is contained in:
parent
b76c027717
commit
a7c4760c8e
|
@ -467,7 +467,7 @@ def Availability : InheritableAttr {
|
|||
let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">,
|
||||
VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
|
||||
BoolArgument<"unavailable">, StringArgument<"message">,
|
||||
BoolArgument<"strict">];
|
||||
BoolArgument<"strict">, StringArgument<"replacement">];
|
||||
let AdditionalMembers =
|
||||
[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
|
||||
return llvm::StringSwitch<llvm::StringRef>(Platform)
|
||||
|
|
|
@ -661,6 +661,11 @@ message=\ *string-literal*
|
|||
error about use of a deprecated or obsoleted declaration. Useful to direct
|
||||
users to replacement APIs.
|
||||
|
||||
replacement=\ *string-literal*
|
||||
Additional message text that Clang will use to provide Fix-It when emitting
|
||||
a warning about use of a deprecated declaration. The Fix-It will replace
|
||||
the deprecated declaration with the new declaration specified.
|
||||
|
||||
Multiple availability attributes can be placed on a declaration, which may
|
||||
correspond to different platforms. Only the availability attribute with the
|
||||
platform corresponding to the target platform will be used; any others will be
|
||||
|
|
|
@ -137,6 +137,9 @@ class Parser : public CodeCompletionHandler {
|
|||
/// \brief Identifier for "strict".
|
||||
IdentifierInfo *Ident_strict;
|
||||
|
||||
/// \brief Identifier for "replacement".
|
||||
IdentifierInfo *Ident_replacement;
|
||||
|
||||
/// C++0x contextual keywords.
|
||||
mutable IdentifierInfo *Ident_final;
|
||||
mutable IdentifierInfo *Ident_override;
|
||||
|
|
|
@ -174,6 +174,14 @@ private:
|
|||
&getAvailabilitySlot(ObsoletedSlot) + 1);
|
||||
}
|
||||
|
||||
const Expr **getReplacementSlot() {
|
||||
return reinterpret_cast<const Expr**>(getStrictSlot() + 1);
|
||||
}
|
||||
|
||||
const Expr *const *getReplacementSlot() const {
|
||||
return reinterpret_cast<const Expr *const *>(getStrictSlot() + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
struct TypeTagForDatatypeData {
|
||||
ParsedType *MatchingCType;
|
||||
|
@ -251,7 +259,8 @@ private:
|
|||
const AvailabilityChange &obsoleted,
|
||||
SourceLocation unavailable,
|
||||
const Expr *messageExpr,
|
||||
Syntax syntaxUsed, SourceLocation strict)
|
||||
Syntax syntaxUsed, SourceLocation strict,
|
||||
const Expr *replacementExpr)
|
||||
: AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
|
||||
ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
|
||||
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
|
||||
|
@ -264,6 +273,7 @@ private:
|
|||
new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated);
|
||||
new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted);
|
||||
memcpy(getStrictSlot(), &strict, sizeof(SourceLocation));
|
||||
*getReplacementSlot() = replacementExpr;
|
||||
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
|
||||
}
|
||||
|
||||
|
@ -456,6 +466,11 @@ public:
|
|||
return MessageExpr;
|
||||
}
|
||||
|
||||
const Expr *getReplacementExpr() const {
|
||||
assert(getKind() == AT_Availability && "Not an availability attribute");
|
||||
return *getReplacementSlot();
|
||||
}
|
||||
|
||||
const ParsedType &getMatchingCType() const {
|
||||
assert(getKind() == AT_TypeTagForDatatype &&
|
||||
"Not a type_tag_for_datatype attribute");
|
||||
|
@ -523,7 +538,7 @@ public:
|
|||
AvailabilityAllocSize =
|
||||
sizeof(AttributeList)
|
||||
+ ((3 * sizeof(AvailabilityChange) + sizeof(void*) +
|
||||
sizeof(ArgsUnion) + sizeof(SourceLocation) - 1)
|
||||
sizeof(ArgsUnion) + sizeof(SourceLocation) + sizeof(const Expr *) - 1)
|
||||
/ sizeof(void*) * sizeof(void*)),
|
||||
TypeTagForDatatypeAllocSize =
|
||||
sizeof(AttributeList)
|
||||
|
@ -642,13 +657,13 @@ public:
|
|||
SourceLocation unavailable,
|
||||
const Expr *MessageExpr,
|
||||
AttributeList::Syntax syntax,
|
||||
SourceLocation strict) {
|
||||
SourceLocation strict, const Expr *ReplacementExpr) {
|
||||
void *memory = allocate(AttributeFactory::AvailabilityAllocSize);
|
||||
return add(new (memory) AttributeList(attrName, attrRange,
|
||||
scopeName, scopeLoc,
|
||||
Param, introduced, deprecated,
|
||||
obsoleted, unavailable, MessageExpr,
|
||||
syntax, strict));
|
||||
syntax, strict, ReplacementExpr));
|
||||
}
|
||||
|
||||
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
|
||||
|
@ -778,11 +793,11 @@ public:
|
|||
SourceLocation unavailable,
|
||||
const Expr *MessageExpr,
|
||||
AttributeList::Syntax syntax,
|
||||
SourceLocation strict) {
|
||||
SourceLocation strict, const Expr *ReplacementExpr) {
|
||||
AttributeList *attr =
|
||||
pool.create(attrName, attrRange, scopeName, scopeLoc, Param, introduced,
|
||||
deprecated, obsoleted, unavailable, MessageExpr, syntax,
|
||||
strict);
|
||||
strict, ReplacementExpr);
|
||||
add(attr);
|
||||
return attr;
|
||||
}
|
||||
|
|
|
@ -2110,7 +2110,7 @@ public:
|
|||
VersionTuple Obsoleted,
|
||||
bool IsUnavailable,
|
||||
StringRef Message,
|
||||
bool IsStrict,
|
||||
bool IsStrict, StringRef Replacement,
|
||||
AvailabilityMergeKind AMK,
|
||||
unsigned AttrSpellingListIndex);
|
||||
TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
|
||||
|
|
|
@ -1074,6 +1074,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
|||
.Case("attribute_availability_tvos", true)
|
||||
.Case("attribute_availability_watchos", true)
|
||||
.Case("attribute_availability_with_strict", true)
|
||||
.Case("attribute_availability_with_replacement", true)
|
||||
.Case("attribute_availability_in_templates", true)
|
||||
.Case("attribute_cf_returns_not_retained", true)
|
||||
.Case("attribute_cf_returns_retained", true)
|
||||
|
|
|
@ -833,7 +833,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
|
|||
/// \brief Parse the contents of the "availability" attribute.
|
||||
///
|
||||
/// availability-attribute:
|
||||
/// 'availability' '(' platform ',' opt-strict version-arg-list, opt-message')'
|
||||
/// 'availability' '(' platform ',' opt-strict version-arg-list,
|
||||
/// opt-replacement, opt-message')'
|
||||
///
|
||||
/// platform:
|
||||
/// identifier
|
||||
|
@ -850,6 +851,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
|
|||
/// 'deprecated' '=' version
|
||||
/// 'obsoleted' = version
|
||||
/// 'unavailable'
|
||||
/// opt-replacement:
|
||||
/// 'replacement' '=' <string>
|
||||
/// opt-message:
|
||||
/// 'message' '=' <string>
|
||||
void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
||||
|
@ -861,7 +864,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
AttributeList::Syntax Syntax) {
|
||||
enum { Introduced, Deprecated, Obsoleted, Unknown };
|
||||
AvailabilityChange Changes[Unknown];
|
||||
ExprResult MessageExpr;
|
||||
ExprResult MessageExpr, ReplacementExpr;
|
||||
|
||||
// Opening '('.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
|
@ -893,9 +896,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
Ident_unavailable = PP.getIdentifierInfo("unavailable");
|
||||
Ident_message = PP.getIdentifierInfo("message");
|
||||
Ident_strict = PP.getIdentifierInfo("strict");
|
||||
Ident_replacement = PP.getIdentifierInfo("replacement");
|
||||
}
|
||||
|
||||
// Parse the optional "strict" and the set of
|
||||
// Parse the optional "strict", the optional "replacement" and the set of
|
||||
// introductions/deprecations/removals.
|
||||
SourceLocation UnavailableLoc, StrictLoc;
|
||||
do {
|
||||
|
@ -931,14 +935,17 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
return;
|
||||
}
|
||||
ConsumeToken();
|
||||
if (Keyword == Ident_message) {
|
||||
if (Keyword == Ident_message || Keyword == Ident_replacement) {
|
||||
if (Tok.isNot(tok::string_literal)) {
|
||||
Diag(Tok, diag::err_expected_string_literal)
|
||||
<< /*Source='availability attribute'*/2;
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
return;
|
||||
}
|
||||
MessageExpr = ParseStringLiteralExpression();
|
||||
if (Keyword == Ident_message)
|
||||
MessageExpr = ParseStringLiteralExpression();
|
||||
else
|
||||
ReplacementExpr = ParseStringLiteralExpression();
|
||||
// Also reject wide string literals.
|
||||
if (StringLiteral *MessageStringLiteral =
|
||||
cast_or_null<StringLiteral>(MessageExpr.get())) {
|
||||
|
@ -950,7 +957,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (Keyword == Ident_message)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special handling of 'NA' only when applied to introduced or
|
||||
|
@ -1037,7 +1047,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
|
|||
Changes[Deprecated],
|
||||
Changes[Obsoleted],
|
||||
UnavailableLoc, MessageExpr.get(),
|
||||
Syntax, StrictLoc);
|
||||
Syntax, StrictLoc, ReplacementExpr.get());
|
||||
}
|
||||
|
||||
/// \brief Parse the contents of the "objc_bridge_related" attribute.
|
||||
|
|
|
@ -492,6 +492,7 @@ void Parser::Initialize() {
|
|||
Ident_obsoleted = nullptr;
|
||||
Ident_unavailable = nullptr;
|
||||
Ident_strict = nullptr;
|
||||
Ident_replacement = nullptr;
|
||||
|
||||
Ident__except = nullptr;
|
||||
|
||||
|
|
|
@ -2196,7 +2196,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
|||
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
|
||||
AA->getIntroduced(), AA->getDeprecated(),
|
||||
AA->getObsoleted(), AA->getUnavailable(),
|
||||
AA->getMessage(), AA->getStrict(), AMK,
|
||||
AA->getMessage(), AA->getStrict(),
|
||||
AA->getReplacement(), AMK,
|
||||
AttrSpellingListIndex);
|
||||
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
|
||||
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
|
||||
|
|
|
@ -1941,6 +1941,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
|
|||
bool IsUnavailable,
|
||||
StringRef Message,
|
||||
bool IsStrict,
|
||||
StringRef Replacement,
|
||||
AvailabilityMergeKind AMK,
|
||||
unsigned AttrSpellingListIndex) {
|
||||
VersionTuple MergedIntroduced = Introduced;
|
||||
|
@ -2087,7 +2088,8 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
|
|||
return ::new (Context) AvailabilityAttr(Range, Context, Platform,
|
||||
Introduced, Deprecated,
|
||||
Obsoleted, IsUnavailable, Message,
|
||||
IsStrict, AttrSpellingListIndex);
|
||||
IsStrict, Replacement,
|
||||
AttrSpellingListIndex);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2119,13 +2121,17 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
if (const StringLiteral *SE =
|
||||
dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr()))
|
||||
Str = SE->getString();
|
||||
StringRef Replacement;
|
||||
if (const StringLiteral *SE =
|
||||
dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr()))
|
||||
Replacement = SE->getString();
|
||||
|
||||
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II,
|
||||
Introduced.Version,
|
||||
Deprecated.Version,
|
||||
Obsoleted.Version,
|
||||
IsUnavailable, Str,
|
||||
IsStrict,
|
||||
IsStrict, Replacement,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -2171,6 +2177,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
NewObsoleted,
|
||||
IsUnavailable, Str,
|
||||
IsStrict,
|
||||
Replacement,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -2194,6 +2201,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
|
|||
Obsoleted.Version,
|
||||
IsUnavailable, Str,
|
||||
IsStrict,
|
||||
Replacement,
|
||||
Sema::AMK_None,
|
||||
Index);
|
||||
if (NewAttr)
|
||||
|
@ -6229,6 +6237,8 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
|
|||
if (K == Sema::AD_Deprecation) {
|
||||
if (auto attr = D->getAttr<DeprecatedAttr>())
|
||||
Replacement = attr->getReplacement();
|
||||
if (auto attr = D->getAttr<AvailabilityAttr>())
|
||||
Replacement = attr->getReplacement();
|
||||
|
||||
if (!Replacement.empty())
|
||||
UseRange =
|
||||
|
|
|
@ -8,9 +8,17 @@
|
|||
#error "Missing __has_feature"
|
||||
#endif
|
||||
|
||||
#if !__has_feature(attribute_availability_with_replacement)
|
||||
#error "Missing __has_feature"
|
||||
#endif
|
||||
|
||||
void f_8(int) __attribute__((deprecated("message", "new8"))); // expected-note {{'f_8' has been explicitly marked deprecated here}}
|
||||
void new8(int);
|
||||
void f_2(int) __attribute__((availability(macosx,deprecated=9.0,replacement="new2"))); // expected-note {{'f_2' has been explicitly marked deprecated here}}
|
||||
void new2(int);
|
||||
void test() {
|
||||
f_8(0); // expected-warning{{'f_8' is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:6}:"new8"
|
||||
f_2(0); // expected-warning{{'f_2' is deprecated: first deprecated in OS X 9.0}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:6}:"new2"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue