[objc_direct] Small updates to help with adoption.

Add fixits for messaging self in MRR or using super, as the intent is
clear, and it turns out people do that a lot more than expected.

Allow for objc_direct_members on main interfaces, it's extremely useful
for internal only classes, and proves to be quite annoying for adoption.

Add some better warnings around properties direct/non-direct clashes (it
was done for methods but properties were a miss).

Radar-Id: rdar://problem/58355212
Signed-off-by: Pierre Habouzit <phabouzit@apple.com>
This commit is contained in:
Pierre Habouzit 2020-01-30 16:48:11 -08:00
parent 6eb969b7c5
commit bebb8e2596
10 changed files with 383 additions and 28 deletions

View File

@ -1905,7 +1905,7 @@ def ObjCDirect : Attr {
def ObjCDirectMembers : Attr { def ObjCDirectMembers : Attr {
let Spellings = [Clang<"objc_direct_members">]; let Spellings = [Clang<"objc_direct_members">];
let Subjects = SubjectList<[ObjCImpl, ObjCCategory], ErrorDiag>; let Subjects = SubjectList<[ObjCImpl, ObjCInterface, ObjCCategory], ErrorDiag>;
let LangOpts = [ObjC]; let LangOpts = [ObjC];
let Documentation = [ObjCDirectMembersDocs]; let Documentation = [ObjCDirectMembersDocs];
} }

View File

@ -4118,7 +4118,7 @@ documentation for more information.
def ObjCDirectMembersDocs : Documentation { def ObjCDirectMembersDocs : Documentation {
let Category = DocCatDecl; let Category = DocCatDecl;
let Content = [{ let Content = [{
The ``objc_direct_members`` attribute can be placed on an Objective-C The ``objc_direct_members`` attribute can be placed on an Objective-C
``@interface`` or ``@implementation`` to mark that methods declared ``@interface`` or ``@implementation`` to mark that methods declared
therein should be considered direct by default. See the documentation therein should be considered direct by default. See the documentation
for ``objc_direct`` for more information about direct methods. for ``objc_direct`` for more information about direct methods.
@ -4127,9 +4127,7 @@ When ``objc_direct_members`` is placed on an ``@interface`` block, every
method in the block is considered to be declared as direct. This includes any method in the block is considered to be declared as direct. This includes any
implicit method declarations introduced by property declarations. If the method implicit method declarations introduced by property declarations. If the method
redeclares a non-direct method, the declaration is ill-formed, exactly as if the redeclares a non-direct method, the declaration is ill-formed, exactly as if the
method was annotated with the ``objc_direct`` attribute. ``objc_direct_members`` method was annotated with the ``objc_direct`` attribute.
cannot be placed on the primary interface of a class, only on category or class
extension interfaces.
When ``objc_direct_members`` is placed on an ``@implementation`` block, When ``objc_direct_members`` is placed on an ``@implementation`` block,
methods defined in the block are considered to be declared as direct unless methods defined in the block are considered to be declared as direct unless

View File

@ -1002,8 +1002,8 @@ def err_objc_direct_on_protocol : Error<
"'objc_direct' attribute cannot be applied to %select{methods|properties}0 " "'objc_direct' attribute cannot be applied to %select{methods|properties}0 "
"declared in an Objective-C protocol">; "declared in an Objective-C protocol">;
def err_objc_direct_duplicate_decl : Error< def err_objc_direct_duplicate_decl : Error<
"%select{|direct }0method declaration conflicts " "%select{|direct }0%select{method|property}1 declaration conflicts "
"with previous %select{|direct }1declaration of method %2">; "with previous %select{|direct }2declaration of method %3">;
def err_objc_direct_impl_decl_mismatch : Error< def err_objc_direct_impl_decl_mismatch : Error<
"direct method was declared in %select{the primary interface|an extension|a category}0 " "direct method was declared in %select{the primary interface|an extension|a category}0 "
"but is implemented in %select{the primary interface|a category|a different category}1">; "but is implemented in %select{the primary interface|a category|a different category}1">;

View File

@ -4859,8 +4859,8 @@ Decl *Sema::ActOnMethodDeclaration(
} else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) {
Diag(ObjCMethod->getLocation(), Diag(ObjCMethod->getLocation(),
diag::err_objc_direct_duplicate_decl) diag::err_objc_direct_duplicate_decl)
<< ObjCMethod->isDirectMethod() << IMD->isDirectMethod() << ObjCMethod->isDirectMethod() << /* method */ 0
<< ObjCMethod->getDeclName(); << IMD->isDirectMethod() << ObjCMethod->getDeclName();
Diag(IMD->getLocation(), diag::note_previous_declaration); Diag(IMD->getLocation(), diag::note_previous_declaration);
} }
} }

View File

@ -2570,6 +2570,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
diag::err_illegal_message_expr_incomplete_type)) diag::err_illegal_message_expr_incomplete_type))
return ExprError(); return ExprError();
if (Method && Method->isDirectMethod() && SuperLoc.isValid()) {
Diag(SuperLoc, diag::err_messaging_super_with_direct_method)
<< FixItHint::CreateReplacement(
SuperLoc, getLangOpts().ObjCAutoRefCount
? "self"
: Method->getClassInterface()->getName());
Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName();
}
// Warn about explicit call of +initialize on its own class. But not on 'super'. // Warn about explicit call of +initialize on its own class. But not on 'super'.
if (Method && Method->getMethodFamily() == OMF_initialize) { if (Method && Method->getMethodFamily() == OMF_initialize) {
if (!SuperLoc.isValid()) { if (!SuperLoc.isValid()) {
@ -2774,9 +2784,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ReceiverType->isIntegerType())) { ReceiverType->isIntegerType())) {
// Implicitly convert integers and pointers to 'id' but emit a warning. // Implicitly convert integers and pointers to 'id' but emit a warning.
// But not in ARC. // But not in ARC.
Diag(Loc, diag::warn_bad_receiver_type) Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << RecRange;
<< ReceiverType
<< Receiver->getSourceRange();
if (ReceiverType->isPointerType()) { if (ReceiverType->isPointerType()) {
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
CK_CPointerToObjCPointerCast).get(); CK_CPointerToObjCPointerCast).get();
@ -2927,11 +2935,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// definition is found in a module that's not visible. // definition is found in a module that's not visible.
const ObjCInterfaceDecl *forwardClass = nullptr; const ObjCInterfaceDecl *forwardClass = nullptr;
if (RequireCompleteType(Loc, OCIType->getPointeeType(), if (RequireCompleteType(Loc, OCIType->getPointeeType(),
getLangOpts().ObjCAutoRefCount getLangOpts().ObjCAutoRefCount
? diag::err_arc_receiver_forward_instance ? diag::err_arc_receiver_forward_instance
: diag::warn_receiver_forward_instance, : diag::warn_receiver_forward_instance,
Receiver? Receiver->getSourceRange() RecRange)) {
: SourceRange(SuperLoc))) {
if (getLangOpts().ObjCAutoRefCount) if (getLangOpts().ObjCAutoRefCount)
return ExprError(); return ExprError();
@ -2993,8 +3000,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError(); return ExprError();
} else { } else {
// Reject other random receiver types (e.g. structs). // Reject other random receiver types (e.g. structs).
Diag(Loc, diag::err_bad_receiver_type) Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << RecRange;
<< ReceiverType << Receiver->getSourceRange();
return ExprError(); return ExprError();
} }
} }
@ -3017,14 +3023,27 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// is what we think it is, so we reject it. // is what we think it is, so we reject it.
if (ReceiverType->isObjCClassType() && !isImplicit && if (ReceiverType->isObjCClassType() && !isImplicit &&
!(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) { !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) {
Diag(Receiver->getExprLoc(), DiagnosticBuilder Builder = Diag(
diag::err_messaging_class_with_direct_method); Receiver->getExprLoc(), diag::err_messaging_class_with_direct_method);
if (Receiver->isObjCSelfExpr()) {
Builder.AddFixItHint(FixItHint::CreateReplacement(
RecRange, Method->getClassInterface()->getName()));
}
Builder.~DiagnosticBuilder();
Diag(Method->getLocation(), diag::note_direct_method_declared_at) Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName(); << Method->getDeclName();
} }
if (SuperLoc.isValid()) { if (SuperLoc.isValid()) {
Diag(SuperLoc, diag::err_messaging_super_with_direct_method); DiagnosticBuilder Builder =
Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
if (ReceiverType->isObjCClassType()) {
Builder.AddFixItHint(FixItHint::CreateReplacement(
SuperLoc, Method->getClassInterface()->getName()));
} else {
Builder.AddFixItHint(FixItHint::CreateReplacement(SuperLoc, "self"));
}
Builder.~DiagnosticBuilder();
Diag(Method->getLocation(), diag::note_direct_method_declared_at) Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName(); << Method->getDeclName();
} }

View File

@ -2421,6 +2421,40 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
DiagnosePropertyAccessorMismatch(property, GetterMethod, DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation()); property->getLocation());
// synthesizing accessors must not result in a direct method that is not
// monomorphic
if (!GetterMethod) {
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(
property->getGetterName(), !IsClassProperty, true, false, CatDecl);
if (ExistingGetter) {
if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {
Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
<< property->isDirectProperty() << 1 /* property */
<< ExistingGetter->isDirectMethod()
<< ExistingGetter->getDeclName();
Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);
}
}
}
}
if (!property->isReadOnly() && !SetterMethod) {
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(
property->getSetterName(), !IsClassProperty, true, false, CatDecl);
if (ExistingSetter) {
if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {
Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
<< property->isDirectProperty() << 1 /* property */
<< ExistingSetter->isDirectMethod()
<< ExistingSetter->getDeclName();
Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);
}
}
}
}
if (!property->isReadOnly() && SetterMethod) { if (!property->isReadOnly() && SetterMethod) {
if (Context.getCanonicalType(SetterMethod->getReturnType()) != if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
Context.VoidTy) Context.VoidTy)

View File

@ -0,0 +1,30 @@
// Objective-C recovery
// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck -check-prefix=CHECK-MRR %s
// RUN: not %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck -check-prefix=CHECK-ARC %s
__attribute__((objc_root_class))
@interface Root
+ (void)classDirectMethod __attribute__((objc_direct));
+ (void)classDirectMethod2 __attribute__((objc_direct));
- (void)instanceDirectMethod __attribute__((objc_direct));
@end
@interface A : Root
@end
@implementation A
+ (void)classMethod {
// CHECK-MRR: {18:4-18:8}:"Root"
[self classDirectMethod];
}
+ (void)classMethod2 {
// CHECK-MRR: {23:4-23:9}:"Root"
// CHECK-ARC: {23:4-23:9}:"self"
[super classDirectMethod2];
}
- (void)instanceMethod {
// CHECK-MRR: {28:4-28:9}:"self"
// CHECK-ARC: {28:4-28:9}:"self"
[super instanceDirectMethod];
}
@end

View File

@ -107,7 +107,7 @@
// CHECK-NEXT: ObjCClassStub (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCClassStub (SubjectMatchRule_objc_interface)
// CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method)
// CHECK-NEXT: ObjCDirect (SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCDirect (SubjectMatchRule_objc_method)
// CHECK-NEXT: ObjCDirectMembers (SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_category) // CHECK-NEXT: ObjCDirectMembers (SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_category)
// CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface)
// CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol) // CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
// CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)

View File

@ -0,0 +1,273 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wselector-type-mismatch %s
__attribute__((objc_root_class))
@interface Inteface_Implementation
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal;
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct;
@end
@implementation Inteface_Implementation
- (int)normal_normal {
return 42;
}
- (int)direct_normal {
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method implementation was previously declared not direct}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) {
return 42;
}
@end
__attribute__((objc_root_class))
@interface Inteface_Extension
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal;
@property(nonatomic, readonly) int normal_direct;
@property(nonatomic, readonly, direct) int direct_direct;
@end
@interface Inteface_Extension ()
@property(nonatomic, readwrite) int normal_normal;
@property(nonatomic, readwrite) int direct_normal;
@property(nonatomic, readwrite, direct) int normal_direct;
@property(nonatomic, readwrite, direct) int direct_direct;
@end
@implementation Inteface_Extension
@end
__attribute__((objc_root_class))
@interface Extension_Implementation
@end
@interface Extension_Implementation ()
@property(nonatomic, readwrite) int normal_normal;
@property(nonatomic, readwrite, direct) int direct_normal;
@property(nonatomic, readwrite) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readwrite, direct) int direct_direct;
@end
@implementation Extension_Implementation
- (int)normal_normal {
return 42;
}
- (int)direct_normal {
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method implementation was previously declared not direct}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) {
return 42;
}
@end
__attribute__((objc_root_class))
@interface Inteface_Category
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@interface Inteface_Category (SomeCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly) int direct_normal; // expected-error {{property declaration conflicts with previous direct declaration of method 'direct_normal'}}
@property(nonatomic, readonly, direct) int normal_direct; // expected-error {{direct property declaration conflicts with previous declaration of method 'normal_direct'}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-error {{direct property declaration conflicts with previous direct declaration of method 'direct_direct'}}
@end
@implementation Inteface_Category
@end
__attribute__((objc_root_class))
@interface Extension_Category
@end
@interface Extension_Category ()
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@interface Extension_Category (SomeCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly) int direct_normal; // expected-error {{property declaration conflicts with previous direct declaration of method 'direct_normal'}}
@property(nonatomic, readonly, direct) int normal_direct; // expected-error {{direct property declaration conflicts with previous declaration of method 'normal_direct'}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-error {{direct property declaration conflicts with previous direct declaration of method 'direct_direct'}}
@end
@implementation Extension_Category
@end
__attribute__((objc_root_class))
@interface Implementation_Category
@end
@interface Implementation_Category (SomeCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@implementation Implementation_Category
- (int)normal_normal {
return 42;
}
- (int)direct_normal { // expected-error {{direct method was declared in a category but is implemented in the primary interface}}
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in a category but is implemented in the primary interface}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in a category but is implemented in the primary interface}}
return 42;
}
@end
__attribute__((objc_root_class))
@interface Category_Category
@end
@interface Category_Category (SomeCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@interface Category_Category (SomeOtherCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly) int direct_normal; // expected-error {{property declaration conflicts with previous direct declaration of method 'direct_normal'}}
@property(nonatomic, readonly, direct) int normal_direct; // expected-error {{direct property declaration conflicts with previous declaration of method 'normal_direct'}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-error {{direct property declaration conflicts with previous direct declaration of method 'direct_direct'}}
@end
@implementation Category_Category
@end
__attribute__((objc_root_class))
@interface Category_CategoryImplementation
@end
@interface Category_CategoryImplementation (SomeCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal;
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct;
@end
@implementation Category_CategoryImplementation (SomeCategory)
- (int)normal_normal {
return 42;
}
- (int)direct_normal {
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method implementation was previously declared not direct}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) {
return 42;
}
@end
@implementation Category_CategoryImplementation
@end
__attribute__((objc_root_class))
@interface Interface_CategoryImplementation
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@interface Interface_CategoryImplementation (SomeCategory)
@end
@implementation Interface_CategoryImplementation (SomeCategory)
- (int)normal_normal {
return 42;
}
- (int)direct_normal { // expected-error {{direct method was declared in the primary interface but is implemented in a category}}
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in the primary interface but is implemented in a category}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in the primary interface but is implemented in a category}}
return 42;
}
@end
@implementation Interface_CategoryImplementation
@end
__attribute__((objc_root_class))
@interface Extension_CategoryImplementation
@end
@interface Extension_CategoryImplementation ()
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@interface Extension_CategoryImplementation (SomeCategory)
@end
@implementation Extension_CategoryImplementation (SomeCategory)
- (int)normal_normal {
return 42;
}
- (int)direct_normal { // expected-error {{direct method was declared in an extension but is implemented in a different category}}
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in an extension but is implemented in a different category}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in an extension but is implemented in a different category}}
return 42;
}
@end
__attribute__((objc_root_class))
@interface OtherCategory_CategoryImplementation
@end
@interface OtherCategory_CategoryImplementation (SomeCategory)
@end
@interface OtherCategory_CategoryImplementation (SomeOtherCategory)
@property(nonatomic, readonly) int normal_normal;
@property(nonatomic, readonly, direct) int direct_normal; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly) int normal_direct; // expected-note {{previous declaration is here}}
@property(nonatomic, readonly, direct) int direct_direct; // expected-note {{previous declaration is here}}
@end
@implementation OtherCategory_CategoryImplementation (SomeCategory)
- (int)normal_normal {
return 42;
}
- (int)direct_normal { // expected-error {{direct method was declared in a category but is implemented in a different category}}
return 42;
}
- (int)normal_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in a category but is implemented in a different category}}
return 42;
}
- (int)direct_direct __attribute__((objc_direct)) { // expected-error {{direct method was declared in a category but is implemented in a different category}}
return 42;
}
@end
@implementation OtherCategory_CategoryImplementation
@end

