forked from OSchip/llvm-project
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:
parent
2034d9f2da
commit
9a12919421
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() &&
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue