From: Steve Naroff Date: Fri, 7 Dec 2007 03:50:46 +0000 (+0000) Subject: Rewrite 'super' within a class method. This required some minor tweaks to the front... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9bcb5fc1fd48c1f40c6a3b5a59130ebc313b4957;p=clang Rewrite 'super' within a class method. This required some minor tweaks to the front-end. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44673 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/RewriteTest.cpp b/Driver/RewriteTest.cpp index 9b19cfb450..6b9c611c71 100644 --- a/Driver/RewriteTest.cpp +++ b/Driver/RewriteTest.cpp @@ -47,6 +47,7 @@ namespace { FunctionDecl *MsgSendSuperStretFunctionDecl; FunctionDecl *MsgSendFpretFunctionDecl; FunctionDecl *GetClassFunctionDecl; + FunctionDecl *GetMetaClassFunctionDecl; FunctionDecl *SelGetUidFunctionDecl; FunctionDecl *CFStringFunctionDecl; @@ -69,6 +70,7 @@ namespace { MsgSendSuperStretFunctionDecl = 0; MsgSendFpretFunctionDecl = 0; GetClassFunctionDecl = 0; + GetMetaClassFunctionDecl = 0; SelGetUidFunctionDecl = 0; CFStringFunctionDecl = 0; ConstantStringClassReference = 0; @@ -103,6 +105,8 @@ namespace { "(struct objc_object *, struct objc_selector *, ...);\n" "extern struct objc_object *objc_getClass" "(const char *);\n" + "extern struct objc_object *objc_getMetaClass" + "(const char *);\n" "extern void objc_exception_throw(struct objc_object *);\n" "extern void objc_exception_try_enter(void *);\n" "extern void objc_exception_try_exit(void *);\n" @@ -160,6 +164,7 @@ namespace { void SynthMsgSendFpretFunctionDecl(); void SynthMsgSendSuperStretFunctionDecl(); void SynthGetClassFunctionDecl(); + void SynthGetMetaClassFunctionDecl(); void SynthCFStringFunctionDecl(); void SynthSelGetUidFunctionDecl(); @@ -1155,6 +1160,20 @@ void RewriteTest::SynthGetClassFunctionDecl() { FunctionDecl::Extern, false, 0); } +// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); +void RewriteTest::SynthGetMetaClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); + llvm::SmallVector ArgTys; + ArgTys.push_back(Context->getPointerType( + Context->CharTy.getQualifiedType(QualType::Const))); + QualType getClassType = Context->getFunctionType(Context->getObjcIdType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/); + GetMetaClassFunctionDecl = new FunctionDecl(SourceLocation(), + getClassIdent, getClassType, + FunctionDecl::Extern, false, 0); +} + // SynthCFStringFunctionDecl - id __builtin___CFStringMakeConstantString(const char *name); void RewriteTest::SynthCFStringFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("__builtin___CFStringMakeConstantString"); @@ -1226,7 +1245,8 @@ Stmt *RewriteTest::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { } ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) { - if (CurMethodDecl) { // check if we are sending a message to 'super' + // check if we are sending a message to 'super' + if (CurMethodDecl && CurMethodDecl->isInstance()) { if (CastExpr *CE = dyn_cast(recExpr)) { if (DeclRefExpr *DRE = dyn_cast(CE->getSubExpr())) { if (ParmVarDecl *PVD = dyn_cast(DRE->getDecl())) { @@ -1242,7 +1262,7 @@ ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) { } } } - } + } } return 0; } @@ -1284,6 +1304,8 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) { SynthMsgSendFpretFunctionDecl(); if (!GetClassFunctionDecl) SynthGetClassFunctionDecl(); + if (!GetMetaClassFunctionDecl) + SynthGetMetaClassFunctionDecl(); // default to objc_msgSend(). FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; @@ -1304,19 +1326,62 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) { // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend(). if (clsName) { // class message. - llvm::SmallVector ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(new StringLiteral(clsName->getName(), - clsName->getLength(), - false, argType, SourceLocation(), - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], ClsExprs.size()); - MsgExprs.push_back(Cls); + if (!strcmp(clsName->getName(), "super")) { + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + + ObjcInterfaceDecl *SuperDecl = + CurMethodDecl->getClassInterface()->getSuperClass(); + + llvm::SmallVector InitExprs; + + // set the receiver to self, the first argument to all methods. + InitExprs.push_back(new DeclRefExpr(CurMethodDecl->getSelfDecl(), + Context->getObjcIdType(), + SourceLocation())); + llvm::SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), + SuperDecl->getIdentifier()->getLength(), + false, argType, SourceLocation(), + SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size()); + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( + new CastExpr(Context->getObjcIdType(), + Cls, SourceLocation())); // set 'super class', using objc_getClass(). + // struct objc_super + QualType superType = getSuperStructType(); + // (struct objc_super) { } + InitListExpr *ILE = new InitListExpr(SourceLocation(), + &InitExprs[0], InitExprs.size(), + SourceLocation()); + CompoundLiteralExpr *SuperRep = new CompoundLiteralExpr(superType, ILE); + // struct objc_super * + Expr *Unop = new UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + MsgExprs.push_back(Unop); + } else { + llvm::SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(new StringLiteral(clsName->getName(), + clsName->getLength(), + false, argType, SourceLocation(), + SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size()); + MsgExprs.push_back(Cls); + } } else { // instance message. Expr *recExpr = Exp->getReceiver(); - if (ObjcInterfaceDecl *ID = isSuperReceiver(recExpr)) { + if (ObjcInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) { MsgSendFlavor = MsgSendSuperFunctionDecl; if (MsgSendStretFlavor) MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; @@ -1330,8 +1395,8 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(new StringLiteral(ID->getIdentifier()->getName(), - ID->getIdentifier()->getLength(), + ClsExprs.push_back(new StringLiteral(SuperDecl->getIdentifier()->getName(), + SuperDecl->getIdentifier()->getLength(), false, argType, SourceLocation(), SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 70c4772a23..3d0add8e27 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -977,7 +977,7 @@ void Sema::ObjcActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { PI.TypeInfo = selfTy.getAsOpaquePtr(); } else PI.TypeInfo = Context.getObjcIdType().getAsOpaquePtr(); - ActOnParamDeclarator(PI, FnBodyScope); + CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); PI.Ident = &Context.Idents.get("_cmd"); PI.TypeInfo = Context.getObjcSelType().getAsOpaquePtr(); diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 9d3e9eb970..56b792eaf5 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -2140,23 +2140,24 @@ Sema::ExprResult Sema::ActOnClassMessage( if (!strcmp(receiverName->getName(), "super") && CurMethodDecl) { ClassDecl = CurMethodDecl->getClassInterface()->getSuperClass(); if (ClassDecl && CurMethodDecl->isInstance()) { + // Synthesize a cast to the super class. This hack allows us to loosely + // represent super without creating a special expression node. IdentifierInfo &II = Context.Idents.get("self"); - ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, - false); + ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, false); QualType superTy = Context.getObjcInterfaceType(ClassDecl); superTy = Context.getPointerType(superTy); ReceiverExpr = ActOnCastExpr(SourceLocation(), superTy.getAsOpaquePtr(), SourceLocation(), ReceiverExpr.Val); - + // We are really in an instance method, redirect. return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac, Args, NumArgs); } - // class method - if (ClassDecl) - receiverName = ClassDecl->getIdentifier(); - } - else + // We are sending a message to 'super' within a class method. Do nothing, + // the receiver will pass through as 'super' (how convenient:-). + } else ClassDecl = getObjCInterfaceDecl(receiverName); + + // FIXME: can ClassDecl ever be null? ObjcMethodDecl *Method = ClassDecl->lookupClassMethod(Sel); QualType returnType; diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index fb0a8b4a36..5432a4c2a4 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -650,9 +650,12 @@ private: /// List of attributes for this method declaration. AttributeList *MethodAttrs; - Stmt *Body; // Null if a prototype. - SourceLocation EndLoc; // the location of the ';' or '{'. + + // The following are only used for method definitions, null otherwise. + // FIXME: space savings opportunity, consider a sub-class. + Stmt *Body; + ParmVarDecl *SelfDecl; public: ObjcMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, @@ -668,7 +671,7 @@ public: MethodContext(static_cast(contextDecl)), SelName(SelInfo), MethodDeclType(T), ParamInfo(paramInfo), NumMethodParams(numParams), - MethodAttrs(M), EndLoc(endLoc) {} + MethodAttrs(M), EndLoc(endLoc), Body(0), SelfDecl(0) {} virtual ~ObjcMethodDecl(); ObjcDeclQualifier getObjcDeclQualifier() const { return objcDeclQualifier; } @@ -718,6 +721,9 @@ public: } Stmt *const getBody() const { return Body; } void setBody(Stmt *B) { Body = B; } + + ParmVarDecl *const getSelfDecl() const { return SelfDecl; } + void setSelfDecl(ParmVarDecl *PVD) { SelfDecl = PVD; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == ObjcMethod; }