From: Fariborz Jahanian Date: Sat, 17 Sep 2011 19:23:40 +0000 (+0000) Subject: objc - Treat type of 'self' in class methods as root of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1d4e8e9340c9699069a33a74562e883a305f7607;p=clang objc - Treat type of 'self' in class methods as root of class of this method. // rdar://10109725 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139989 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e5afd2d1ac..6faf93fb4c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -675,8 +675,9 @@ public: GlobalMethodPool::iterator ReadMethodPool(Selector Sel); - /// Private Helper predicate to check for 'self'. - bool isSelfExpr(Expr *RExpr); + /// Private Helper predicate to check for 'self'. Upon success, it + /// returns method declaration where 'self' is referenced. + const ObjCMethodDecl *GetMethodIfSelfExpr(Expr *RExpr); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2d80ac1265..715a4bd025 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5074,6 +5074,23 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, OK)); } +/// SelfInClassMethodType - convet type of 'self' in class method +/// to pointer to root of method's class. +static void +SelfInClassMethodType(Sema &S, Expr *selfExpr, QualType &SelfType) { + if (const ObjCMethodDecl *MD = S.GetMethodIfSelfExpr(selfExpr)) + if (MD->isClassMethod()) { + const ObjCInterfaceDecl *Root = 0; + if (const ObjCInterfaceDecl * IDecl = MD->getClassInterface()) + do { + Root = IDecl; + } while ((IDecl = IDecl->getSuperClass())); + if (Root) + SelfType = S.Context.getObjCObjectPointerType( + S.Context.getObjCInterfaceType(Root)); + } +} + // checkPointerTypesForAssignment - This is a very tricky routine (despite // being closely modeled after the C99 spec:-). The odd characteristic of this // routine is it effectively iqnores the qualifiers on the top level pointee. @@ -5309,6 +5326,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Compatible; } + SelfInClassMethodType(*this, RHS.get(), RHSType); + // If the left-hand side is a reference type, then we are in a // (rare!) case where we've allowed the use of references in C, // e.g., as a parameter type in a built-in function. In this case, @@ -9564,7 +9583,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { Selector Sel = ME->getSelector(); // self = [ init...] - if (isSelfExpr(Op->getLHS()) && Sel.getNameForSlot(0).startswith("init")) + if (GetMethodIfSelfExpr(Op->getLHS()) && Sel.getNameForSlot(0).startswith("init")) diagnostic = diag::warn_condition_is_idiomatic_assignment; // = [ nextObject] diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 51b5e4fb63..5858596205 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -457,18 +457,20 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, return IsError; } -bool Sema::isSelfExpr(Expr *receiver) { +/// GetMethodIfSelfExpr - Check if receiver is an objc 'self' expression +/// and return its method declaration if so; else return 0. +const ObjCMethodDecl *Sema::GetMethodIfSelfExpr(Expr *receiver) { // 'self' is objc 'self' in an objc method only. DeclContext *DC = CurContext; while (isa(DC)) DC = DC->getParent(); if (DC && !isa(DC)) - return false; + return 0; receiver = receiver->IgnoreParenLValueCasts(); if (DeclRefExpr *DRE = dyn_cast(receiver)) if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) - return true; - return false; + return static_cast(DC); + return 0; } // Helper method for ActOnClassMethod/ActOnInstanceMethod. @@ -1272,7 +1274,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. - if (!Receiver || !isSelfExpr(Receiver)) { + if (!Receiver || !GetMethodIfSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), true); @@ -1336,7 +1338,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, return ExprError(); } - if (!Method && (!Receiver || !isSelfExpr(Receiver))) { + if (!Method && (!Receiver || !GetMethodIfSelfExpr(Receiver))) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? @@ -1507,7 +1509,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (getLangOptions().ObjCAutoRefCount) { // In ARC, annotate delegate init calls. if (Result->getMethodFamily() == OMF_init && - (SuperLoc.isValid() || isSelfExpr(Receiver))) { + (SuperLoc.isValid() || GetMethodIfSelfExpr(Receiver))) { // Only consider init calls *directly* in init implementations, // not within blocks. ObjCMethodDecl *method = dyn_cast(CurContext); diff --git a/test/SemaObjC/class-type-conversion.m b/test/SemaObjC/class-type-conversion.m new file mode 100644 index 0000000000..9d369fabf3 --- /dev/null +++ b/test/SemaObjC/class-type-conversion.m @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar://10109725 + +@interface NSObject { + Class isa; +} +- (id)addObserver:(NSObject *)observer; // expected-note 2 {{passing argument to parameter 'observer' here}} +@end + +@interface MyClass : NSObject { +} +@end + +@implementation NSObject ++ (void)initialize +{ + NSObject *obj = 0; + [obj addObserver:self]; +} + +- init +{ + NSObject *obj = 0; + [obj addObserver:self]; + return [obj addObserver:(Class)0]; // expected-warning {{incompatible pointer types sending 'Class' to parameter of type 'NSObject *'}} +} +- (id)addObserver:(NSObject *)observer { return 0; } +@end + +@implementation MyClass + ++ (void)initialize +{ + NSObject *obj = 0; + [obj addObserver:self]; +} + +- init +{ + NSObject *obj = 0; + [obj addObserver:self]; + return [obj addObserver:(Class)0]; // expected-warning {{incompatible pointer types sending 'Class' to parameter of type 'NSObject *'}} +} +@end