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<ObjCSuperExpr>(). 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<ObjCSuperExpr>(...)) {
     // 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
This commit is contained in:
Douglas Gregor 2010-04-21 00:45:42 +00:00
parent 2034d9f2da
commit 9a12919421
21 changed files with 1116 additions and 666 deletions

View File

@ -344,151 +344,352 @@ public:
};
class ObjCMessageExpr : public Expr {
// SubExprs - The receiver and arguments of the message expression.
Stmt **SubExprs;
/// \brief The number of arguments in the message send, not
/// including the receiver.
unsigned NumArgs : 16;
// NumArgs - The number of arguments (not including the receiver) to the
// message expression.
unsigned NumArgs;
/// \brief The kind of message send this is, which is one of the
/// ReceiverKind values.
///
/// We pad this out to a byte to avoid excessive masking and shifting.
unsigned Kind : 8;
/// \brief The location of the class name in a class message.
SourceLocation ClassNameLoc;
/// \brief Whether we have an actual method prototype in \c
/// SelectorOrMethod.
///
/// When non-zero, we have a method declaration; otherwise, we just
/// have a selector.
unsigned HasMethod : 8;
// A unigue name for this message.
Selector SelName;
/// \brief When the message expression is a send to 'super', this is
/// the location of the 'super' keyword.
SourceLocation SuperLoc;
// A method prototype for this message (optional).
// FIXME: Since method decls contain the selector, and most messages have a
// prototype, consider devising a scheme for unifying SelName/MethodProto.
ObjCMethodDecl *MethodProto;
/// \brief Stores either the selector that this message is sending
/// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
/// referring to the method that we type-checked against.
uintptr_t SelectorOrMethod;
SourceLocation LBracloc, RBracloc;
/// \brief The source locations of the open and close square
/// brackets ('[' and ']', respectively).
SourceLocation LBracLoc, RBracLoc;
// Constants for indexing into SubExprs.
enum { RECEIVER=0, ARGS_START=1 };
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
: Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
HasMethod(0), SelectorOrMethod(0) { }
// Bit-swizzling flags.
enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
/// \brief Retrieve the pointer value of the ,essage receiver.
void *getReceiverPointer() const {
return *const_cast<void **>(
reinterpret_cast<const void * const*>(this + 1));
}
/// \brief Set the pointer value of the message receiver.
void setReceiverPointer(void *Value) {
*reinterpret_cast<void **>(this + 1) = Value;
}
public:
/// This constructor is used to represent class messages where the
/// ObjCInterfaceDecl* of the receiver is not known.
ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
SourceLocation clsNameLoc, 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(ASTContext &C, ObjCInterfaceDecl *cls,
SourceLocation clsNameLoc, Selector selInfo,
QualType retType, ObjCMethodDecl *methDecl,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned NumArgs);
// constructor for instance messages.
ObjCMessageExpr(ASTContext &C, Expr *receiver, Selector selInfo,
QualType retType, ObjCMethodDecl *methDecl,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned NumArgs);
explicit ObjCMessageExpr(EmptyShell Empty)
: Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
virtual void DoDestroy(ASTContext &C);
/// getReceiver - Returns the receiver of the message expression.
/// This can be NULL if the message is for class methods. For
/// class methods, use getClassName.
/// FIXME: need to handle/detect 'super' usage within a class method.
Expr *getReceiver() {
uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
}
const Expr *getReceiver() const {
return const_cast<ObjCMessageExpr*>(this)->getReceiver();
}
// FIXME: need setters for different receiver types.
void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; }
Selector getSelector() const { return SelName; }
void setSelector(Selector S) { SelName = S; }
const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
ObjCMethodDecl *getMethodDecl() { return MethodProto; }
void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; }
/// \brief Describes the class receiver of a message send.
struct ClassInfo {
/// \brief The interface declaration for the class that is
/// receiving the message. May be NULL.
ObjCInterfaceDecl *Decl;
/// \brief The name of the class that is receiving the
/// message. This will never be NULL.
IdentifierInfo *Name;
/// \brief The source location of the class name.
SourceLocation Loc;
ClassInfo() : Decl(0), Name(0), Loc() { }
ClassInfo(ObjCInterfaceDecl *Decl, IdentifierInfo *Name, SourceLocation Loc)
: Decl(Decl), Name(Name), Loc(Loc) { }
/// \brief The kind of receiver this message is sending to.
enum ReceiverKind {
/// \brief The receiver is a class.
Class = 0,
/// \brief The receiver is an object instance.
Instance,
/// \brief The receiver is a superclass.
SuperClass,
/// \brief The receiver is the instance of the superclass object.
SuperInstance
};
/// 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;
void setClassInfo(const ClassInfo &C);
/// \brief Create a message send to super.
///
/// \param Context The ASTContext in which this expression will be created.
///
/// \param T The result type of this message.
///
/// \param LBrac The location of the open square bracket '['.
///
/// \param SuperLoc The location of the "super" keyword.
///
/// \param IsInstanceSuper Whether this is an instance "super"
/// message (otherwise, it's a class "super" message).
///
/// \param Sel The selector used to determine which method gets called.
///
/// \param Method The Objective-C method against which this message
/// send was type-checked. May be NULL.
///
/// \param Args The message send arguments.
///
/// \param NumArgs The number of arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
/// getClassName - For class methods, this returns the invoked class,
/// and returns NULL otherwise. For instance methods, use getReceiver.
IdentifierInfo *getClassName() const {
return getClassInfo().Name;
/// \brief Create a class message send.
///
/// \param Context The ASTContext in which this expression will be created.
///
/// \param T The result type of this message.
///
/// \param LBrac The location of the open square bracket '['.
///
/// \param Receiver The type of the receiver, including
/// source-location information.
///
/// \param Sel The selector used to determine which method gets called.
///
/// \param Method The Objective-C method against which this message
/// send was type-checked. May be NULL.
///
/// \param Args The message send arguments.
///
/// \param NumArgs The number of arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
/// \brief Create an instance message send.
///
/// \param Context The ASTContext in which this expression will be created.
///
/// \param T The result type of this message.
///
/// \param LBrac The location of the open square bracket '['.
///
/// \param Receiver The expression used to produce the object that
/// will receive this message.
///
/// \param Sel The selector used to determine which method gets called.
///
/// \param Method The Objective-C method against which this message
/// send was type-checked. May be NULL.
///
/// \param Args The message send arguments.
///
/// \param NumArgs The number of arguments.
///
/// \param RBracLoc The location of the closing square bracket ']'.
static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc);
/// \brief Create an empty Objective-C message expression, to be
/// filled in by subsequent calls.
///
/// \param Context The context in which the message send will be created.
///
/// \param NumArgs The number of message arguments, not including
/// the receiver.
static ObjCMessageExpr *CreateEmpty(ASTContext &Context, unsigned NumArgs);
/// \brief Determine the kind of receiver that this message is being
/// sent to.
ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; }
/// \brief Determine whether this is an instance message to either a
/// computed object or to super.
bool isInstanceMessage() const {
return getReceiverKind() == Instance || getReceiverKind() == SuperInstance;
}
/// getNumArgs - Return the number of actual arguments to this call.
/// \brief Determine whether this is an class message to either a
/// specified class or to super.
bool isClassMessage() const {
return getReceiverKind() == Class || getReceiverKind() == SuperClass;
}
/// \brief Returns the receiver of an instance message.
///
/// \brief Returns the object expression for an instance message, or
/// NULL for a message that is not an instance message.
Expr *getInstanceReceiver() {
if (getReceiverKind() == Instance)
return static_cast<Expr *>(getReceiverPointer());
return 0;
}
const Expr *getInstanceReceiver() const {
return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver();
}
/// \brief Turn this message send into an instance message that
/// computes the receiver object with the given expression.
void setInstanceReceiver(Expr *rec) {
Kind = Instance;
setReceiverPointer(rec);
}
/// \brief Returns the type of a class message send, or NULL if the
/// message is not a class message.
QualType getClassReceiver() const {
if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo())
return TSInfo->getType();
return QualType();
}
/// \brief Returns a type-source information of a class message
/// send, or NULL if the message is not a class message.
TypeSourceInfo *getClassReceiverTypeInfo() const {
if (getReceiverKind() == Class)
return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer());
return 0;
}
void setClassReceiver(TypeSourceInfo *TSInfo) {
Kind = Class;
setReceiverPointer(TSInfo);
}
/// \brief Retrieve the location of the 'super' keyword for a class
/// or instance message to 'super', otherwise an invalid source location.
SourceLocation getSuperLoc() const {
if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass)
return SuperLoc;
return SourceLocation();
}
/// \brief Retrieve the Objective-C interface to which this message
/// is being directed, if known.
///
/// This routine cross-cuts all of the different kinds of message
/// sends to determine what the underlying (statically known) type
/// of the receiver will be; use \c getReceiverKind() to determine
/// whether the message is a class or an instance method, whether it
/// is a send to super or not, etc.
///
/// \returns The Objective-C interface if known, otherwise NULL.
ObjCInterfaceDecl *getReceiverInterface() const;
/// \brief Retrieve the type referred to by 'super'.
///
/// The returned type will either be an ObjCInterfaceType (for an
/// class message to super) or an ObjCObjectPointerType that refers
/// to a class (for an instance message to super);
QualType getSuperType() const {
if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass)
return QualType::getFromOpaquePtr(getReceiverPointer());
return QualType();
}
void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) {
Kind = IsInstanceSuper? SuperInstance : SuperClass;
SuperLoc = Loc;
setReceiverPointer(T.getAsOpaquePtr());
}
Selector getSelector() const;
void setSelector(Selector S) {
HasMethod = false;
SelectorOrMethod = reinterpret_cast<uintptr_t>(S.getAsOpaquePtr());
}
const ObjCMethodDecl *getMethodDecl() const {
if (HasMethod)
return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod);
return 0;
}
ObjCMethodDecl *getMethodDecl() {
if (HasMethod)
return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod);
return 0;
}
void setMethodDecl(ObjCMethodDecl *MD) {
HasMethod = true;
SelectorOrMethod = reinterpret_cast<uintptr_t>(MD);
}
/// \brief Return the number of actual arguments in this message,
/// not counting the receiver.
unsigned getNumArgs() const { return NumArgs; }
void setNumArgs(unsigned nArgs) {
NumArgs = nArgs;
// FIXME: should always allocate SubExprs via the ASTContext's
// allocator.
if (!SubExprs)
SubExprs = new Stmt* [NumArgs + 1];
/// \brief Retrieve the arguments to this message, not including the
/// receiver.
Stmt **getArgs() {
return reinterpret_cast<Stmt **>(this + 1) + 1;
}
const Stmt * const *getArgs() const {
return reinterpret_cast<const Stmt * const *>(this + 1) + 1;
}
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
return cast<Expr>(SubExprs[Arg+ARGS_START]);
return cast<Expr>(getArgs()[Arg]);
}
const Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
return cast<Expr>(SubExprs[Arg+ARGS_START]);
return cast<Expr>(getArgs()[Arg]);
}
/// setArg - Set the specified argument.
void setArg(unsigned Arg, Expr *ArgExpr) {
assert(Arg < NumArgs && "Arg access out of range!");
SubExprs[Arg+ARGS_START] = ArgExpr;
getArgs()[Arg] = ArgExpr;
}
SourceLocation getLeftLoc() const { return LBracloc; }
SourceLocation getRightLoc() const { return RBracloc; }
SourceLocation getLeftLoc() const { return LBracLoc; }
SourceLocation getRightLoc() const { return RBracLoc; }
void setLeftLoc(SourceLocation L) { LBracloc = L; }
void setRightLoc(SourceLocation L) { RBracloc = L; }
void setLeftLoc(SourceLocation L) { LBracLoc = L; }
void setRightLoc(SourceLocation L) { RBracLoc = L; }
void setSourceRange(SourceRange R) {
LBracloc = R.getBegin();
RBracloc = R.getEnd();
LBracLoc = R.getBegin();
RBracLoc = R.getEnd();
}
virtual SourceRange getSourceRange() const {
return SourceRange(LBracloc, RBracloc);
return SourceRange(LBracLoc, RBracLoc);
}
static bool classof(const Stmt *T) {
@ -503,10 +704,10 @@ public:
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
arg_iterator arg_begin() { return getArgs(); }
arg_iterator arg_end() { return getArgs() + NumArgs; }
const_arg_iterator arg_begin() const { return (Stmt **)getArgs(); }
const_arg_iterator arg_end() const { return (Stmt **)getArgs() + NumArgs; }
};
/// ObjCSuperExpr - Represents the "super" expression in Objective-C,

