manmanren created this revision.
manmanren added reviewers: dexonsmith, rjmccall.
manmanren added a subscriber: cfe-commits.

This can be used to display Fix-Its.
We only add this to GNU attributes. Since it now has two optional arguments, 
and the common parsing does not handle "replacement = ", we use custom parsing 
for DeprecatedAttr.

http://reviews.llvm.org/D17865

Files:
  include/clang/Basic/Attr.td
  include/clang/Parse/Parser.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Parse/ParseDecl.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Sema/attr-availability-replacement.c
  test/SemaCXX/cxx11-attr-print.cpp

Index: test/SemaCXX/cxx11-attr-print.cpp
===================================================================
--- test/SemaCXX/cxx11-attr-print.cpp
+++ test/SemaCXX/cxx11-attr-print.cpp
@@ -10,12 +10,15 @@
 // CHECK: int z {{\[}}[gnu::aligned(4)]];
 int z [[gnu::aligned(4)]];
 
-// CHECK: __attribute__((deprecated("warning")));
+// CHECK: __attribute__((deprecated("warning", "")));
 int a __attribute__((deprecated("warning")));
 
-// CHECK: int b {{\[}}[gnu::deprecated("warning")]];
+// CHECK: int b {{\[}}[gnu::deprecated("warning", "")]];
 int b [[gnu::deprecated("warning")]];
 
+// CHECK: __attribute__((deprecated("", "")));
+int c __attribute__((deprecated));
+
 // CHECK: int cxx11_alignas alignas(4);
 alignas(4) int cxx11_alignas;
 
Index: test/Sema/attr-availability-replacement.c
===================================================================
--- test/Sema/attr-availability-replacement.c
+++ test/Sema/attr-availability-replacement.c
@@ -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(replacement="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"
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -5068,7 +5068,18 @@
         !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu")))
       S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension);
 
-  handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
+  // Handle the cases where the attribute has a text message or a replacement
+  // string, or both.
+  StringRef Str, Replacement;
+  if ((Attr.isArgExpr(0) && Attr.getArgAsExpr(0) &&
+       !S.checkStringLiteralArgumentAttr(Attr, 0, Str))||
+      (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) &&
+       !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)))
+    return;
+
+  D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str,
+                                      Replacement,
+                                      Attr.getAttributeSpellingListIndex()));
 }
 
 static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -6126,18 +6137,35 @@
     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);
   }
 
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -492,6 +492,7 @@
   Ident_obsoleted = nullptr;
   Ident_unavailable = nullptr;
   Ident_strict = nullptr;
+  Ident_replacement = nullptr;
 
   Ident__except = nullptr;
 
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -349,6 +349,10 @@
     ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
                                ScopeLoc, Syntax);
     return;
+  } else if (AttrKind == AttributeList::AT_Deprecated) {
+    ParseDeprecatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+                             ScopeLoc, Syntax);
+    return;
   } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
     ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
                                     ScopeName, ScopeLoc, Syntax);
@@ -1040,6 +1044,65 @@
                Syntax, StrictLoc);
 }
 
+/// \brief Parse the contents of the "deprecated" attribute.
+unsigned Parser::ParseDeprecatedAttribute(IdentifierInfo &Deprecated,
+                                      SourceLocation DeprecatedLoc,
+                                      ParsedAttributes &Attrs,
+                                      SourceLocation *EndLoc,
+                                      IdentifierInfo *ScopeName,
+                                      SourceLocation ScopeLoc,
+                                      AttributeList::Syntax Syntax) {
+  // Ignore the left paren location for now.
+  ConsumeParen();
+
+  if (!Ident_replacement)
+    Ident_replacement = PP.getIdentifierInfo("replacement");
+
+  ExprResult ReplacementExpr, MessageExpr;
+  if (Tok.isNot(tok::r_paren)) {
+    do {
+      if (Tok.is(tok::identifier)) {
+        IdentifierInfo *Keyword = Tok.getIdentifierInfo();
+        ConsumeToken();
+        if (Keyword != Ident_replacement) {
+        }
+
+        if (Tok.isNot(tok::equal)) {
+          Diag(Tok, diag::err_expected_after) << Keyword << tok::equal;
+          SkipUntil(tok::r_paren, StopAtSemi);
+          return 0;
+        }
+        ConsumeToken();
+
+        if (Tok.isNot(tok::string_literal)) {
+          Diag(Tok, diag::err_expected_string_literal)
+            << /*Source='availability attribute'*/2;
+          SkipUntil(tok::r_paren, StopAtSemi);
+          return 0;
+        }
+        ReplacementExpr = ParseStringLiteralExpression();
+      } else if (Tok.is(tok::string_literal)) {
+        MessageExpr = ParseStringLiteralExpression(true);
+      }
+    } while (TryConsumeToken(tok::comma));
+  }
+
+  SourceLocation RParen = Tok.getLocation();
+  ArgsVector ArgExprs;
+  if (!ExpectAndConsume(tok::r_paren)) {
+    ArgExprs.push_back(MessageExpr.get());
+    ArgExprs.push_back(ReplacementExpr.get());
+    SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : DeprecatedLoc;
+    Attrs.addNew(&Deprecated, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+                 ArgExprs.data(), ArgExprs.size(), Syntax);
+  }
+
+  if (EndLoc)
+    *EndLoc = RParen;
+
+  return static_cast<unsigned>(ArgExprs.size());
+}
+
 /// \brief Parse the contents of the "objc_bridge_related" attribute.
 /// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')'
 /// related_class:
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1079,6 +1079,7 @@
       .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)
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -137,6 +137,9 @@
   /// \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;
@@ -2222,6 +2225,14 @@
                                   SourceLocation ScopeLoc,
                                   AttributeList::Syntax Syntax);
 
+  unsigned ParseDeprecatedAttribute(IdentifierInfo &Deprecated,
+                                    SourceLocation DeprecatedLoc,
+                                    ParsedAttributes &Attrs,
+                                    SourceLocation *EndLoc,
+                                    IdentifierInfo *ScopeName,
+                                    SourceLocation ScopeLoc,
+                                    AttributeList::Syntax Syntax);
+
   void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
                                        SourceLocation ObjCBridgeRelatedLoc,
                                        ParsedAttributes &attrs,
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -711,7 +711,8 @@
 def Deprecated : InheritableAttr {
   let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
                    CXX11<"","deprecated", 201309>];
-  let Args = [StringArgument<"Message", 1>];
+  let Args = [StringArgument<"Message", 1>,
+              StringArgument<"Replacement", 1>];
   let Documentation = [Undocumented];
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to