]> granicus.if.org Git - clang/commitdiff
Provide an attribute, objc_method_family, to allow the inferred family
authorJohn McCall <rjmccall@apple.com>
Wed, 2 Mar 2011 11:33:24 +0000 (11:33 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 2 Mar 2011 11:33:24 +0000 (11:33 +0000)
of an Objective-C method to be overridden on a case-by-case basis.  This
is a higher-level tool than ns_returns_retained &c.;  it lets users specify
that not only does a method have different retain/release semantics, but
that it semantically acts differently than one might assume from its name.
This in turn is quite useful to static analysis.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126839 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/AttributeList.h
lib/AST/DeclObjC.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Sema/AttributeList.cpp
lib/Sema/SemaDeclAttr.cpp

index 57e5be4ae8ead07ec7c2fc609f9b087252b0ad1b..282c5082ed6511acef07bf40168184faed3f13c9 100644 (file)
@@ -369,6 +369,15 @@ def ObjCException : InheritableAttr {
   let Spellings = ["objc_exception"];
 }
 
+def ObjCMethodFamily : InheritableAttr {
+  let Spellings = ["objc_method_family"];
+  let Subjects = [ObjCMethod];
+  let Args = [EnumArgument<"Family", "FamilyKind",
+               ["none", "alloc", "copy", "init", "mutableCopy", "new"],
+               ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init",
+                "OMF_mutableCopy", "OMF_new"]>];
+}
+
 def ObjCNSObject : InheritableAttr {
   let Spellings = ["NSObject"];
 }
index 8c36f37513ebbe5d3bb75fb27ec97117f8686f09..68b244702468344f320dc689025e17b50577ed4c 100644 (file)
@@ -1028,6 +1028,7 @@ def err_format_attribute_result_not : Error<"function does not return %0">;
 def err_format_attribute_implicit_this_format_string : Error<
   "format attribute cannot specify the implicit this argument as the format "
   "string">;
+def warn_unknown_method_family : Warning<"unrecognized method family">;
 def err_attribute_invalid_size : Error<
   "vector size not an integral multiple of component size">;
 def err_attribute_zero_size : Error<"zero vector size">;
index 45ee579a02d3839a4becc88353a87766934c0265..10b859e9f9f7228c6ce66d83273daefc3dcd658d 100644 (file)
@@ -125,6 +125,7 @@ public:
     AT_nothrow,
     AT_nsobject,
     AT_objc_exception,
+    AT_objc_method_family,
     AT_cf_returns_not_retained, // Clang-specific.
     AT_cf_returns_retained,     // Clang-specific.
     AT_ns_returns_not_retained, // Clang-specific.
index 3a7c2a6e70deb5d4af51ce2722b28d1809419d42..e9d537029b1070e2ceee482fdadd912dd14c5a41 100644 (file)
@@ -403,6 +403,22 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
   if (family != InvalidObjCMethodFamily)
     return family;
 
+  // Check for an explicit attribute.
+  if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) {
+    // The unfortunate necessity of mapping between enums here is due
+    // to the attributes framework.
+    switch (attr->getFamily()) {
+    case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break;
+    case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break;
+    case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break;
+    case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break;
+    case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break;
+    case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break;
+    }
+    Family = static_cast<unsigned>(family);
+    return family;
+  }
+
   family = getSelector().getMethodFamily();
   switch (family) {
   case OMF_None: break;
index 374f85d8b83059f4ec7fe5bbcababbfca632f5f1..10abfb4b83d1f03e96defa652b4e6b9f947fa089 100644 (file)
@@ -540,6 +540,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("attribute_ns_consumed", true)
            .Case("attribute_cf_consumed", true)
            .Case("attribute_objc_ivar_unused", true)
+           .Case("attribute_objc_method_family", true)
            .Case("attribute_overloadable", true)
            .Case("attribute_unavailable_with_message", true)
            .Case("blocks", LangOpts.Blocks)
index c0a305365afc027a38fec87140b889482ecc404e..1663fd58a99791fe0a128772c09c78447f82d20d 100644 (file)
@@ -98,6 +98,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
     .Case("returns_twice", IgnoredAttribute)
     .Case("vec_type_hint", IgnoredAttribute)
     .Case("objc_exception", AT_objc_exception)
+    .Case("objc_method_family", AT_objc_method_family)
     .Case("ext_vector_type", AT_ext_vector_type)
     .Case("neon_vector_type", AT_neon_vector_type)
     .Case("neon_polyvector_type", AT_neon_polyvector_type)
index 893cf6ac26e47f3f28a6db0e4c4a816402b92784..db4bc3e4af9ca5ec543c41ba84810617d92202e8 100644 (file)
@@ -1094,6 +1094,51 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type));
 }
 
+static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr,
+                                       Sema &S) {
+  ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl);
+  if (!method) {
+    S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type)
+      << 13; // methods
+    return;
+  }
+
+  if (attr.getNumArgs() != 0 || !attr.getParameterName()) {
+    if (!attr.getParameterName() && attr.getNumArgs() == 1) {
+      S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+        << "objc_method_family" << 1;
+    } else {
+      S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+    }
+    attr.setInvalid();
+    return;
+  }
+
+  llvm::StringRef param = attr.getParameterName()->getName();
+  ObjCMethodFamilyAttr::FamilyKind family;
+  if (param == "none")
+    family = ObjCMethodFamilyAttr::OMF_None;
+  else if (param == "alloc")
+    family = ObjCMethodFamilyAttr::OMF_alloc;
+  else if (param == "copy")
+    family = ObjCMethodFamilyAttr::OMF_copy;
+  else if (param == "init")
+    family = ObjCMethodFamilyAttr::OMF_init;
+  else if (param == "mutableCopy")
+    family = ObjCMethodFamilyAttr::OMF_mutableCopy;
+  else if (param == "new")
+    family = ObjCMethodFamilyAttr::OMF_new;
+  else {
+    // Just warn and ignore it.  This is future-proof against new
+    // families being used in system headers.
+    S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family);
+    return;
+  }
+
+  decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
+                                                     S.Context, family));
+}
+
 static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
                                     Sema &S) {
   if (Attr.getNumArgs() != 0) {
@@ -2752,6 +2797,9 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D,
   case AttributeList::AT_objc_exception:
     HandleObjCExceptionAttr(D, Attr, S);
     break;
+  case AttributeList::AT_objc_method_family:
+    HandleObjCMethodFamilyAttr(D, Attr, S);
+    break;
   case AttributeList::AT_nsobject:    HandleObjCNSObject    (D, Attr, S); break;
   case AttributeList::AT_blocks:      HandleBlocksAttr      (D, Attr, S); break;
   case AttributeList::AT_sentinel:    HandleSentinelAttr    (D, Attr, S); break;