View File

@ -458,7 +458,6 @@ public:
namespace bugreporter {
const Stmt *GetDerefExpr(const ExplodedNode *N);
const Stmt *GetReceiverExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetCalleeExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);

View File

@ -2239,101 +2239,156 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
}
// constructor for instance messages.
ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver,
Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo),
MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = receiver;
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
}
LBracloc = LBrac;
RBracloc = RBrac;
}
// constructor for class messages.
// FIXME: clsName should be typed to ObjCInterfaceType
ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
SourceLocation clsNameLoc, Selector selInfo,
QualType retType, ObjCMethodDecl *mproto,
SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs, unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
SelName(selInfo), MethodProto(mproto) {
NumArgs = nargs;
SubExprs = new (C) Stmt*[NumArgs+1];
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
if (NumArgs) {
for (unsigned i = 0; i != NumArgs; ++i)
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
}
LBracloc = LBrac;
RBracloc = RBrac;
}
// constructor for class messages.
ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
SourceLocation clsNameLoc, Selector selInfo,
QualType retType,
ObjCMethodDecl *mproto, SourceLocation LBrac,
SourceLocation RBrac, Expr **ArgExprs,
unsigned nargs)
: Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
SelName(selInfo), MethodProto(mproto)
ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false,
hasAnyValueDependentArguments(Args, NumArgs)),
NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
HasMethod(Method != 0), SuperLoc(SuperLoc),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
NumArgs = nargs;
SubExprs = new (C) 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<Expr *>(ArgExprs[i]);
}
LBracloc = LBrac;
RBracloc = RBrac;
setReceiverPointer(SuperType.getAsOpaquePtr());
if (NumArgs)
memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
}
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, SourceLocation());
case IsClsMethDeclUnknown:
return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc);
case IsClsMethDeclKnown: {
ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags);
return ClassInfo(D, D->getIdentifier(), ClassNameLoc);
}
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, T->isDependentType(),
(T->isDependentType() ||
hasAnyValueDependentArguments(Args, NumArgs))),
NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
setReceiverPointer(Receiver);
if (NumArgs)
memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
}
void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
if (CI.Decl == 0 && CI.Name == 0) {
SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth);
return;
}
if (CI.Decl == 0)
SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown);
else
SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown);
ClassNameLoc = CI.Loc;
ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, T->isDependentType(),
(T->isDependentType() ||
hasAnyValueDependentArguments(Args, NumArgs))),
NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
setReceiverPointer(Receiver);
if (NumArgs)
memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
}
void ObjCMessageExpr::DoDestroy(ASTContext &C) {
DestroyChildren(C);
if (SubExprs)
C.Deallocate(SubExprs);
this->~ObjCMessageExpr();
C.Deallocate((void*) this);
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper,
SuperType, Sel, Method, Args, NumArgs,
RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
NumArgs, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
NumArgs, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
unsigned NumArgs) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
Selector ObjCMessageExpr::getSelector() const {
if (HasMethod)
return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod)
->getSelector();
return Selector(SelectorOrMethod);
}
ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
switch (getReceiverKind()) {
case Instance:
if (const ObjCObjectPointerType *Ptr
= getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
return Ptr->getInterfaceDecl();
break;
case Class:
if (const ObjCInterfaceType *Iface
= getClassReceiver()->getAs<ObjCInterfaceType>())
return Iface->getDecl();
break;
case SuperInstance:
if (const ObjCObjectPointerType *Ptr
= getSuperType()->getAs<ObjCObjectPointerType>())
return Ptr->getInterfaceDecl();
break;
case SuperClass:
if (const ObjCObjectPointerType *Iface
= getSuperType()->getAs<ObjCObjectPointerType>())
return Iface->getInterfaceDecl();
break;
}
return 0;
}
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
@ -2809,10 +2864,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() {
// ObjCMessageExpr
Stmt::child_iterator ObjCMessageExpr::child_begin() {
return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START;
if (getReceiverKind() == Instance)
return reinterpret_cast<Stmt **>(this + 1);
return getArgs();
}
Stmt::child_iterator ObjCMessageExpr::child_end() {
return &SubExprs[0]+ARGS_START+getNumArgs();
return getArgs() + getNumArgs();
}
// Blocks

View File

@ -505,8 +505,23 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
OS << " selector=" << Node->getSelector().getAsString();
if (IdentifierInfo *clsName = Node->getClassName())
OS << " class=" << clsName->getNameStart();
switch (Node->getReceiverKind()) {
case ObjCMessageExpr::Instance:
break;
case ObjCMessageExpr::Class:
OS << " class=";
DumpType(Node->getClassReceiver());
break;
case ObjCMessageExpr::SuperInstance:
OS << " super (instance)";
break;
case ObjCMessageExpr::SuperClass:
OS << " super (class)";
break;
}
}
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {

View File

@ -1247,9 +1247,21 @@ void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "[";
Expr *receiver = Mess->getReceiver();
if (receiver) PrintExpr(receiver);
else OS << Mess->getClassName()->getName();
switch (Mess->getReceiverKind()) {
case ObjCMessageExpr::Instance:
PrintExpr(Mess->getInstanceReceiver());
break;
case ObjCMessageExpr::Class:
OS << Mess->getClassReceiver().getAsString(Policy);
break;
case ObjCMessageExpr::SuperInstance:
case ObjCMessageExpr::SuperClass:
OS << "Super";
break;
}
OS << ' ';
Selector selector = Mess->getSelector();
if (selector.isUnarySelector()) {

View File

@ -31,13 +31,22 @@
using namespace clang;
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
const Expr* Receiver = ME->getReceiver();
QualType T;
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Instance:
T = ME->getInstanceReceiver()->getType();
break;
if (!Receiver)
return NULL;
case ObjCMessageExpr::SuperInstance:
T = ME->getSuperType();
break;
if (const ObjCObjectPointerType *PT =
Receiver->getType()->getAs<ObjCObjectPointerType>())
case ObjCMessageExpr::Class:
case ObjCMessageExpr::SuperClass:
return 0;
}
if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
return PT->getInterfaceType();
return NULL;
@ -509,11 +518,21 @@ public:
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
const IdentifierInfo *ClsName = ME->getClassName();
if (!ClsName)
ObjCInterfaceDecl *Class = 0;
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Class:
Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
break;
case ObjCMessageExpr::SuperClass:
Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
case ObjCMessageExpr::Instance:
case ObjCMessageExpr::SuperInstance:
return;
}
Selector S = ME->getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
"of class '" << ClsName->getName()
"of class '" << Class->getName()
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);

