objective-C: introduce __attribute((objc_requires_super)) on method

in classes. Use it to flag those method implementations which don't
contain call to 'super' if they have 'super' class and it has the method
with this attribute set. This is wip. // rdar://6386358

llvm-svn: 163434
This commit is contained in:
Fariborz Jahanian 2012-09-07 23:46:23 +00:00
parent 625fca7c5a
commit 566fff0dac
9 changed files with 94 additions and 8 deletions

View File

@ -528,6 +528,11 @@ def ObjCReturnsInnerPointer : Attr {
let Subjects = [ObjCMethod];
}
def ObjCRequiresSuper : InheritableAttr {
let Spellings = [GNU<"objc_requires_super">];
let Subjects = [ObjCMethod];
}
def ObjCRootClass : Attr {
let Spellings = [GNU<"objc_root_class">];
let Subjects = [ObjCInterface];

View File

@ -740,7 +740,7 @@ def warn_objc_property_attr_mutually_exclusive : Warning<
"property attributes '%0' and '%1' are mutually exclusive">,
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
def warn_objc_missing_super_dealloc : Warning<
"method possibly missing a [super dealloc] call">,
"method possibly missing a [super %0] call">,
InGroup<ObjCMissingSuperCalls>;
def error_dealloc_bad_result_type : Error<
"dealloc return type must be correctly specified as 'void' under ARC, "
@ -2057,6 +2057,12 @@ def warn_ns_attribute_wrong_parameter_type : Warning<
"%0 attribute only applies to %select{Objective-C object|pointer}1 "
"parameters">,
InGroup<IgnoredAttributes>;
def warn_objc_requires_super_protocol : Warning<
"%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">,
InGroup<DiagGroup<"requires-super-attribute">>;
def note_protocol_decl : Note<
"protocol is declared here">;
def err_ns_bridged_not_interface : Error<
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;

View File

@ -7832,7 +7832,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
computeNRVO(Body, getCurFunction());
}
if (getCurFunction()->ObjCShouldCallSuperDealloc) {
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc);
Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc)
<< MD->getDeclName();
getCurFunction()->ObjCShouldCallSuperDealloc = false;
}
if (getCurFunction()->ObjCShouldCallSuperFinalize) {

View File

@ -3974,6 +3974,33 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
const AttributeList &attr) {
SourceLocation loc = attr.getLoc();
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
if (!method) {
S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
<< SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
return;
}
DeclContext *DC = method->getDeclContext();
if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
<< attr.getName() << 0;
S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
return;
}
if (method->getMethodFamily() == OMF_dealloc) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
<< attr.getName() << 1;
return;
}
method->addAttr(
::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context));
}
/// Handle cf_audited_transfer and cf_unknown_transfer.
static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
if (!isa<FunctionDecl>(D)) {
@ -4281,6 +4308,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
case AttributeList::AT_ObjCRequiresSuper:
handleObjCRequiresSuperAttr(S, D, Attr); break;
case AttributeList::AT_NSBridged:
handleNSBridgedAttr(S, scope, D, Attr); break;

View File

@ -371,8 +371,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Warn on deprecated methods under -Wdeprecated-implementations,
// and prepare for warning on missing super calls.
if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) {
if (ObjCMethodDecl *IMD =
IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod()))
ObjCMethodDecl *IMD =
IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod());
if (IMD)
DiagnoseObjCImplementedDeprecations(*this,
dyn_cast<NamedDecl>(IMD),
MDecl->getLocation(), 0);
@ -385,7 +387,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
getCurFunction()->ObjCShouldCallSuperDealloc =
!(Context.getLangOpts().ObjCAutoRefCount ||
Context.getLangOpts().getGC() == LangOptions::GCOnly) &&
MDecl->getMethodFamily() == OMF_dealloc;
MDecl->getMethodFamily() == OMF_dealloc;
if (!getCurFunction()->ObjCShouldCallSuperDealloc)
getCurFunction()->ObjCShouldCallSuperDealloc =
(IMD && IMD->hasAttr<ObjCRequiresSuperAttr>());
getCurFunction()->ObjCShouldCallSuperFinalize =
Context.getLangOpts().getGC() != LangOptions::NonGC &&
MDecl->getMethodFamily() == OMF_finalize;

View File

@ -1780,6 +1780,14 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
if (Method->isInstanceMethod()) {
if (Sel.getMethodFamily() == OMF_dealloc)
getCurFunction()->ObjCShouldCallSuperDealloc = false;
else if (const ObjCMethodDecl *IMD =
Class->lookupMethod(Method->getSelector(),
Method->isInstanceMethod()))
// Must check for name of message since the method could
// be another method with objc_requires_super attribute set.
if (IMD->hasAttr<ObjCRequiresSuperAttr>() &&
Sel == IMD->getSelector())
getCurFunction()->ObjCShouldCallSuperDealloc = false;
if (Sel.getMethodFamily() == OMF_finalize)
getCurFunction()->ObjCShouldCallSuperFinalize = false;

View File

@ -0,0 +1,31 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -x objective-c++ -fobjc-arc -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://6386358
@protocol NSObject // expected-note {{protocol is declared here}}
- MyDealloc __attribute((objc_requires_super)); // expected-warning {{'objc_requires_super' attribute cannot be applied to methods in protocols}}
@end
@interface Root
- MyDealloc __attribute((objc_requires_super));
- (void)XXX __attribute((objc_requires_super));
- (void) dealloc __attribute((objc_requires_super)); // expected-warning {{'objc_requires_super' attribute cannot be applied to dealloc}}
@end
@interface Baz : Root<NSObject>
- MyDealloc;
@end
@implementation Baz
- MyDealloc {
[super MyDealloc];
return 0;
}
- (void)XXX {
[super MyDealloc];
} // expected-warning {{method possibly missing a [super 'XXX'] call}}
@end

View File

@ -41,11 +41,11 @@ __attribute__((objc_root_class))
@end
// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: warn-missing-super.m:24:1: warning: method possibly missing a [super dealloc] call
// CHECK: warn-missing-super.m:24:1: warning: method possibly missing a [super 'dealloc'] call
// CHECK: 1 warning generated.
// RUN: %clang_cc1 -fsyntax-only -fobjc-gc %s 2>&1 | FileCheck --check-prefix=CHECK-GC %s
// CHECK-GC: warn-missing-super.m:24:1: warning: method possibly missing a [super dealloc] call
// CHECK-GC: warn-missing-super.m:24:1: warning: method possibly missing a [super 'dealloc'] call
// CHECK-GC: warn-missing-super.m:26:1: warning: method possibly missing a [super finalize] call
// CHECK-GC: 2 warnings generated.

View File

@ -15,5 +15,5 @@ template<typename T> struct shared_ptr {
- (void)dealloc
{
constexpr shared_ptr<int> dummy;
} // expected-warning {{method possibly missing a [super dealloc] call}}
} // expected-warning {{method possibly missing a [super 'dealloc'] call}}
@end