]> granicus.if.org Git - clang/commitdiff
Support attributes for Objective-C categories
authorAlex Lorenz <arphaman@gmail.com>
Thu, 23 Mar 2017 11:44:25 +0000 (11:44 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 23 Mar 2017 11:44:25 +0000 (11:44 +0000)
rdar://31095315

Differential Revision: https://reviews.llvm.org/D31179

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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Sema/Sema.h
lib/Parse/ParseObjc.cpp
lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/attr-deprecated.m
test/SemaObjC/category-attribute.m [new file with mode: 0644]
test/SemaObjC/default-synthesize-3.m
test/SemaObjC/warn-deprecated-implementations.m

index b486e62c3506ff12110b0841d2b13e65ae2e234c..969fe0e231023b4d2a8b22a459a12c2e8563b8e9 100644 (file)
@@ -364,8 +364,6 @@ def ext_decomp_decl_empty : ExtWarn<
 /// Objective-C parser diagnostics
 def err_expected_minus_or_plus : Error<
   "method type specifier must start with '-' or '+'">;
-def err_objc_no_attributes_on_category : Error<
-  "attributes may not be specified on a category">;
 def err_objc_missing_end : Error<"missing '@end'">;
 def note_objc_container_start : Note<
   "%select{class|protocol|category|class extension|implementation"
index 9588ab4212ba125852500e8b9c6221533ec25997..51504b55e7413a1d40217680e7aa05498919f95b 100644 (file)
@@ -7666,7 +7666,8 @@ public:
                                     Decl * const *ProtoRefs,
                                     unsigned NumProtoRefs,
                                     const SourceLocation *ProtoLocs,
-                                    SourceLocation EndProtoLoc);
+                                    SourceLocation EndProtoLoc,
+                                    AttributeList *AttrList);
 
   Decl *ActOnStartClassImplementation(
                     SourceLocation AtClassImplLoc,
index 9f6f91c9fccf561c5ad07b81c94f0fdc08da0ea7..47674738d178482712bc4af6d334abab1d50abac 100644 (file)
@@ -278,11 +278,6 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
     T.consumeClose();
     if (T.getCloseLocation().isInvalid())
       return nullptr;
-
-    if (!attrs.empty()) { // categories don't support attributes.
-      Diag(nameLoc, diag::err_objc_no_attributes_on_category);
-      attrs.clear();
-    }
     
     // Next, we need to check for any protocol references.
     assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
@@ -294,16 +289,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
                                     /*consumeLastToken=*/true))
       return nullptr;
 
-    Decl *CategoryType =
-    Actions.ActOnStartCategoryInterface(AtLoc,
-                                        nameId, nameLoc,
-                                        typeParameterList,
-                                        categoryId, categoryLoc,
-                                        ProtocolRefs.data(),
-                                        ProtocolRefs.size(),
-                                        ProtocolLocs.data(),
-                                        EndProtoLoc);
-    
+    Decl *CategoryType = Actions.ActOnStartCategoryInterface(
+        AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
+        ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
+        EndProtoLoc, attrs.getList());
+
     if (Tok.is(tok::l_brace))
       ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
       
index b43e5b9e32789980e1ea0e0fca6bed674d6d0525..e50f8b206779720fd5dd826c75662bda6256d5a9 100644 (file)
@@ -258,7 +258,8 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
       S.Diag(ND->getLocation(), diag::note_method_declared_at)
         << ND->getDeclName();
     else
-      S.Diag(ND->getLocation(), diag::note_previous_decl) << "class";
+      S.Diag(ND->getLocation(), diag::note_previous_decl)
+          << (isa<ObjCCategoryDecl>(ND) ? "category" : "class");
   }
 }
 
@@ -1724,7 +1725,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
                             Decl * const *ProtoRefs,
                             unsigned NumProtoRefs,
                             const SourceLocation *ProtoLocs,