View File

@ -46,14 +46,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
return NULL;
}
const Stmt*
clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
return ME->getReceiver();
return NULL;
}
const Stmt*
clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
@ -402,7 +394,7 @@ public:
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
const Expr *Receiver = ME->getReceiver();
const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();

View File

@ -603,12 +603,33 @@ public:
Selector S = ME->getSelector();
if (Expr* Receiver = ME->getReceiver()) {
const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
const ObjCInterfaceDecl* OD = 0;
bool IsInstanceMessage = false;
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Instance:
OD = getReceiverDecl(ME->getInstanceReceiver());
IsInstanceMessage = true;
break;
case ObjCMessageExpr::SuperInstance:
IsInstanceMessage = true;
OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
->getInterfaceDecl();
break;
case ObjCMessageExpr::Class:
OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
break;
case ObjCMessageExpr::SuperClass:
OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
}
return M[ObjCSummaryKey(ME->getClassName(), S)];
if (IsInstanceMessage)
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
return M[ObjCSummaryKey(OD->getIdentifier(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
@ -836,7 +857,7 @@ public:
RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
return getInstanceMethodSummary(ME->getSelector(), 0,
ID, ME->getMethodDecl(), ME->getType());
}
@ -851,8 +872,21 @@ public:
QualType RetTy);
RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
ME->getClassInfo().Decl,
ObjCInterfaceDecl *Class = 0;
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Class:
case ObjCMessageExpr::SuperClass:
Class = ME->getReceiverInterface();
break;
case ObjCMessageExpr::Instance:
case ObjCMessageExpr::SuperInstance:
break;
}
return getClassMethodSummary(ME->getSelector(),
Class? Class->getIdentifier() : 0,
Class,
ME->getMethodDecl(), ME->getType());
}
@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
const Expr *Receiver = ME->getReceiver();
const Expr *Receiver = ME->getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
SVal receiverV;
if (const Expr *Receiver = ME->getInstanceReceiver()) {
receiverV = state->getSValAsScalarOrLoc(Receiver);
// FIXME: Eventually replace the use of state->get<RefBindings> with
// a generic API for reasoning about the Objective-C types of symbolic
// objects.
if (SymbolRef Sym = receiverV.getAsLocSymbol())
if (const RefVal *T = state->get<RefBindings>(Sym))
if (const ObjCObjectPointerType* PT =
// FIXME: Eventually replace the use of state->get<RefBindings> with
// a generic API for reasoning about the Objective-C types of symbolic
// objects.
if (SymbolRef Sym = receiverV.getAsLocSymbol())
if (const RefVal *T = state->get<RefBindings>(Sym))
if (const ObjCObjectPointerType* PT =
T->getType()->getAs<ObjCObjectPointerType>())
ID = PT->getInterfaceDecl();
// FIXME: this is a hack. This may or may not be the actual method
// that is called.
if (!ID) {
if (const ObjCObjectPointerType *PT =
Receiver->getType()->getAs<ObjCObjectPointerType>())
ID = PT->getInterfaceDecl();
// FIXME: this is a hack. This may or may not be the actual method
// that is called.
if (!ID) {
if (const ObjCObjectPointerType *PT =
Receiver->getType()->getAs<ObjCObjectPointerType>())
ID = PT->getInterfaceDecl();
}
} else {
// FIXME: Hack for 'super'.
ID = ME->getReceiverInterface();
}
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
if (isa<ObjCMethodDecl>(LC->getDecl())) {
if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
// Get the region associated with 'self'.
if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
if (const Expr *receiver = ME->getReceiver())
if (const Expr *receiver = ME->getInstanceReceiver())
if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
const ObjCInterfaceDecl *D = ME->getReceiverInterface();
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}
@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
assert(Receiver);
SVal V = state->getSValAsScalarOrLoc(Receiver);
bool found = false;
if (SymbolRef Sym = V.getAsLocSymbol())
if (state->get<RefBindings>(Sym)) {
found = true;
RE = Summaries.getObjAllocRetEffect();
}
if (Receiver) {
SVal V = state->getSValAsScalarOrLoc(Receiver);
if (SymbolRef Sym = V.getAsLocSymbol())
if (state->get<RefBindings>(Sym)) {
found = true;
RE = Summaries.getObjAllocRetEffect();
}
} // FIXME: Otherwise, this is a send-to-super instance message.
if (!found)
RE = RetEffect::MakeNoRet();
}
@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
ExplodedNode* Pred,
const GRState *state) {
RetainSummary *Summ =
ME->getReceiver()
ME->isInstanceMessage()
? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}

