Skip to content

Commit

Permalink
Add an optional string argument to DeprecatedAttr for Fix-It.
Browse files Browse the repository at this point in the history
We only add this to __attribute__((deprecated)).

Differential Revision: http://reviews.llvm.org/D17865

llvm-svn: 263652
  • Loading branch information
manman-ren committed Mar 16, 2016
1 parent 8a46c06 commit c7890fe
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 6 deletions.
7 changes: 5 additions & 2 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -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 {
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Expand Up @@ -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.
}];
}
1 change: 1 addition & 0 deletions clang/lib/Lex/PPMacroExpansion.cpp
Expand Up @@ -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)
Expand Down
40 changes: 36 additions & 4 deletions clang/lib/Sema/SemaDeclAttr.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand Down
17 changes: 17 additions & 0 deletions clang/test/SemaCXX/attr-deprecated-replacement-error.cpp
@@ -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}}
16 changes: 16 additions & 0 deletions clang/test/SemaCXX/attr-deprecated-replacement-fixit.cpp
@@ -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"
}
9 changes: 9 additions & 0 deletions clang/test/SemaCXX/cxx11-attr-print.cpp
Expand Up @@ -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;

Expand Down
11 changes: 11 additions & 0 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit c7890fe

Please sign in to comment.