forked from OSchip/llvm-project
Add an optional string argument to DeprecatedAttr for Fix-It.
We only add this to __attribute__((deprecated)). Differential Revision: http://reviews.llvm.org/D17865 llvm-svn: 263652
This commit is contained in:
parent
8a46c067ed
commit
c7890fed01
|
@ -722,8 +722,11 @@ def OpenCLGenericAddressSpace : TypeAttr {
|
|||
def Deprecated : InheritableAttr {
|
||||
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
|
||||
CXX11<"","deprecated", 201309>];
|
||||
let Args = [StringArgument<"Message", 1>];
|
||||
let Documentation = [Undocumented];
|
||||
let Args = [StringArgument<"Message", 1>,
|
||||
// An optional string argument that enables us to provide a
|
||||
// Fix-It.
|
||||
StringArgument<"Replacement", 1>];
|
||||
let Documentation = [DeprecatedDocs];
|
||||
}
|
||||
|
||||
def Destructor : InheritableAttr {
|
||||
|
|
|
@ -2239,3 +2239,24 @@ experimental at this time.
|
|||
}];
|
||||
}
|
||||
|
||||
def DeprecatedDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``deprecated`` attribute can be applied to a function, a variable, or a
|
||||
type. This is useful when identifying functions, variables, or types that are
|
||||
expected to be removed in a future version of a program.
|
||||
|
||||
Consider the function declaration for a hypothetical function ``f``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void f(void) __attribute__((deprecated("message", "replacement")));
|
||||
|
||||
When spelled as `__attribute__((deprecated))`, the deprecated attribute can have
|
||||
two optional string arguments. The first one is the message to display when
|
||||
emitting the warning; the second one enables the compiler to provide a Fix-It
|
||||
to replace the deprecated name with a new name. Otherwise, when spelled as
|
||||
`[[gnu::deprecated]] or [[deprecated]]`, the attribute can have one optional
|
||||
string argument which is the message to display when emitting the warning.
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -1079,6 +1079,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
|||
.Case("attribute_cf_returns_retained", true)
|
||||
.Case("attribute_cf_returns_on_parameters", true)
|
||||
.Case("attribute_deprecated_with_message", true)
|
||||
.Case("attribute_deprecated_with_replacement", true)
|
||||
.Case("attribute_ext_vector_type", true)
|
||||
.Case("attribute_ns_returns_not_retained", true)
|
||||
.Case("attribute_ns_returns_retained", true)
|
||||
|
|
|
@ -5136,12 +5136,27 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
}
|
||||
}
|
||||
|
||||
// Handle the cases where the attribute has a text message.
|
||||
StringRef Str, Replacement;
|
||||
if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) &&
|
||||
!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
|
||||
return;
|
||||
|
||||
// Only support a single optional message for Declspec and CXX11.
|
||||
if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute())
|
||||
checkAttributeAtMostNumArgs(S, Attr, 1);
|
||||
else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) &&
|
||||
!S.checkStringLiteralArgumentAttr(Attr, 1, Replacement))
|
||||
return;
|
||||
|
||||
if (!S.getLangOpts().CPlusPlus14)
|
||||
if (Attr.isCXX11Attribute() &&
|
||||
!(Attr.hasScope() && Attr.getScopeName()->isStr("gnu")))
|
||||
S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName();
|
||||
|
||||
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
|
||||
D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str,
|
||||
Replacement,
|
||||
Attr.getAttributeSpellingListIndex()));
|
||||
}
|
||||
|
||||
static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||
|
@ -6209,18 +6224,35 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
|
|||
break;
|
||||
}
|
||||
|
||||
CharSourceRange UseRange;
|
||||
StringRef Replacement;
|
||||
if (K == Sema::AD_Deprecation) {
|
||||
if (auto attr = D->getAttr<DeprecatedAttr>())
|
||||
Replacement = attr->getReplacement();
|
||||
|
||||
if (!Replacement.empty())
|
||||
UseRange =
|
||||
CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
|
||||
}
|
||||
|
||||
if (!Message.empty()) {
|
||||
S.Diag(Loc, diag_message) << D << Message;
|
||||
S.Diag(Loc, diag_message) << D << Message
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
if (ObjCProperty)
|
||||
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
|
||||
<< ObjCProperty->getDeclName() << property_note_select;
|
||||
} else if (!UnknownObjCClass) {
|
||||
S.Diag(Loc, diag) << D;
|
||||
S.Diag(Loc, diag) << D
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
if (ObjCProperty)
|
||||
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
|
||||
<< ObjCProperty->getDeclName() << property_note_select;
|
||||
} else {
|
||||
S.Diag(Loc, diag_fwdclass_message) << D;
|
||||
S.Diag(Loc, diag_fwdclass_message) << D
|
||||
<< (UseRange.isValid() ?
|
||||
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
|
||||
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -verify -fsyntax-only -std=c++11 -fms-extensions %s
|
||||
|
||||
#if !__has_feature(attribute_deprecated_with_replacement)
|
||||
#error "Missing __has_feature"
|
||||
#endif
|
||||
|
||||
int a1 [[deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
int a2 [[deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
|
||||
int b1 [[gnu::deprecated("warning", "fixit")]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
int b2 [[gnu::deprecated("warning", 1)]]; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
|
||||
__declspec(deprecated("warning", "fixit")) int c1; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
__declspec(deprecated("warning", 1)) int c2; // expected-error{{'deprecated' attribute takes no more than 1 argument}}
|
||||
|
||||
int d1 __attribute__((deprecated("warning", "fixit")));
|
||||
int d2 __attribute__((deprecated("warning", 1))); // expected-error{{'deprecated' attribute requires a string}}
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -verify -fsyntax-only %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
|
||||
// RUN: cp %s %t
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fixit %t
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -Werror %t
|
||||
|
||||
#if !__has_feature(attribute_deprecated_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 test() {
|
||||
f_8(0); // expected-warning{{'f_8' is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:6}:"new8"
|
||||
}
|
|
@ -16,6 +16,15 @@ int a __attribute__((deprecated("warning")));
|
|||
// CHECK: int b {{\[}}[gnu::deprecated("warning")]];
|
||||
int b [[gnu::deprecated("warning")]];
|
||||
|
||||
// CHECK: __declspec(deprecated("warning"))
|
||||
__declspec(deprecated("warning")) int c;
|
||||
|
||||
// CHECK: int d {{\[}}[deprecated("warning")]];
|
||||
int d [[deprecated("warning")]];
|
||||
|
||||
// CHECK: __attribute__((deprecated("warning", "fixit")));
|
||||
int e __attribute__((deprecated("warning", "fixit")));
|
||||
|
||||
// CHECK: int cxx11_alignas alignas(4);
|
||||
alignas(4) int cxx11_alignas;
|
||||
|
||||
|
|
|
@ -1111,6 +1111,15 @@ static void writeAvailabilityValue(raw_ostream &OS) {
|
|||
<< " OS << \"";
|
||||
}
|
||||
|
||||
static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) {
|
||||
OS << "\\\"\" << getMessage() << \"\\\"\";\n";
|
||||
// Only GNU deprecated has an optional fixit argument at the second position.
|
||||
if (Variety == "GNU")
|
||||
OS << " if (!getReplacement().empty()) OS << \", \\\"\""
|
||||
" << getReplacement() << \"\\\"\";\n";
|
||||
OS << " OS << \"";
|
||||
}
|
||||
|
||||
static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
|
||||
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
|
||||
|
||||
|
@ -1224,6 +1233,8 @@ writePrettyPrintFunction(Record &R,
|
|||
OS << "(";
|
||||
if (Spelling == "availability") {
|
||||
writeAvailabilityValue(OS);
|
||||
} else if (Spelling == "deprecated" || Spelling == "gnu::deprecated") {
|
||||
writeDeprecatedAttrValue(OS, Variety);
|
||||
} else {
|
||||
unsigned index = 0;
|
||||
for (const auto &arg : Args) {
|
||||
|
|
Loading…
Reference in New Issue