View File

@ -218,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const GRState *state = C.getState();
if (const Expr *receiver = ME->getReceiver())
// FIXME: Handle 'super'?
if (const Expr *receiver = ME->getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_undef)
@ -265,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
const Expr *receiver = ME->getReceiver();
report->addRange(receiver->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
if (const Expr *receiver = ME->getInstanceReceiver()) {
report->addRange(receiver->getSourceRange());
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
}
C.EmitReport(report);
}

View File

@ -27,10 +27,14 @@ using namespace clang;
static bool scan_dealloc(Stmt* S, Selector Dealloc) {
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Dealloc)
if (ME->getReceiver())
if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
return isa<ObjCSuperExpr>(Receiver);
if (ME->getSelector() == Dealloc) {
switch (ME->getReceiverKind()) {
case ObjCMessageExpr::Instance: return false;
case ObjCMessageExpr::SuperInstance: return true;
case ObjCMessageExpr::Class: break;
case ObjCMessageExpr::SuperClass: break;
}
}
// Recurse to children.
@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
if (ME->getReceiver())
if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
if (ME->getInstanceReceiver())
if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getReceiver())
if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
if (ME->getInstanceReceiver())
if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&

View File

@ -2124,7 +2124,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// But first evaluate the receiver (if any).
ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
if (Expr *Receiver = ME->getReceiver()) {
if (Expr *Receiver = ME->getInstanceReceiver()) {
ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
@ -2176,7 +2176,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
if (const Expr *Receiver = ME->getReceiver()) {
if (const Expr *Receiver = ME->getInstanceReceiver()) {
const GRState *state = GetState(Pred);
// Bifurcate the state into nil and non-nil ones.
@ -2206,8 +2206,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// Dispatch to plug-in transfer function.
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
else {
IdentifierInfo* ClsName = ME->getClassName();
else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
IdentifierInfo* ClsName = Iface->getIdentifier();
Selector S = ME->getSelector();
// Check for special instance methods.

View File

@ -56,7 +56,7 @@ void
NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
const Expr *receiver = ME->getReceiver();
const Expr *receiver = ME->getInstanceReceiver();
if (!receiver)
return;

View File

@ -53,31 +53,34 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
// arguments in generic code.
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const Expr *ReceiverExpr = E->getReceiver();
bool isSuperMessage = false;
bool isClassMessage = false;
// Find the receiver
llvm::Value *Receiver;
if (!ReceiverExpr) {
const ObjCInterfaceDecl *OID = E->getClassInfo().Decl;
// Very special case, super send in class method. The receiver is
// self (the class object) and the send uses super semantics.
if (!OID) {
assert(E->getClassName()->isStr("super") &&
"Unexpected missing class interface in message send.");
isSuperMessage = true;
Receiver = LoadObjCSelf();
} else {
Receiver = Runtime.GetClass(Builder, OID);
}
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
case ObjCMessageExpr::Class: {
const ObjCInterfaceType *IFace
= E->getClassReceiver()->getAs<ObjCInterfaceType>();
assert(IFace && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, IFace->getDecl());
isClassMessage = true;
} else if (isa<ObjCSuperExpr>(E->getReceiver())) {
isSuperMessage = true;
break;
}
case ObjCMessageExpr::SuperInstance:
Receiver = LoadObjCSelf();
} else {
Receiver = EmitScalarExpr(E->getReceiver());
isSuperMessage = true;
break;
case ObjCMessageExpr::SuperClass:
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
break;
}
CallArgList Args;

View File

@ -782,25 +782,42 @@ unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr(
unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
E->setNumArgs(Record[Idx++]);
assert(Record[Idx] == E->getNumArgs());
++Idx;
ObjCMessageExpr::ReceiverKind Kind
= static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
switch (Kind) {
case ObjCMessageExpr::Instance:
E->setInstanceReceiver(
cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
break;
case ObjCMessageExpr::Class:
E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx));
break;
case ObjCMessageExpr::SuperClass:
case ObjCMessageExpr::SuperInstance: {
QualType T = Reader.GetType(Record[Idx++]);
SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]);
E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
break;
}
}
assert(Kind == E->getReceiverKind());
if (Record[Idx++])
E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
else
E->setSelector(Reader.GetSelector(Record, Idx));
E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setSelector(Reader.GetSelector(Record, Idx));
E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
E->setReceiver(
cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
if (!E->getReceiver()) {
ObjCMessageExpr::ClassInfo CI;
CI.Decl = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]));
CI.Name = Reader.GetIdentifierInfo(Record, Idx);
CI.Loc = SourceLocation::getFromRawEncoding(Record[Idx++]);
E->setClassInfo(CI);
}
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
return E->getNumArgs() + 1;
return E->getNumArgs() + (Kind == ObjCMessageExpr::Instance);
}
unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) {
@ -1195,7 +1212,8 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty);
break;
case pch::EXPR_OBJC_MESSAGE_EXPR:
S = new (Context) ObjCMessageExpr(Empty);
S = ObjCMessageExpr::CreateEmpty(*Context,
Record[PCHStmtReader::NumExprFields]);
break;
case pch::EXPR_OBJC_SUPER_EXPR:
S = new (Context) ObjCSuperExpr(Empty);

