From a3a37ae8c8b862e087f3795edd856377b60971fd Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 24 Jun 2008 15:50:53 +0000 Subject: [PATCH] ObjCMessageExpr objects that represent messages to class methods now can contain the ObjCInterfaceDecl* of the target class if it was available when the ObjCMessageExpr object was constructed. The original interfaces of the class has been preserved (requiring no functionality changes from clients), but now a "getClasSInfo" method returns both the ObjCInterfaceDecl* and IdentifierInfo* of the target class. llvm-svn: 52676 --- clang/include/clang/AST/ExprObjC.h | 35 +++++++++++++++++++++-------- clang/lib/AST/Expr.cpp | 36 +++++++++++++++++++++++++++++- clang/lib/Sema/SemaExprObjC.cpp | 12 ++++++++-- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 03c96f1757f2..d588a1c35ae0 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -227,6 +227,9 @@ public: class ObjCMessageExpr : public Expr { enum { RECEIVER=0, ARGS_START=1 }; + // Bit-swizziling flags. + enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 }; + Stmt **SubExprs; unsigned NumArgs; @@ -249,12 +252,21 @@ class ObjCMessageExpr : public Expr { MethodProto(NULL), LBracloc(LBrac), RBracloc(RBrac) {} public: - // constructor for class messages. - // FIXME: clsName should be typed to ObjCInterfaceType + /// This constructor is used to represent class messages where the + /// ObjCInterfaceDecl* of the receiver is not known. ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned NumArgs); + + /// This constructor is used to represent class messages where the + /// ObjCInterfaceDecl* of the receiver is known. + // FIXME: clsName should be typed to ObjCInterfaceType + ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + QualType retType, ObjCMethodDecl *methDecl, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned NumArgs); + // constructor for instance messages. ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *methDecl, @@ -270,7 +282,7 @@ public: /// class methods, use getClassName. Expr *getReceiver() { uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - return x & 0x1 ? NULL : (Expr*) x; + return (x & Flags) == IsInstMeth ? (Expr*) x : 0; } const Expr *getReceiver() const { return const_cast(this)->getReceiver(); @@ -280,16 +292,21 @@ public: const ObjCMethodDecl *getMethodDecl() const { return MethodProto; } ObjCMethodDecl *getMethodDecl() { return MethodProto; } + + typedef std::pair ClassInfo; + + /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl* + /// and IdentifierInfo* of the invoked class. Both can be NULL if this + /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none + /// was available when this ObjCMessageExpr object was constructed. + ClassInfo getClassInfo() const; /// getClassName - For class methods, this returns the invoked class, /// and returns NULL otherwise. For instance methods, use getReceiver. - IdentifierInfo *getClassName() { - uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - return x & 0x1 ? (IdentifierInfo*) (x & ~0x1) : NULL; - } - const IdentifierInfo *getClassName() const { - return const_cast(this)->getClassName(); + IdentifierInfo *getClassName() const { + return getClassInfo().second; } + /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return NumArgs; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e18c27c3b5c6..cdbafde0c084 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1131,7 +1131,7 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | 0x1); + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); @@ -1140,6 +1140,40 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, RBracloc = RBrac; } +// constructor for class messages. +ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) +: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +MethodProto(mproto) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { + uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; + switch (x & Flags) { + default: + assert(false && "Invalid ObjCMessageExpr."); + case IsInstMeth: + return ClassInfo(0, 0); + case IsClsMethDeclUnknown: + return ClassInfo(0, (IdentifierInfo*) (x & ~Flags)); + case IsClsMethDeclKnown: { + ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); + return ClassInfo(D, D->getIdentifier()); + } + } +} + bool ChooseExpr::isConditionTrue(ASTContext &C) const { llvm::APSInt CondVal(32); bool IsConst = getCond()->isIntegerConstantExpr(CondVal, C); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 1aed69ec2c56..c33efbd743f6 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -202,8 +202,16 @@ Sema::ExprResult Sema::ActOnClassMessage( return true; } } - return new ObjCMessageExpr(receiverName, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); + + // If we have the ObjCInterfaceDecl* for the class that is receiving + // the message, use that to construct the ObjCMessageExpr. Otherwise + // pass on the IdentifierInfo* for the class. + if (ClassDecl) + return new ObjCMessageExpr(ClassDecl, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); + else + return new ObjCMessageExpr(receiverName, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); } // ActOnInstanceMessage - used for both unary and keyword messages.