View File

@ -18,6 +18,7 @@ __attribute__((objc_root_class))
+ (void)classRootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}}; + (void)classRootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}};
- (void)otherRootDirect __attribute__((objc_direct)); // expected-note {{direct method 'otherRootDirect' declared here}} - (void)otherRootDirect __attribute__((objc_direct)); // expected-note {{direct method 'otherRootDirect' declared here}}
+ (void)otherClassRootDirect __attribute__((objc_direct)); // expected-note {{direct method 'otherClassRootDirect' declared here}} + (void)otherClassRootDirect __attribute__((objc_direct)); // expected-note {{direct method 'otherClassRootDirect' declared here}}
+ (void)otherOtherClassRootDirect __attribute__((objc_direct)); // expected-note {{direct method 'otherOtherClassRootDirect' declared here}}
- (void)notDirectInIface; // expected-note {{previous declaration is here}} - (void)notDirectInIface; // expected-note {{previous declaration is here}}
+ (void)classNotDirectInIface; // expected-note {{previous declaration is here}} + (void)classNotDirectInIface; // expected-note {{previous declaration is here}}
@end @end
@ -48,11 +49,6 @@ __attribute__((objc_direct_members))
+ (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note {{previous declaration is here}} + (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note {{previous declaration is here}}
@end @end
__attribute__((objc_root_class, objc_direct_members)) // expected-error {{'objc_direct_members' attribute only applies to Objective-C implementation declarations and Objective-C containers}}
@interface SubDirectFail : Root
- (instancetype)init;
@end
@interface Sub : Root <Proto> @interface Sub : Root <Proto>
/* invalid overrides with directs */ /* invalid overrides with directs */
- (void)rootRegular __attribute__((objc_direct)); // expected-error {{methods that override superclass methods cannot be direct}} - (void)rootRegular __attribute__((objc_direct)); // expected-error {{methods that override superclass methods cannot be direct}}
@ -94,6 +90,8 @@ __attribute__((objc_direct_members))
+ (void)otherClassRootDirect { + (void)otherClassRootDirect {
[self someRootDirectMethod]; // expected-error {{messaging a Class with a method that is possibly direct}} [self someRootDirectMethod]; // expected-error {{messaging a Class with a method that is possibly direct}}
} }
+ (void)otherOtherClassRootDirect {
}
- (void)rootExtensionDirect { - (void)rootExtensionDirect {
} }
+ (void)classRootExtensionDirect { + (void)classRootExtensionDirect {
@ -135,6 +133,9 @@ __attribute__((objc_direct_members))
- (void)someValidSubMethod { - (void)someValidSubMethod {
[super otherRootDirect]; // expected-error {{messaging super with a direct method}} [super otherRootDirect]; // expected-error {{messaging super with a direct method}}
} }
+ (void)someValidSubMethod {
[super otherOtherClassRootDirect]; // expected-error {{messaging super with a direct method}}
}
@end @end
extern void callMethod(id obj, Class cls); extern void callMethod(id obj, Class cls);