View File

@ -712,18 +712,33 @@ void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr(
void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Writer.WriteSubStmt(E->getInstanceReceiver());
break;
case ObjCMessageExpr::Class:
Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record);
break;
case ObjCMessageExpr::SuperClass:
case ObjCMessageExpr::SuperInstance:
Writer.AddTypeRef(E->getSuperType(), Record);
Writer.AddSourceLocation(E->getSuperLoc(), Record);
break;
}
if (E->getMethodDecl()) {
Record.push_back(1);
Writer.AddDeclRef(E->getMethodDecl(), Record);
} else {
Record.push_back(0);
Writer.AddSelectorRef(E->getSelector(), Record);
}
Writer.AddSourceLocation(E->getLeftLoc(), Record);
Writer.AddSourceLocation(E->getRightLoc(), Record);
Writer.AddSelectorRef(E->getSelector(), Record);
Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
Writer.WriteSubStmt(E->getReceiver());
if (!E->getReceiver()) {
ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
Writer.AddDeclRef(CI.Decl, Record);
Writer.AddIdentifierRef(CI.Name, Record);
Writer.AddSourceLocation(CI.Loc, Record);
}
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg)

View File

@ -1239,11 +1239,26 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getSetterName(), PDecl->getType(),
PDecl->getSetterMethodDecl(),
SourceLocation(), SourceLocation(),
&ExprVec[0], 1);
if (isa<ObjCSuperExpr>(Receiver))
MsgExpr = ObjCMessageExpr::Create(*Context,
PDecl->getType().getNonReferenceType(),
/*FIXME?*/SourceLocation(),
Receiver->getLocStart(),
/*IsInstanceSuper=*/true,
cast<Expr>(Receiver)->getType(),
PDecl->getSetterName(),
PDecl->getSetterMethodDecl(),
&ExprVec[0], 1,
/*FIXME:*/SourceLocation());
else
MsgExpr = ObjCMessageExpr::Create(*Context,
PDecl->getType().getNonReferenceType(),
/*FIXME: */SourceLocation(),
cast<Expr>(Receiver),
PDecl->getSetterName(),
PDecl->getSetterMethodDecl(),
&ExprVec[0], 1,
/*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
// Now do the actual rewrite.
@ -1268,11 +1283,27 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
PDecl->getGetterName(), PDecl->getType(),
PDecl->getGetterMethodDecl(),
SourceLocation(), SourceLocation(),
0, 0);
if (isa<ObjCSuperExpr>(Receiver))
MsgExpr = ObjCMessageExpr::Create(*Context,
PDecl->getType().getNonReferenceType(),
/*FIXME:*/SourceLocation(),
Receiver->getLocStart(),
/*IsInstanceSuper=*/true,
cast<Expr>(Receiver)->getType(),
PDecl->getGetterName(),
PDecl->getGetterMethodDecl(),
0, 0,
/*FIXME:*/SourceLocation());
else
MsgExpr = ObjCMessageExpr::Create(*Context,
PDecl->getType().getNonReferenceType(),
/*FIXME:*/SourceLocation(),
cast<Expr>(Receiver),
PDecl->getGetterName(),
PDecl->getGetterMethodDecl(),
0, 0,
/*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
@ -2687,205 +2718,211 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Synthesize a call to objc_msgSend().
llvm::SmallVector<Expr*, 8> MsgExprs;
IdentifierInfo *clsName = Exp->getClassName();
switch (Exp->getReceiverKind()) {
case ObjCMessageExpr::SuperClass: {
MsgSendFlavor = MsgSendSuperFunctionDecl;
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
// Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
if (clsName) { // class message.
// FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle
// the 'super' idiom within a class method.
if (clsName->getName() == "super") {
MsgSendFlavor = MsgSendSuperFunctionDecl;
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
llvm::SmallVector<Expr*, 4> InitExprs;
llvm::SmallVector<Expr*, 4> InitExprs;
// set the receiver to self, the first argument to all methods.
InitExprs.push_back(
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()))
); // set the 'receiver'.
// set the receiver to self, the first argument to all methods.
InitExprs.push_back(
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()))
); // set the 'receiver'.
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc,
EndLoc);
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
CastExpr::CK_Unknown, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
&ClsExprs[0], ClsExprs.size(),
StartLoc, EndLoc);
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
InitExprs.push_back( // set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context,
Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc,
EndLoc);
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
CastExpr::CK_Unknown, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
&ClsExprs[0], ClsExprs.size(),
StartLoc, EndLoc);
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
InitExprs.push_back( // set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context,
Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
if (LangOpts.Microsoft) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
superType, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
// internal definition (__rw_objc_super) that is uses. This is why
// we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType),
CastExpr::CK_Unknown, SuperRep);
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
new (Context) InitListExpr(*Context, SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
superType, ILE, false);
// struct objc_super *
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
}
MsgExprs.push_back(SuperRep);
if (LangOpts.Microsoft) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
superType, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
// internal definition (__rw_objc_super) that is uses. This is why
// we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType),
CastExpr::CK_Unknown, SuperRep);
} else {
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
clsName->getNameStart(),
clsName->getLength(),
false, argType,
SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc, EndLoc);
MsgExprs.push_back(Cls);
}
} else { // instance message.
Expr *recExpr = Exp->getReceiver();
if (isSuperReceiver(recExpr)) {
MsgSendFlavor = MsgSendSuperFunctionDecl;
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
llvm::SmallVector<Expr*, 4> InitExprs;
InitExprs.push_back(
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()))
); // set the 'receiver'.
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc, EndLoc);
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
CastExpr::CK_Unknown, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
&ClsExprs[0], ClsExprs.size(),
StartLoc, EndLoc);
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
InitExprs.push_back(
// set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
if (LangOpts.Microsoft) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
superType, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
// internal definition (__rw_objc_super) that is uses. This is why
// we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType),
CastExpr::CK_Unknown, SuperRep);
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
new (Context) InitListExpr(*Context, SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
superType, ILE, false);
}
MsgExprs.push_back(SuperRep);
} else {
// Remove all type-casts because it may contain objc-style types; e.g.
// Foo<Proto> *.
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
recExpr = CE->getSubExpr();
recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown, recExpr);
MsgExprs.push_back(recExpr);
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
new (Context) InitListExpr(*Context, SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
superType, ILE, false);
// struct objc_super *
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
}
MsgExprs.push_back(SuperRep);
break;
}
case ObjCMessageExpr::Class: {
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ObjCInterfaceDecl *Class
= Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(StringLiteral::Create(*Context,
clsName->getNameStart(),
clsName->getLength(),
false, argType,
SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc, EndLoc);
MsgExprs.push_back(Cls);
break;
}
case ObjCMessageExpr::SuperInstance:{
MsgSendFlavor = MsgSendSuperFunctionDecl;
if (MsgSendStretFlavor)
MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
llvm::SmallVector<Expr*, 4> InitExprs;
InitExprs.push_back(
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
SourceLocation()))
); // set the 'receiver'.
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
ClsExprs.push_back(StringLiteral::Create(*Context,
ClassDecl->getIdentifier()->getNameStart(),
ClassDecl->getIdentifier()->getLength(),
false, argType, SourceLocation()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
StartLoc, EndLoc);
// (Class)objc_getClass("CurrentClass")
CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
Context->getObjCClassType(),
CastExpr::CK_Unknown, Cls);
ClsExprs.clear();
ClsExprs.push_back(ArgExpr);
Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
&ClsExprs[0], ClsExprs.size(),
StartLoc, EndLoc);
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
// To turn off a warning, type-cast to 'id'
InitExprs.push_back(
// set 'super class', using class_getSuperclass().
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
if (LangOpts.Microsoft) {
SynthSuperContructorFunctionDecl();
// Simulate a contructor call...
DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
superType, SourceLocation());
SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
InitExprs.size(),
superType, SourceLocation());
// The code for super is a little tricky to prevent collision with
// the structure definition in the header. The rewriter has it's own
// internal definition (__rw_objc_super) that is uses. This is why
// we need the cast below. For example:
// (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
//
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
SuperRep = NoTypeInfoCStyleCastExpr(Context,
Context->getPointerType(superType),
CastExpr::CK_Unknown, SuperRep);
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE =
new (Context) InitListExpr(*Context, SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
TypeSourceInfo *superTInfo
= Context->getTrivialTypeSourceInfo(superType);
SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
superType, ILE, false);
}
MsgExprs.push_back(SuperRep);
break;
}
case ObjCMessageExpr::Instance: {
// Remove all type-casts because it may contain objc-style types; e.g.
// Foo<Proto> *.
Expr *recExpr = Exp->getInstanceReceiver();
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
recExpr = CE->getSubExpr();
recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
CastExpr::CK_Unknown, recExpr);
MsgExprs.push_back(recExpr);
break;
}
}
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);

View File

@ -153,9 +153,10 @@ public:
ObjCInterfaceDecl *MsgD = 0;
ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(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->getClassInfo().Decl;
// FIXME: Case when we only have an identifier.
assert(MsgD && "Identifier only");
MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
break;
}
case ObjCMessageExpr::SuperClass:
// Expecting class method.
if (IsInstanceMethod)
return false;
MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
case ObjCMessageExpr::SuperInstance:
// Expecting instance method.
if (!IsInstanceMethod)
return false;
MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
->getInterfaceDecl();
break;
}
assert(MsgD);
@ -248,31 +268,44 @@ public:
ObjCInterfaceDecl *MsgD = 0;
while (true) {
if (Msg->getReceiver() == 0) {
switch (Msg->getReceiverKind()) {
case ObjCMessageExpr::Instance: {
const ObjCObjectPointerType *OPT =
Msg->getInstanceReceiver()->getType()
->getAsObjCInterfacePointerType();
if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
CanBeInstanceMethod = CanBeClassMethod = true;
break;
}
if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
CanBeClassMethod = true;
break;
}
MsgD = OPT->getInterfaceDecl();
assert(MsgD);
CanBeInstanceMethod = true;
break;
}
case ObjCMessageExpr::Class:
CanBeClassMethod = true;
MsgD = Msg->getClassInfo().Decl;
// FIXME: Case when we only have an identifier.
assert(MsgD && "Identifier only");
MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
break;
}
const ObjCObjectPointerType *OPT =
Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
CanBeInstanceMethod = CanBeClassMethod = true;
break;
}
if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
case ObjCMessageExpr::SuperClass:
CanBeClassMethod = true;
MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
case ObjCMessageExpr::SuperInstance:
CanBeInstanceMethod = true;
MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
->getInterfaceDecl();
break;
}
MsgD = OPT->getInterfaceDecl();
assert(MsgD);
CanBeInstanceMethod = true;
break;
}
assert(CanBeInstanceMethod || CanBeClassMethod);

View File

@ -2899,13 +2899,24 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
return 0;
// Determine the class that we're sending the message to.
ObjCInterfaceDecl *IFace = Msg->getClassInfo().Decl;
if (!IFace) {
if (Expr *Receiver = Msg->getReceiver()) {
QualType T = Receiver->getType();
if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
IFace = Ptr->getInterfaceDecl();
}
ObjCInterfaceDecl *IFace = 0;
switch (Msg->getReceiverKind()) {
case ObjCMessageExpr::Class:
if (const ObjCInterfaceType *IFaceType
= Msg->getClassReceiver()->getAs<ObjCInterfaceType>())
IFace = IFaceType->getDecl();
break;
case ObjCMessageExpr::Instance: {
QualType T = Msg->getInstanceReceiver()->getType();
if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
IFace = Ptr->getInterfaceDecl();
break;
}
case ObjCMessageExpr::SuperInstance:
case ObjCMessageExpr::SuperClass:
break;
}
if (!IFace)

View File

@ -3130,10 +3130,10 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel,
OMD->getResultType(),
OMD, OpLoc, MemberLoc,
NULL, 0));
return Owned(ObjCMessageExpr::Create(Context,
OMD->getResultType().getNonReferenceType(),
OpLoc, BaseExpr, Sel,
OMD, NULL, 0, MemberLoc));
}
}

View File

@ -684,20 +684,19 @@ ActOnClassMessage(Scope *S, IdentifierInfo *receiverName, Selector Sel,
returnType = returnType.getNonReferenceType();
// FIXME: need to do a better job handling 'super' usage within a class. For
// now, we simply pass the "super" identifier through (which isn't consistent
// with instance methods.
QualType ReceiverType = Context.getObjCInterfaceType(ClassDecl);
if (isSuper)
return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc,
Sel, returnType, Method, lbrac, rbrac,
ArgExprs, NumArgs);
return ObjCMessageExpr::Create(Context, returnType, lbrac, receiverLoc,
/*IsInstanceSuper=*/false,ReceiverType,
Sel, Method, ArgExprs, NumArgs, rbrac);
// 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.
return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc,
Sel, returnType, Method, lbrac, rbrac,
ArgExprs, NumArgs);
TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(ReceiverType,
receiverLoc);
return ObjCMessageExpr::Create(Context, returnType, lbrac, TSInfo, Sel,
Method, ArgExprs, NumArgs, rbrac);
}
// ActOnInstanceMessage - used for both unary and keyword messages.
@ -717,6 +716,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// C99 6.7.5.3p[7,8].
DefaultFunctionArrayLvalueConversion(RExpr);
ObjCMethodDecl *Method = 0;
QualType returnType;
QualType ReceiverCType =
Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
@ -724,24 +724,15 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
// Handle messages to id.
if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() ||
Context.isObjCNSObjectType(RExpr->getType())) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
// FIXME: If our superclass is NSObject and we message 'super',
// we'll end up looking in the global method pool??
Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
Method, lbrac, rbrac,
ArgExprs, NumArgs);
}
// Handle messages to Class.
if (ReceiverCType->isObjCClassType() ||
ReceiverCType->isObjCQualifiedClassType()) {
ObjCMethodDecl *Method = 0;
} else if (ReceiverCType->isObjCClassType() ||
ReceiverCType->isObjCQualifiedClassType()) {
// Handle messages to Class.
if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
// First check the public methods in the class interface.
@ -775,86 +766,78 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
}
}
}
if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
Method, lbrac, rbrac,
ArgExprs, NumArgs);
}
} else {
ObjCInterfaceDecl* ClassDecl = 0;
ObjCMethodDecl *Method = 0;
ObjCInterfaceDecl* ClassDecl = 0;
// We allow sending a message to a qualified ID ("id<foo>"), which is ok as
// long as one of the protocols implements the selector (if not, warn).
if (const ObjCObjectPointerType *QIdTy =
// We allow sending a message to a qualified ID ("id<foo>"), which is ok as
// long as one of the protocols implements the selector (if not, warn).
if (const ObjCObjectPointerType *QIdTy =
ReceiverCType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
E = QIdTy->qual_end(); I != E; ++I) {
ObjCProtocolDecl *PDecl = *I;
if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
break;
// Since we aren't supporting "Class<foo>", look for a class method.
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
break;
}
} else if (const ObjCObjectPointerType *OCIType =
ReceiverCType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
ClassDecl = OCIType->getInterfaceDecl();
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to InstanceMethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
if (!Method) {
// Search protocol qualifiers.
for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
E = OCIType->qual_end(); QI != E; ++QI) {
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
// Search protocols for instance methods.
for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
E = QIdTy->qual_end(); I != E; ++I) {
ObjCProtocolDecl *PDecl = *I;
if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
break;
// Since we aren't supporting "Class<foo>", look for a class method.
if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
break;
}
}
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
} else if (const ObjCObjectPointerType *OCIType =
ReceiverCType->getAsObjCInterfacePointerType()) {
// We allow sending a message to a pointer to an interface (an object).
if (!Method && !isSelfExpr(RExpr)) {
// 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??
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
Diag(lbrac, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;
ClassDecl = OCIType->getInterfaceDecl();
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to InstanceMethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
if (!Method) {
// Search protocol qualifiers.
for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
E = OCIType->qual_end(); QI != E; ++QI) {
if ((Method = (*QI)->lookupInstanceMethod(Sel)))
break;
}
}
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
if (!Method) {
// If we have implementations in scope, check "private" methods.
Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
if (!Method && !isSelfExpr(RExpr)) {
// 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??
if (OCIType->qual_empty()) {
Method = LookupInstanceMethodInGlobalPool(
Sel, SourceRange(lbrac,rbrac));
if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
Diag(lbrac, diag::warn_maynot_respond)
<< OCIType->getInterfaceDecl()->getIdentifier() << Sel;
}
}
}
if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
return true;
} else if (!Context.getObjCIdType().isNull() &&
(ReceiverCType->isPointerType() ||
(ReceiverCType->isIntegerType() &&
ReceiverCType->isScalarType()))) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
Diag(lbrac, diag::warn_bad_receiver_type)
<< RExpr->getType() << RExpr->getSourceRange();
if (ReceiverCType->isPointerType())
ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast);
else
ImpCastExprToType(RExpr, Context.getObjCIdType(),
CastExpr::CK_IntegralToPointer);
} else {
// Reject other random receiver types (e.g. structs).
Diag(lbrac, diag::err_bad_receiver_type)
<< RExpr->getType() << RExpr->getSourceRange();
return true;
} else if (!Context.getObjCIdType().isNull() &&
(ReceiverCType->isPointerType() ||
(ReceiverCType->isIntegerType() &&
ReceiverCType->isScalarType()))) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
Diag(lbrac, diag::warn_bad_receiver_type)
<< RExpr->getType() << RExpr->getSourceRange();
if (ReceiverCType->isPointerType())
ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast);
else
ImpCastExprToType(RExpr, Context.getObjCIdType(),
CastExpr::CK_IntegralToPointer);
} else {
// Reject other random receiver types (e.g. structs).
Diag(lbrac, diag::err_bad_receiver_type)
<< RExpr->getType() << RExpr->getSourceRange();
return true;
}
}
if (Method)
@ -863,7 +846,15 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
lbrac, rbrac, returnType))
return true;
returnType = returnType.getNonReferenceType();
return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method,
lbrac, rbrac, ArgExprs, NumArgs);
if (isa<ObjCSuperExpr>(RExpr))
return ObjCMessageExpr::Create(Context, returnType, lbrac,
RExpr->getLocStart(),
/*IsInstanceSuper=*/true,
RExpr->getType(),
Sel, Method, ArgExprs, NumArgs, rbrac);
return ObjCMessageExpr::Create(Context, returnType, lbrac, RExpr, Sel,
Method, ArgExprs, NumArgs, rbrac);
}

View File

@ -971,9 +971,9 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
}
bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) {
ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
if (CI.Decl && Visit(MakeCursorObjCClassRef(CI.Decl, CI.Loc, TU)))
return true;
if (TypeSourceInfo *TSInfo = E->getClassReceiverTypeInfo())
if (Visit(TSInfo->getTypeLoc()))
return true;
return VisitExpr(E);
}