Support attributes for Objective-C categories
rdar://31095315
Differential Revision: https://reviews.llvm.org/D31179
llvm-svn: 298589
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index b486e62..969fe0e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -364,8 +364,6 @@
/// 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"
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9588ab4..51504b5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7666,7 +7666,8 @@
Decl * const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
- SourceLocation EndProtoLoc);
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
Decl *ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 9f6f91c..4767473 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -278,11 +278,6 @@
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 @@
/*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);
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index b43e5b9..e50f8b2 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -258,7 +258,8 @@
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 @@
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 @@
NumProtoRefs, Context);
}
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+
CheckObjCDeclScope(CDecl);
return ActOnObjCContainerStartDefinition(CDecl);
}
@@ -1865,9 +1870,10 @@
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);
}
}
diff --git a/clang/test/SemaObjC/attr-deprecated.m b/clang/test/SemaObjC/attr-deprecated.m
index 59087bd..8a949f9 100644
--- a/clang/test/SemaObjC/attr-deprecated.m
+++ b/clang/test/SemaObjC/attr-deprecated.m
@@ -121,9 +121,15 @@
}
__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/clang/test/SemaObjC/category-attribute.m b/clang/test/SemaObjC/category-attribute.m
new file mode 100644
index 0000000..7efe3df
--- /dev/null
+++ b/clang/test/SemaObjC/category-attribute.m
@@ -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"
diff --git a/clang/test/SemaObjC/default-synthesize-3.m b/clang/test/SemaObjC/default-synthesize-3.m
index dce9eda..fe2b35f 100644
--- a/clang/test/SemaObjC/default-synthesize-3.m
+++ b/clang/test/SemaObjC/default-synthesize-3.m
@@ -33,8 +33,8 @@
- (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}}
diff --git a/clang/test/SemaObjC/warn-deprecated-implementations.m b/clang/test/SemaObjC/warn-deprecated-implementations.m
index 6e208b5..f5a010d 100644
--- a/clang/test/SemaObjC/warn-deprecated-implementations.m
+++ b/clang/test/SemaObjC/warn-deprecated-implementations.m
@@ -65,3 +65,10 @@
return (void *)0;
}
@end
+
+__attribute__((deprecated))
+@interface Test(DeprecatedCategory) // expected-note {{category declared here}}
+@end
+
+@implementation Test(DeprecatedCategory) // expected-warning {{Implementing deprecated category}}
+@end