-                            SourceLocation EndProtoLoc) {
+                            SourceLocation EndProtoLoc,
+                            AttributeList *AttrList) {
   ObjCCategoryDecl *CDecl;
   ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
 
@@ -1801,6 +1803,9 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
                                             NumProtoRefs, Context); 
   }
 
+  if (AttrList)
+    ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+
   CheckObjCDeclScope(CDecl);
   return ActOnObjCContainerStartDefinition(CDecl);
 }
@@ -1865,9 +1870,10 @@ Decl *Sema::ActOnStartCategoryImplementation(
       CatIDecl->setImplementation(CDecl);
       // Warn on implementating category of deprecated class under 
       // -Wdeprecated-implementations flag.
-      DiagnoseObjCImplementedDeprecations(*this, 
-                                          dyn_cast<NamedDecl>(IDecl), 
-                                          CDecl->getLocation(), 2);
+      DiagnoseObjCImplementedDeprecations(
+          *this,
+          CatIDecl->isDeprecated() ? CatIDecl : dyn_cast<NamedDecl>(IDecl),
+          CDecl->getLocation(), 2);
     }
   }
 
index 59087bdf11547cc859595ebdf42aaccd7115b714..8a949f96e8b7ee02011006c3e0d663127f5f6ea9 100644 (file)
@@ -121,9 +121,15 @@ void test(Test2 *foo) {
 }
 
 __attribute__((deprecated))
-@interface A(Blah) // expected-error{{attributes may not be specified on a category}}
+@interface A(Blah) // no warning
+- (A*)getA;
 @end
 
+@implementation A(Blah) // Don't warn by default
+- (A*)getA {
+  return self;
+}
+@end
 
 typedef struct {
        int x;
diff --git a/test/SemaObjC/category-attribute.m b/test/SemaObjC/category-attribute.m
new file mode 100644 (file)
index 0000000..7efe3df
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+// expected-no-diagnostics
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="A")))
+@interface TestInterface
+@end
+// CHECK: ObjCInterfaceDecl {{.*}} TestInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="B")))
+@interface TestInterface ()
+@end
+// CHECK: ObjCCategoryDecl
+// CHECK-NEXT: ObjCInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr {{.*}} "Swift" "B"
+
+__attribute__ ((external_source_symbol(language= "Swift", defined_in="C")))
+@interface TestInterface (Category)
+@end
+// CHECK: ObjCCategoryDecl
+// CHECK-NEXT: ObjCInterface
+// CHECK-NEXT: ExternalSourceSymbolAttr {{.*}} "Swift" "C"
index dce9edabb90d3709db10be4770f9c22df1122b68..fe2b35f615234e4addea90636d18e157ce5d8a5c 100644 (file)
@@ -33,8 +33,8 @@ __attribute ((objc_requires_property_definitions))  // redundant, just for testi
 - (id) DeepMustSynthProperty { return 0; }
 @end
 
-__attribute ((objc_requires_property_definitions)) 
-@interface Deep(CAT)  // expected-error {{attributes may not be specified on a category}}
+__attribute ((objc_requires_property_definitions)) // expected-error {{'objc_requires_property_definitions' attribute only applies to Objective-C interfaces}}
+@interface Deep(CAT)
 @end
 
 __attribute ((objc_requires_property_definitions)) // expected-error {{'objc_requires_property_definitions' attribute only applies to Objective-C interfaces}}
index 6e208b5be79514886bca974ed560bcc025a69d3d..f5a010da3fa264132cdf2f88ba6b1b7cf6dc526f 100644 (file)
@@ -65,3 +65,10 @@ __attribute__((deprecated))
   return (void *)0;
 }
 @end
+
+__attribute__((deprecated))
+@interface Test(DeprecatedCategory) // expected-note {{category declared here}}
+@end
+
+@implementation Test(DeprecatedCategory) // expected-warning {{Implementing deprecated category}}
+@end