From 9a1291942127751d4621f930d048fe22496e9681 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 21 Apr 2010 00:45:42 +0000 Subject: Overhaul the AST representation of Objective-C message send expressions, to improve source-location information, clarify the actual receiver of the message, and pave the way for proper C++ support. The ObjCMessageExpr node represents four different kinds of message sends in a single AST node: 1) Send to a object instance described by an expression (e.g., [x method:5]) 2) Send to a class described by the class name (e.g., [NSString method:5]) 3) Send to a superclass class (e.g, [super method:5] in class method) 4) Send to a superclass instance (e.g., [super method:5] in instance method) Previously these four cases where tangled together. Now, they have more distinct representations. Specific changes: 1) Unchanged; the object instance is represented by an Expr*. 2) Previously stored the ObjCInterfaceDecl* referring to the class receiving the message. Now stores a TypeSourceInfo* so that we know how the class was spelled. This both maintains typedef information and opens the door for more complicated C++ types (e.g., dependent types). There was an alternative, unused representation of these sends by naming the class via an IdentifierInfo *. In practice, we either had an ObjCInterfaceDecl *, from which we would get the IdentifierInfo *, or we fell into the case below... 3) Previously represented by a class message whose IdentifierInfo * referred to "super". Sema and CodeGen would use isStr("super") to determine if they had a send to super. Now represented as a "class super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). 4) Previously represented by an instance message whose receiver is a an ObjCSuperExpr, which Sema and CodeGen would check for via isa(). Now represented as an "instance super" send, where we have both the location of the "super" keyword and the ObjCInterfaceDecl* of the superclass we're targetting (statically). Note that ObjCSuperExpr only has one remaining use in the AST, which is for "super.prop" references. The new representation of ObjCMessageExpr is 2 pointers smaller than the old one, since it combines more storage. It also eliminates a leak when we loaded message-send expressions from a precompiled header. The representation also feels much cleaner to me; comments welcome! This patch attempts to maintain the same semantics we previously had with Objective-C message sends. In several places, there are massive changes that boil down to simply replacing a nested-if structure such as: if (message has a receiver expression) { // instance message if (isa(...)) { // send to super } else { // send to an object } } else { // class message if (name->isStr("super")) { // class send to super } else { // send to class } } with a switch switch (E->getReceiverKind()) { case ObjCMessageExpr::SuperInstance: ... case ObjCMessageExpr::Instance: ... case ObjCMessageExpr::SuperClass: ... case ObjCMessageExpr::Class:... } There are quite a few places (particularly in the checkers) where send-to-super is effectively ignored. I've placed FIXMEs in most of them, and attempted to address send-to-super in a reasonable way. This could use some review. llvm-svn: 101972 --- clang/lib/Index/Analyzer.cpp | 79 +++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 23 deletions(-) (limited to 'clang/lib/Index/Analyzer.cpp') diff --git a/clang/lib/Index/Analyzer.cpp b/clang/lib/Index/Analyzer.cpp index 7b414f2a9fb..1354fe6be0d 100644 --- a/clang/lib/Index/Analyzer.cpp +++ b/clang/lib/Index/Analyzer.cpp @@ -153,9 +153,10 @@ public: ObjCInterfaceDecl *MsgD = 0; ObjCMessageExpr *Msg = cast(ASTLoc.AsStmt()); - if (Msg->getReceiver()) { + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Instance: { const ObjCObjectPointerType *OPT = - Msg->getReceiver()->getType()->getAsObjCInterfacePointerType(); + Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType(); // Can be anything! Accept it as a possibility.. if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) @@ -171,15 +172,34 @@ public: // Should be an instance method. if (!IsInstanceMethod) return false; + break; + } - } else { + case ObjCMessageExpr::Class: { + // Expecting class method. + if (IsInstanceMethod) + return false; + + MsgD = Msg->getClassReceiver()->getAs()->getDecl(); + break; + } + + case ObjCMessageExpr::SuperClass: // Expecting class method. if (IsInstanceMethod) return false; - MsgD = Msg->getClassInfo().Decl; - // FIXME: Case when we only have an identifier. - assert(MsgD && "Identifier only"); + MsgD = Msg->getSuperType()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::SuperInstance: + // Expecting instance method. + if (!IsInstanceMethod) + return false; + + MsgD = Msg->getSuperType()->getAs() + ->getInterfaceDecl(); + break; } assert(MsgD); @@ -248,31 +268,44 @@ public: ObjCInterfaceDecl *MsgD = 0; while (true) { - if (Msg->getReceiver() == 0) { - CanBeClassMethod = true; - MsgD = Msg->getClassInfo().Decl; - // FIXME: Case when we only have an identifier. - assert(MsgD && "Identifier only"); - break; - } + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Instance: { + const ObjCObjectPointerType *OPT = + Msg->getInstanceReceiver()->getType() + ->getAsObjCInterfacePointerType(); + + if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) { + CanBeInstanceMethod = CanBeClassMethod = true; + break; + } - const ObjCObjectPointerType *OPT = - Msg->getReceiver()->getType()->getAsObjCInterfacePointerType(); + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + CanBeClassMethod = true; + break; + } - if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) { - CanBeInstanceMethod = CanBeClassMethod = true; + MsgD = OPT->getInterfaceDecl(); + assert(MsgD); + CanBeInstanceMethod = true; break; } + + case ObjCMessageExpr::Class: + CanBeClassMethod = true; + MsgD = Msg->getClassReceiver()->getAs()->getDecl(); + break; - if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + case ObjCMessageExpr::SuperClass: CanBeClassMethod = true; + MsgD = Msg->getSuperType()->getAs()->getDecl(); break; - } - MsgD = OPT->getInterfaceDecl(); - assert(MsgD); - CanBeInstanceMethod = true; - break; + case ObjCMessageExpr::SuperInstance: + CanBeInstanceMethod = true; + MsgD = Msg->getSuperType()->getAs() + ->getInterfaceDecl(); + break; + } } assert(CanBeInstanceMethod || CanBeClassMethod); -- cgit v1.2.3