SemaPseudoObject.cpp revision 249423
1234287Sdim//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===// 2234287Sdim// 3234287Sdim// The LLVM Compiler Infrastructure 4234287Sdim// 5234287Sdim// This file is distributed under the University of Illinois Open Source 6234287Sdim// License. See LICENSE.TXT for details. 7234287Sdim// 8234287Sdim//===----------------------------------------------------------------------===// 9234287Sdim// 10234287Sdim// This file implements semantic analysis for expressions involving 11234287Sdim// pseudo-object references. Pseudo-objects are conceptual objects 12234287Sdim// whose storage is entirely abstract and all accesses to which are 13234287Sdim// translated through some sort of abstraction barrier. 14234287Sdim// 15234287Sdim// For example, Objective-C objects can have "properties", either 16234287Sdim// declared or undeclared. A property may be accessed by writing 17234287Sdim// expr.prop 18234287Sdim// where 'expr' is an r-value of Objective-C pointer type and 'prop' 19234287Sdim// is the name of the property. If this expression is used in a context 20234287Sdim// needing an r-value, it is treated as if it were a message-send 21234287Sdim// of the associated 'getter' selector, typically: 22234287Sdim// [expr prop] 23234287Sdim// If it is used as the LHS of a simple assignment, it is treated 24234287Sdim// as a message-send of the associated 'setter' selector, typically: 25234287Sdim// [expr setProp: RHS] 26234287Sdim// If it is used as the LHS of a compound assignment, or the operand 27234287Sdim// of a unary increment or decrement, both are required; for example, 28234287Sdim// 'expr.prop *= 100' would be translated to: 29234287Sdim// [expr setProp: [expr prop] * 100] 30234287Sdim// 31234287Sdim//===----------------------------------------------------------------------===// 32234287Sdim 33234287Sdim#include "clang/Sema/SemaInternal.h" 34234287Sdim#include "clang/AST/ExprObjC.h" 35249423Sdim#include "clang/Basic/CharInfo.h" 36234287Sdim#include "clang/Lex/Preprocessor.h" 37249423Sdim#include "clang/Sema/Initialization.h" 38249423Sdim#include "clang/Sema/ScopeInfo.h" 39239462Sdim#include "llvm/ADT/SmallString.h" 40234287Sdim 41234287Sdimusing namespace clang; 42234287Sdimusing namespace sema; 43234287Sdim 44234287Sdimnamespace { 45234287Sdim // Basically just a very focused copy of TreeTransform. 46234287Sdim template <class T> struct Rebuilder { 47234287Sdim Sema &S; 48234287Sdim Rebuilder(Sema &S) : S(S) {} 49234287Sdim 50234287Sdim T &getDerived() { return static_cast<T&>(*this); } 51234287Sdim 52234287Sdim Expr *rebuild(Expr *e) { 53234287Sdim // Fast path: nothing to look through. 54234287Sdim if (typename T::specific_type *specific 55234287Sdim = dyn_cast<typename T::specific_type>(e)) 56234287Sdim return getDerived().rebuildSpecific(specific); 57234287Sdim 58234287Sdim // Otherwise, we should look through and rebuild anything that 59234287Sdim // IgnoreParens would. 60234287Sdim 61234287Sdim if (ParenExpr *parens = dyn_cast<ParenExpr>(e)) { 62234287Sdim e = rebuild(parens->getSubExpr()); 63234287Sdim return new (S.Context) ParenExpr(parens->getLParen(), 64234287Sdim parens->getRParen(), 65234287Sdim e); 66234287Sdim } 67234287Sdim 68234287Sdim if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) { 69234287Sdim assert(uop->getOpcode() == UO_Extension); 70234287Sdim e = rebuild(uop->getSubExpr()); 71234287Sdim return new (S.Context) UnaryOperator(e, uop->getOpcode(), 72234287Sdim uop->getType(), 73234287Sdim uop->getValueKind(), 74234287Sdim uop->getObjectKind(), 75234287Sdim uop->getOperatorLoc()); 76234287Sdim } 77234287Sdim 78234287Sdim if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { 79234287Sdim assert(!gse->isResultDependent()); 80234287Sdim unsigned resultIndex = gse->getResultIndex(); 81234287Sdim unsigned numAssocs = gse->getNumAssocs(); 82234287Sdim 83234287Sdim SmallVector<Expr*, 8> assocs(numAssocs); 84234287Sdim SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); 85234287Sdim 86234287Sdim for (unsigned i = 0; i != numAssocs; ++i) { 87234287Sdim Expr *assoc = gse->getAssocExpr(i); 88234287Sdim if (i == resultIndex) assoc = rebuild(assoc); 89234287Sdim assocs[i] = assoc; 90234287Sdim assocTypes[i] = gse->getAssocTypeSourceInfo(i); 91234287Sdim } 92234287Sdim 93234287Sdim return new (S.Context) GenericSelectionExpr(S.Context, 94234287Sdim gse->getGenericLoc(), 95234287Sdim gse->getControllingExpr(), 96243830Sdim assocTypes, 97243830Sdim assocs, 98234287Sdim gse->getDefaultLoc(), 99234287Sdim gse->getRParenLoc(), 100234287Sdim gse->containsUnexpandedParameterPack(), 101234287Sdim resultIndex); 102234287Sdim } 103234287Sdim 104234287Sdim llvm_unreachable("bad expression to rebuild!"); 105234287Sdim } 106234287Sdim }; 107234287Sdim 108234287Sdim struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> { 109234287Sdim Expr *NewBase; 110234287Sdim ObjCPropertyRefRebuilder(Sema &S, Expr *newBase) 111234287Sdim : Rebuilder<ObjCPropertyRefRebuilder>(S), NewBase(newBase) {} 112234287Sdim 113234287Sdim typedef ObjCPropertyRefExpr specific_type; 114234287Sdim Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) { 115234287Sdim // Fortunately, the constraint that we're rebuilding something 116234287Sdim // with a base limits the number of cases here. 117249423Sdim assert(refExpr->isObjectReceiver()); 118234287Sdim 119234287Sdim if (refExpr->isExplicitProperty()) { 120234287Sdim return new (S.Context) 121234287Sdim ObjCPropertyRefExpr(refExpr->getExplicitProperty(), 122234287Sdim refExpr->getType(), refExpr->getValueKind(), 123234287Sdim refExpr->getObjectKind(), refExpr->getLocation(), 124234287Sdim NewBase); 125234287Sdim } 126234287Sdim return new (S.Context) 127234287Sdim ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(), 128234287Sdim refExpr->getImplicitPropertySetter(), 129234287Sdim refExpr->getType(), refExpr->getValueKind(), 130234287Sdim refExpr->getObjectKind(),refExpr->getLocation(), 131234287Sdim NewBase); 132234287Sdim } 133234287Sdim }; 134234287Sdim 135234287Sdim struct ObjCSubscriptRefRebuilder : Rebuilder<ObjCSubscriptRefRebuilder> { 136234287Sdim Expr *NewBase; 137234287Sdim Expr *NewKeyExpr; 138234287Sdim ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr) 139234287Sdim : Rebuilder<ObjCSubscriptRefRebuilder>(S), 140234287Sdim NewBase(newBase), NewKeyExpr(newKeyExpr) {} 141234287Sdim 142234287Sdim typedef ObjCSubscriptRefExpr specific_type; 143234287Sdim Expr *rebuildSpecific(ObjCSubscriptRefExpr *refExpr) { 144234287Sdim assert(refExpr->getBaseExpr()); 145234287Sdim assert(refExpr->getKeyExpr()); 146234287Sdim 147234287Sdim return new (S.Context) 148234287Sdim ObjCSubscriptRefExpr(NewBase, 149234287Sdim NewKeyExpr, 150234287Sdim refExpr->getType(), refExpr->getValueKind(), 151234287Sdim refExpr->getObjectKind(),refExpr->getAtIndexMethodDecl(), 152234287Sdim refExpr->setAtIndexMethodDecl(), 153234287Sdim refExpr->getRBracket()); 154234287Sdim } 155234287Sdim }; 156234287Sdim 157234287Sdim class PseudoOpBuilder { 158234287Sdim public: 159234287Sdim Sema &S; 160234287Sdim unsigned ResultIndex; 161234287Sdim SourceLocation GenericLoc; 162234287Sdim SmallVector<Expr *, 4> Semantics; 163234287Sdim 164234287Sdim PseudoOpBuilder(Sema &S, SourceLocation genericLoc) 165234287Sdim : S(S), ResultIndex(PseudoObjectExpr::NoResult), 166234287Sdim GenericLoc(genericLoc) {} 167234287Sdim 168234287Sdim virtual ~PseudoOpBuilder() {} 169234287Sdim 170234287Sdim /// Add a normal semantic expression. 171234287Sdim void addSemanticExpr(Expr *semantic) { 172234287Sdim Semantics.push_back(semantic); 173234287Sdim } 174234287Sdim 175234287Sdim /// Add the 'result' semantic expression. 176234287Sdim void addResultSemanticExpr(Expr *resultExpr) { 177234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 178234287Sdim ResultIndex = Semantics.size(); 179234287Sdim Semantics.push_back(resultExpr); 180234287Sdim } 181234287Sdim 182234287Sdim ExprResult buildRValueOperation(Expr *op); 183234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 184234287Sdim SourceLocation opLoc, 185234287Sdim BinaryOperatorKind opcode, 186234287Sdim Expr *LHS, Expr *RHS); 187234287Sdim ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 188234287Sdim UnaryOperatorKind opcode, 189234287Sdim Expr *op); 190234287Sdim 191243830Sdim virtual ExprResult complete(Expr *syntacticForm); 192234287Sdim 193234287Sdim OpaqueValueExpr *capture(Expr *op); 194234287Sdim OpaqueValueExpr *captureValueAsResult(Expr *op); 195234287Sdim 196234287Sdim void setResultToLastSemantic() { 197234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 198234287Sdim ResultIndex = Semantics.size() - 1; 199234287Sdim } 200234287Sdim 201234287Sdim /// Return true if assignments have a non-void result. 202243830Sdim bool CanCaptureValueOfType(QualType ty) { 203243830Sdim assert(!ty->isIncompleteType()); 204243830Sdim assert(!ty->isDependentType()); 205234287Sdim 206243830Sdim if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl()) 207243830Sdim return ClassDecl->isTriviallyCopyable(); 208243830Sdim return true; 209243830Sdim } 210243830Sdim 211234287Sdim virtual Expr *rebuildAndCaptureObject(Expr *) = 0; 212234287Sdim virtual ExprResult buildGet() = 0; 213234287Sdim virtual ExprResult buildSet(Expr *, SourceLocation, 214234287Sdim bool captureSetValueAsResult) = 0; 215234287Sdim }; 216234287Sdim 217243830Sdim /// A PseudoOpBuilder for Objective-C \@properties. 218234287Sdim class ObjCPropertyOpBuilder : public PseudoOpBuilder { 219234287Sdim ObjCPropertyRefExpr *RefExpr; 220234287Sdim ObjCPropertyRefExpr *SyntacticRefExpr; 221234287Sdim OpaqueValueExpr *InstanceReceiver; 222234287Sdim ObjCMethodDecl *Getter; 223234287Sdim 224234287Sdim ObjCMethodDecl *Setter; 225234287Sdim Selector SetterSelector; 226234982Sdim Selector GetterSelector; 227234287Sdim 228234287Sdim public: 229234287Sdim ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : 230234287Sdim PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), 231234287Sdim SyntacticRefExpr(0), InstanceReceiver(0), Getter(0), Setter(0) { 232234287Sdim } 233234287Sdim 234234287Sdim ExprResult buildRValueOperation(Expr *op); 235234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 236234287Sdim SourceLocation opLoc, 237234287Sdim BinaryOperatorKind opcode, 238234287Sdim Expr *LHS, Expr *RHS); 239234287Sdim ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 240234287Sdim UnaryOperatorKind opcode, 241234287Sdim Expr *op); 242234287Sdim 243234287Sdim bool tryBuildGetOfReference(Expr *op, ExprResult &result); 244239462Sdim bool findSetter(bool warn=true); 245234287Sdim bool findGetter(); 246234287Sdim 247234287Sdim Expr *rebuildAndCaptureObject(Expr *syntacticBase); 248234287Sdim ExprResult buildGet(); 249234287Sdim ExprResult buildSet(Expr *op, SourceLocation, bool); 250243830Sdim ExprResult complete(Expr *SyntacticForm); 251243830Sdim 252243830Sdim bool isWeakProperty() const; 253234287Sdim }; 254234287Sdim 255234287Sdim /// A PseudoOpBuilder for Objective-C array/dictionary indexing. 256234287Sdim class ObjCSubscriptOpBuilder : public PseudoOpBuilder { 257234287Sdim ObjCSubscriptRefExpr *RefExpr; 258234287Sdim OpaqueValueExpr *InstanceBase; 259234287Sdim OpaqueValueExpr *InstanceKey; 260234287Sdim ObjCMethodDecl *AtIndexGetter; 261234287Sdim Selector AtIndexGetterSelector; 262234287Sdim 263234287Sdim ObjCMethodDecl *AtIndexSetter; 264234287Sdim Selector AtIndexSetterSelector; 265234287Sdim 266234287Sdim public: 267234287Sdim ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) : 268234287Sdim PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), 269234287Sdim RefExpr(refExpr), 270234287Sdim InstanceBase(0), InstanceKey(0), 271234287Sdim AtIndexGetter(0), AtIndexSetter(0) { } 272234287Sdim 273234287Sdim ExprResult buildRValueOperation(Expr *op); 274234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 275234287Sdim SourceLocation opLoc, 276234287Sdim BinaryOperatorKind opcode, 277234287Sdim Expr *LHS, Expr *RHS); 278234287Sdim Expr *rebuildAndCaptureObject(Expr *syntacticBase); 279234287Sdim 280234287Sdim bool findAtIndexGetter(); 281234287Sdim bool findAtIndexSetter(); 282234287Sdim 283234287Sdim ExprResult buildGet(); 284234287Sdim ExprResult buildSet(Expr *op, SourceLocation, bool); 285234287Sdim }; 286234287Sdim 287234287Sdim} 288234287Sdim 289234287Sdim/// Capture the given expression in an OpaqueValueExpr. 290234287SdimOpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { 291234287Sdim // Make a new OVE whose source is the given expression. 292234287Sdim OpaqueValueExpr *captured = 293234287Sdim new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(), 294234287Sdim e->getValueKind(), e->getObjectKind(), 295234287Sdim e); 296234287Sdim 297234287Sdim // Make sure we bind that in the semantics. 298234287Sdim addSemanticExpr(captured); 299234287Sdim return captured; 300234287Sdim} 301234287Sdim 302234287Sdim/// Capture the given expression as the result of this pseudo-object 303234287Sdim/// operation. This routine is safe against expressions which may 304234287Sdim/// already be captured. 305234287Sdim/// 306243830Sdim/// \returns the captured expression, which will be the 307234287Sdim/// same as the input if the input was already captured 308234287SdimOpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { 309234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 310234287Sdim 311234287Sdim // If the expression hasn't already been captured, just capture it 312234287Sdim // and set the new semantic 313234287Sdim if (!isa<OpaqueValueExpr>(e)) { 314234287Sdim OpaqueValueExpr *cap = capture(e); 315234287Sdim setResultToLastSemantic(); 316234287Sdim return cap; 317234287Sdim } 318234287Sdim 319234287Sdim // Otherwise, it must already be one of our semantic expressions; 320234287Sdim // set ResultIndex to its index. 321234287Sdim unsigned index = 0; 322234287Sdim for (;; ++index) { 323234287Sdim assert(index < Semantics.size() && 324234287Sdim "captured expression not found in semantics!"); 325234287Sdim if (e == Semantics[index]) break; 326234287Sdim } 327234287Sdim ResultIndex = index; 328234287Sdim return cast<OpaqueValueExpr>(e); 329234287Sdim} 330234287Sdim 331234287Sdim/// The routine which creates the final PseudoObjectExpr. 332234287SdimExprResult PseudoOpBuilder::complete(Expr *syntactic) { 333234287Sdim return PseudoObjectExpr::Create(S.Context, syntactic, 334234287Sdim Semantics, ResultIndex); 335234287Sdim} 336234287Sdim 337234287Sdim/// The main skeleton for building an r-value operation. 338234287SdimExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) { 339234287Sdim Expr *syntacticBase = rebuildAndCaptureObject(op); 340234287Sdim 341234287Sdim ExprResult getExpr = buildGet(); 342234287Sdim if (getExpr.isInvalid()) return ExprError(); 343234287Sdim addResultSemanticExpr(getExpr.take()); 344234287Sdim 345234287Sdim return complete(syntacticBase); 346234287Sdim} 347234287Sdim 348234287Sdim/// The basic skeleton for building a simple or compound 349234287Sdim/// assignment operation. 350234287SdimExprResult 351234287SdimPseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, 352234287Sdim BinaryOperatorKind opcode, 353234287Sdim Expr *LHS, Expr *RHS) { 354234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 355234287Sdim 356234287Sdim Expr *syntacticLHS = rebuildAndCaptureObject(LHS); 357234287Sdim OpaqueValueExpr *capturedRHS = capture(RHS); 358234287Sdim 359234287Sdim Expr *syntactic; 360234287Sdim 361234287Sdim ExprResult result; 362234287Sdim if (opcode == BO_Assign) { 363234287Sdim result = capturedRHS; 364234287Sdim syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, 365234287Sdim opcode, capturedRHS->getType(), 366234287Sdim capturedRHS->getValueKind(), 367243830Sdim OK_Ordinary, opcLoc, false); 368234287Sdim } else { 369234287Sdim ExprResult opLHS = buildGet(); 370234287Sdim if (opLHS.isInvalid()) return ExprError(); 371234287Sdim 372234287Sdim // Build an ordinary, non-compound operation. 373234287Sdim BinaryOperatorKind nonCompound = 374234287Sdim BinaryOperator::getOpForCompoundAssignment(opcode); 375234287Sdim result = S.BuildBinOp(Sc, opcLoc, nonCompound, 376234287Sdim opLHS.take(), capturedRHS); 377234287Sdim if (result.isInvalid()) return ExprError(); 378234287Sdim 379234287Sdim syntactic = 380234287Sdim new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, 381234287Sdim result.get()->getType(), 382234287Sdim result.get()->getValueKind(), 383234287Sdim OK_Ordinary, 384234287Sdim opLHS.get()->getType(), 385234287Sdim result.get()->getType(), 386243830Sdim opcLoc, false); 387234287Sdim } 388234287Sdim 389234287Sdim // The result of the assignment, if not void, is the value set into 390234287Sdim // the l-value. 391243830Sdim result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true); 392234287Sdim if (result.isInvalid()) return ExprError(); 393234287Sdim addSemanticExpr(result.take()); 394234287Sdim 395234287Sdim return complete(syntactic); 396234287Sdim} 397234287Sdim 398234287Sdim/// The basic skeleton for building an increment or decrement 399234287Sdim/// operation. 400234287SdimExprResult 401234287SdimPseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 402234287Sdim UnaryOperatorKind opcode, 403234287Sdim Expr *op) { 404234287Sdim assert(UnaryOperator::isIncrementDecrementOp(opcode)); 405234287Sdim 406234287Sdim Expr *syntacticOp = rebuildAndCaptureObject(op); 407234287Sdim 408234287Sdim // Load the value. 409234287Sdim ExprResult result = buildGet(); 410234287Sdim if (result.isInvalid()) return ExprError(); 411234287Sdim 412234287Sdim QualType resultType = result.get()->getType(); 413234287Sdim 414234287Sdim // That's the postfix result. 415243830Sdim if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) { 416234287Sdim result = capture(result.take()); 417234287Sdim setResultToLastSemantic(); 418234287Sdim } 419234287Sdim 420234287Sdim // Add or subtract a literal 1. 421234287Sdim llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1); 422234287Sdim Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy, 423234287Sdim GenericLoc); 424234287Sdim 425234287Sdim if (UnaryOperator::isIncrementOp(opcode)) { 426234287Sdim result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one); 427234287Sdim } else { 428234287Sdim result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one); 429234287Sdim } 430234287Sdim if (result.isInvalid()) return ExprError(); 431234287Sdim 432234287Sdim // Store that back into the result. The value stored is the result 433234287Sdim // of a prefix operation. 434243830Sdim result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode)); 435234287Sdim if (result.isInvalid()) return ExprError(); 436234287Sdim addSemanticExpr(result.take()); 437234287Sdim 438234287Sdim UnaryOperator *syntactic = 439234287Sdim new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, 440234287Sdim VK_LValue, OK_Ordinary, opcLoc); 441234287Sdim return complete(syntactic); 442234287Sdim} 443234287Sdim 444234287Sdim 445234287Sdim//===----------------------------------------------------------------------===// 446234287Sdim// Objective-C @property and implicit property references 447234287Sdim//===----------------------------------------------------------------------===// 448234287Sdim 449234287Sdim/// Look up a method in the receiver type of an Objective-C property 450234287Sdim/// reference. 451234287Sdimstatic ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel, 452234287Sdim const ObjCPropertyRefExpr *PRE) { 453234287Sdim if (PRE->isObjectReceiver()) { 454234287Sdim const ObjCObjectPointerType *PT = 455234287Sdim PRE->getBase()->getType()->castAs<ObjCObjectPointerType>(); 456234287Sdim 457234287Sdim // Special case for 'self' in class method implementations. 458234287Sdim if (PT->isObjCClassType() && 459234287Sdim S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) { 460234287Sdim // This cast is safe because isSelfExpr is only true within 461234287Sdim // methods. 462234287Sdim ObjCMethodDecl *method = 463234287Sdim cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor()); 464234287Sdim return S.LookupMethodInObjectType(sel, 465234287Sdim S.Context.getObjCInterfaceType(method->getClassInterface()), 466234287Sdim /*instance*/ false); 467234287Sdim } 468234287Sdim 469234287Sdim return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 470234287Sdim } 471234287Sdim 472234287Sdim if (PRE->isSuperReceiver()) { 473234287Sdim if (const ObjCObjectPointerType *PT = 474234287Sdim PRE->getSuperReceiverType()->getAs<ObjCObjectPointerType>()) 475234287Sdim return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 476234287Sdim 477234287Sdim return S.LookupMethodInObjectType(sel, PRE->getSuperReceiverType(), false); 478234287Sdim } 479234287Sdim 480234287Sdim assert(PRE->isClassReceiver() && "Invalid expression"); 481234287Sdim QualType IT = S.Context.getObjCInterfaceType(PRE->getClassReceiver()); 482234287Sdim return S.LookupMethodInObjectType(sel, IT, false); 483234287Sdim} 484234287Sdim 485243830Sdimbool ObjCPropertyOpBuilder::isWeakProperty() const { 486243830Sdim QualType T; 487243830Sdim if (RefExpr->isExplicitProperty()) { 488243830Sdim const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); 489243830Sdim if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) 490243830Sdim return true; 491243830Sdim 492243830Sdim T = Prop->getType(); 493243830Sdim } else if (Getter) { 494243830Sdim T = Getter->getResultType(); 495243830Sdim } else { 496243830Sdim return false; 497243830Sdim } 498243830Sdim 499243830Sdim return T.getObjCLifetime() == Qualifiers::OCL_Weak; 500243830Sdim} 501243830Sdim 502234287Sdimbool ObjCPropertyOpBuilder::findGetter() { 503234287Sdim if (Getter) return true; 504234287Sdim 505234287Sdim // For implicit properties, just trust the lookup we already did. 506234287Sdim if (RefExpr->isImplicitProperty()) { 507234982Sdim if ((Getter = RefExpr->getImplicitPropertyGetter())) { 508234982Sdim GetterSelector = Getter->getSelector(); 509234982Sdim return true; 510234982Sdim } 511234982Sdim else { 512234982Sdim // Must build the getter selector the hard way. 513234982Sdim ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); 514234982Sdim assert(setter && "both setter and getter are null - cannot happen"); 515234982Sdim IdentifierInfo *setterName = 516234982Sdim setter->getSelector().getIdentifierInfoForSlot(0); 517234982Sdim const char *compStr = setterName->getNameStart(); 518234982Sdim compStr += 3; 519234982Sdim IdentifierInfo *getterName = &S.Context.Idents.get(compStr); 520234982Sdim GetterSelector = 521234982Sdim S.PP.getSelectorTable().getNullarySelector(getterName); 522234982Sdim return false; 523234982Sdim 524234982Sdim } 525234287Sdim } 526234287Sdim 527234287Sdim ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); 528234287Sdim Getter = LookupMethodInReceiverType(S, prop->getGetterName(), RefExpr); 529234287Sdim return (Getter != 0); 530234287Sdim} 531234287Sdim 532234287Sdim/// Try to find the most accurate setter declaration for the property 533234287Sdim/// reference. 534234287Sdim/// 535234287Sdim/// \return true if a setter was found, in which case Setter 536239462Sdimbool ObjCPropertyOpBuilder::findSetter(bool warn) { 537234287Sdim // For implicit properties, just trust the lookup we already did. 538234287Sdim if (RefExpr->isImplicitProperty()) { 539234287Sdim if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) { 540234287Sdim Setter = setter; 541234287Sdim SetterSelector = setter->getSelector(); 542234287Sdim return true; 543234287Sdim } else { 544234287Sdim IdentifierInfo *getterName = 545234287Sdim RefExpr->getImplicitPropertyGetter()->getSelector() 546234287Sdim .getIdentifierInfoForSlot(0); 547234287Sdim SetterSelector = 548234287Sdim SelectorTable::constructSetterName(S.PP.getIdentifierTable(), 549234287Sdim S.PP.getSelectorTable(), 550234287Sdim getterName); 551234287Sdim return false; 552234287Sdim } 553234287Sdim } 554234287Sdim 555234287Sdim // For explicit properties, this is more involved. 556234287Sdim ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); 557234287Sdim SetterSelector = prop->getSetterName(); 558234287Sdim 559234287Sdim // Do a normal method lookup first. 560234287Sdim if (ObjCMethodDecl *setter = 561234287Sdim LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { 562243830Sdim if (setter->isPropertyAccessor() && warn) 563239462Sdim if (const ObjCInterfaceDecl *IFace = 564239462Sdim dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) { 565239462Sdim const StringRef thisPropertyName(prop->getName()); 566249423Sdim // Try flipping the case of the first character. 567239462Sdim char front = thisPropertyName.front(); 568249423Sdim front = isLowercase(front) ? toUppercase(front) : toLowercase(front); 569239462Sdim SmallString<100> PropertyName = thisPropertyName; 570239462Sdim PropertyName[0] = front; 571239462Sdim IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); 572239462Sdim if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember)) 573239462Sdim if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { 574239462Sdim S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use) 575239462Sdim << prop->getName() << prop1->getName() << setter->getSelector(); 576239462Sdim S.Diag(prop->getLocation(), diag::note_property_declare); 577239462Sdim S.Diag(prop1->getLocation(), diag::note_property_declare); 578239462Sdim } 579239462Sdim } 580234287Sdim Setter = setter; 581234287Sdim return true; 582234287Sdim } 583234287Sdim 584234287Sdim // That can fail in the somewhat crazy situation that we're 585234287Sdim // type-checking a message send within the @interface declaration 586234287Sdim // that declared the @property. But it's not clear that that's 587234287Sdim // valuable to support. 588234287Sdim 589234287Sdim return false; 590234287Sdim} 591234287Sdim 592234287Sdim/// Capture the base object of an Objective-C property expression. 593234287SdimExpr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 594234287Sdim assert(InstanceReceiver == 0); 595234287Sdim 596234287Sdim // If we have a base, capture it in an OVE and rebuild the syntactic 597234287Sdim // form to use the OVE as its base. 598234287Sdim if (RefExpr->isObjectReceiver()) { 599234287Sdim InstanceReceiver = capture(RefExpr->getBase()); 600234287Sdim 601234287Sdim syntacticBase = 602234287Sdim ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase); 603234287Sdim } 604234287Sdim 605234287Sdim if (ObjCPropertyRefExpr * 606234287Sdim refE = dyn_cast<ObjCPropertyRefExpr>(syntacticBase->IgnoreParens())) 607234287Sdim SyntacticRefExpr = refE; 608234287Sdim 609234287Sdim return syntacticBase; 610234287Sdim} 611234287Sdim 612234287Sdim/// Load from an Objective-C property reference. 613234287SdimExprResult ObjCPropertyOpBuilder::buildGet() { 614234287Sdim findGetter(); 615234287Sdim assert(Getter); 616234287Sdim 617234287Sdim if (SyntacticRefExpr) 618234287Sdim SyntacticRefExpr->setIsMessagingGetter(); 619234287Sdim 620234287Sdim QualType receiverType; 621234287Sdim if (RefExpr->isClassReceiver()) { 622234287Sdim receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 623234287Sdim } else if (RefExpr->isSuperReceiver()) { 624234287Sdim receiverType = RefExpr->getSuperReceiverType(); 625234287Sdim } else { 626234287Sdim assert(InstanceReceiver); 627234287Sdim receiverType = InstanceReceiver->getType(); 628234287Sdim } 629234287Sdim 630234287Sdim // Build a message-send. 631234287Sdim ExprResult msg; 632234287Sdim if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 633234287Sdim assert(InstanceReceiver || RefExpr->isSuperReceiver()); 634234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, 635234287Sdim GenericLoc, Getter->getSelector(), 636234287Sdim Getter, MultiExprArg()); 637234287Sdim } else { 638234287Sdim msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), 639234287Sdim GenericLoc, 640234287Sdim Getter->getSelector(), Getter, 641234287Sdim MultiExprArg()); 642234287Sdim } 643234287Sdim return msg; 644234287Sdim} 645234287Sdim 646234287Sdim/// Store to an Objective-C property reference. 647234287Sdim/// 648243830Sdim/// \param captureSetValueAsResult If true, capture the actual 649234287Sdim/// value being set as the value of the property operation. 650234287SdimExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, 651234287Sdim bool captureSetValueAsResult) { 652239462Sdim bool hasSetter = findSetter(false); 653234287Sdim assert(hasSetter); (void) hasSetter; 654234287Sdim 655234287Sdim if (SyntacticRefExpr) 656234287Sdim SyntacticRefExpr->setIsMessagingSetter(); 657234287Sdim 658234287Sdim QualType receiverType; 659234287Sdim if (RefExpr->isClassReceiver()) { 660234287Sdim receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 661234287Sdim } else if (RefExpr->isSuperReceiver()) { 662234287Sdim receiverType = RefExpr->getSuperReceiverType(); 663234287Sdim } else { 664234287Sdim assert(InstanceReceiver); 665234287Sdim receiverType = InstanceReceiver->getType(); 666234287Sdim } 667234287Sdim 668234287Sdim // Use assignment constraints when possible; they give us better 669234287Sdim // diagnostics. "When possible" basically means anything except a 670234287Sdim // C++ class type. 671234287Sdim if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) { 672234287Sdim QualType paramType = (*Setter->param_begin())->getType(); 673234287Sdim if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) { 674234287Sdim ExprResult opResult = op; 675234287Sdim Sema::AssignConvertType assignResult 676234287Sdim = S.CheckSingleAssignmentConstraints(paramType, opResult); 677234287Sdim if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, 678234287Sdim op->getType(), opResult.get(), 679234287Sdim Sema::AA_Assigning)) 680234287Sdim return ExprError(); 681234287Sdim 682234287Sdim op = opResult.take(); 683234287Sdim assert(op && "successful assignment left argument invalid?"); 684234287Sdim } 685234287Sdim } 686234287Sdim 687234287Sdim // Arguments. 688234287Sdim Expr *args[] = { op }; 689234287Sdim 690234287Sdim // Build a message-send. 691234287Sdim ExprResult msg; 692234287Sdim if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 693234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, 694234287Sdim GenericLoc, SetterSelector, Setter, 695234287Sdim MultiExprArg(args, 1)); 696234287Sdim } else { 697234287Sdim msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), 698234287Sdim GenericLoc, 699234287Sdim SetterSelector, Setter, 700234287Sdim MultiExprArg(args, 1)); 701234287Sdim } 702234287Sdim 703234287Sdim if (!msg.isInvalid() && captureSetValueAsResult) { 704234287Sdim ObjCMessageExpr *msgExpr = 705234287Sdim cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); 706234287Sdim Expr *arg = msgExpr->getArg(0); 707243830Sdim if (CanCaptureValueOfType(arg->getType())) 708243830Sdim msgExpr->setArg(0, captureValueAsResult(arg)); 709234287Sdim } 710234287Sdim 711234287Sdim return msg; 712234287Sdim} 713234287Sdim 714234287Sdim/// @property-specific behavior for doing lvalue-to-rvalue conversion. 715234287SdimExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { 716234287Sdim // Explicit properties always have getters, but implicit ones don't. 717234287Sdim // Check that before proceeding. 718249423Sdim if (RefExpr->isImplicitProperty() && !RefExpr->getImplicitPropertyGetter()) { 719234287Sdim S.Diag(RefExpr->getLocation(), diag::err_getter_not_found) 720249423Sdim << RefExpr->getSourceRange(); 721234287Sdim return ExprError(); 722234287Sdim } 723234287Sdim 724234287Sdim ExprResult result = PseudoOpBuilder::buildRValueOperation(op); 725234287Sdim if (result.isInvalid()) return ExprError(); 726234287Sdim 727234287Sdim if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType()) 728234287Sdim S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(), 729234287Sdim Getter, RefExpr->getLocation()); 730234287Sdim 731234287Sdim // As a special case, if the method returns 'id', try to get 732234287Sdim // a better type from the property. 733234287Sdim if (RefExpr->isExplicitProperty() && result.get()->isRValue() && 734234287Sdim result.get()->getType()->isObjCIdType()) { 735234287Sdim QualType propType = RefExpr->getExplicitProperty()->getType(); 736234287Sdim if (const ObjCObjectPointerType *ptr 737234287Sdim = propType->getAs<ObjCObjectPointerType>()) { 738234287Sdim if (!ptr->isObjCIdType()) 739234287Sdim result = S.ImpCastExprToType(result.get(), propType, CK_BitCast); 740234287Sdim } 741234287Sdim } 742234287Sdim 743234287Sdim return result; 744234287Sdim} 745234287Sdim 746234287Sdim/// Try to build this as a call to a getter that returns a reference. 747234287Sdim/// 748234287Sdim/// \return true if it was possible, whether or not it actually 749234287Sdim/// succeeded 750234287Sdimbool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op, 751234287Sdim ExprResult &result) { 752234287Sdim if (!S.getLangOpts().CPlusPlus) return false; 753234287Sdim 754234287Sdim findGetter(); 755234287Sdim assert(Getter && "property has no setter and no getter!"); 756234287Sdim 757234287Sdim // Only do this if the getter returns an l-value reference type. 758234287Sdim QualType resultType = Getter->getResultType(); 759234287Sdim if (!resultType->isLValueReferenceType()) return false; 760234287Sdim 761234287Sdim result = buildRValueOperation(op); 762234287Sdim return true; 763234287Sdim} 764234287Sdim 765234287Sdim/// @property-specific behavior for doing assignments. 766234287SdimExprResult 767234287SdimObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc, 768234287Sdim SourceLocation opcLoc, 769234287Sdim BinaryOperatorKind opcode, 770234287Sdim Expr *LHS, Expr *RHS) { 771234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 772234287Sdim 773234287Sdim // If there's no setter, we have no choice but to try to assign to 774234287Sdim // the result of the getter. 775234287Sdim if (!findSetter()) { 776234287Sdim ExprResult result; 777234287Sdim if (tryBuildGetOfReference(LHS, result)) { 778234287Sdim if (result.isInvalid()) return ExprError(); 779234287Sdim return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS); 780234287Sdim } 781234287Sdim 782234287Sdim // Otherwise, it's an error. 783234287Sdim S.Diag(opcLoc, diag::err_nosetter_property_assignment) 784234287Sdim << unsigned(RefExpr->isImplicitProperty()) 785234287Sdim << SetterSelector 786234287Sdim << LHS->getSourceRange() << RHS->getSourceRange(); 787234287Sdim return ExprError(); 788234287Sdim } 789234287Sdim 790234287Sdim // If there is a setter, we definitely want to use it. 791234287Sdim 792234287Sdim // Verify that we can do a compound assignment. 793234287Sdim if (opcode != BO_Assign && !findGetter()) { 794234287Sdim S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment) 795234287Sdim << LHS->getSourceRange() << RHS->getSourceRange(); 796234287Sdim return ExprError(); 797234287Sdim } 798234287Sdim 799234287Sdim ExprResult result = 800234287Sdim PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); 801234287Sdim if (result.isInvalid()) return ExprError(); 802234287Sdim 803234287Sdim // Various warnings about property assignments in ARC. 804234287Sdim if (S.getLangOpts().ObjCAutoRefCount && InstanceReceiver) { 805234287Sdim S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS); 806234287Sdim S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); 807234287Sdim } 808234287Sdim 809234287Sdim return result; 810234287Sdim} 811234287Sdim 812234287Sdim/// @property-specific behavior for doing increments and decrements. 813234287SdimExprResult 814234287SdimObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 815234287Sdim UnaryOperatorKind opcode, 816234287Sdim Expr *op) { 817234287Sdim // If there's no setter, we have no choice but to try to assign to 818234287Sdim // the result of the getter. 819234287Sdim if (!findSetter()) { 820234287Sdim ExprResult result; 821234287Sdim if (tryBuildGetOfReference(op, result)) { 822234287Sdim if (result.isInvalid()) return ExprError(); 823234287Sdim return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take()); 824234287Sdim } 825234287Sdim 826234287Sdim // Otherwise, it's an error. 827234287Sdim S.Diag(opcLoc, diag::err_nosetter_property_incdec) 828234287Sdim << unsigned(RefExpr->isImplicitProperty()) 829234287Sdim << unsigned(UnaryOperator::isDecrementOp(opcode)) 830234287Sdim << SetterSelector 831234287Sdim << op->getSourceRange(); 832234287Sdim return ExprError(); 833234287Sdim } 834234287Sdim 835234287Sdim // If there is a setter, we definitely want to use it. 836234287Sdim 837234287Sdim // We also need a getter. 838234287Sdim if (!findGetter()) { 839234287Sdim assert(RefExpr->isImplicitProperty()); 840234287Sdim S.Diag(opcLoc, diag::err_nogetter_property_incdec) 841234287Sdim << unsigned(UnaryOperator::isDecrementOp(opcode)) 842234982Sdim << GetterSelector 843234287Sdim << op->getSourceRange(); 844234287Sdim return ExprError(); 845234287Sdim } 846234287Sdim 847234287Sdim return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op); 848234287Sdim} 849234287Sdim 850243830SdimExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { 851243830Sdim if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) { 852243830Sdim DiagnosticsEngine::Level Level = 853243830Sdim S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, 854243830Sdim SyntacticForm->getLocStart()); 855243830Sdim if (Level != DiagnosticsEngine::Ignored) 856243830Sdim S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr, 857243830Sdim SyntacticRefExpr->isMessagingGetter()); 858243830Sdim } 859243830Sdim 860243830Sdim return PseudoOpBuilder::complete(SyntacticForm); 861243830Sdim} 862243830Sdim 863234287Sdim// ObjCSubscript build stuff. 864234287Sdim// 865234287Sdim 866234287Sdim/// objective-c subscripting-specific behavior for doing lvalue-to-rvalue 867234287Sdim/// conversion. 868234287Sdim/// FIXME. Remove this routine if it is proven that no additional 869234287Sdim/// specifity is needed. 870234287SdimExprResult ObjCSubscriptOpBuilder::buildRValueOperation(Expr *op) { 871234287Sdim ExprResult result = PseudoOpBuilder::buildRValueOperation(op); 872234287Sdim if (result.isInvalid()) return ExprError(); 873234287Sdim return result; 874234287Sdim} 875234287Sdim 876234287Sdim/// objective-c subscripting-specific behavior for doing assignments. 877234287SdimExprResult 878234287SdimObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc, 879234287Sdim SourceLocation opcLoc, 880234287Sdim BinaryOperatorKind opcode, 881234287Sdim Expr *LHS, Expr *RHS) { 882234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 883234287Sdim // There must be a method to do the Index'ed assignment. 884234287Sdim if (!findAtIndexSetter()) 885234287Sdim return ExprError(); 886234287Sdim 887234287Sdim // Verify that we can do a compound assignment. 888234287Sdim if (opcode != BO_Assign && !findAtIndexGetter()) 889234287Sdim return ExprError(); 890234287Sdim 891234287Sdim ExprResult result = 892234287Sdim PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); 893234287Sdim if (result.isInvalid()) return ExprError(); 894234287Sdim 895234287Sdim // Various warnings about objc Index'ed assignments in ARC. 896234287Sdim if (S.getLangOpts().ObjCAutoRefCount && InstanceBase) { 897234287Sdim S.checkRetainCycles(InstanceBase->getSourceExpr(), RHS); 898234287Sdim S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); 899234287Sdim } 900234287Sdim 901234287Sdim return result; 902234287Sdim} 903234287Sdim 904234287Sdim/// Capture the base object of an Objective-C Index'ed expression. 905234287SdimExpr *ObjCSubscriptOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 906234287Sdim assert(InstanceBase == 0); 907234287Sdim 908234287Sdim // Capture base expression in an OVE and rebuild the syntactic 909234287Sdim // form to use the OVE as its base expression. 910234287Sdim InstanceBase = capture(RefExpr->getBaseExpr()); 911234287Sdim InstanceKey = capture(RefExpr->getKeyExpr()); 912234287Sdim 913234287Sdim syntacticBase = 914234287Sdim ObjCSubscriptRefRebuilder(S, InstanceBase, 915234287Sdim InstanceKey).rebuild(syntacticBase); 916234287Sdim 917234287Sdim return syntacticBase; 918234287Sdim} 919234287Sdim 920234287Sdim/// CheckSubscriptingKind - This routine decide what type 921234287Sdim/// of indexing represented by "FromE" is being done. 922234287SdimSema::ObjCSubscriptKind 923234287Sdim Sema::CheckSubscriptingKind(Expr *FromE) { 924234287Sdim // If the expression already has integral or enumeration type, we're golden. 925234287Sdim QualType T = FromE->getType(); 926234287Sdim if (T->isIntegralOrEnumerationType()) 927234287Sdim return OS_Array; 928234287Sdim 929234287Sdim // If we don't have a class type in C++, there's no way we can get an 930234287Sdim // expression of integral or enumeration type. 931234287Sdim const RecordType *RecordTy = T->getAs<RecordType>(); 932234287Sdim if (!RecordTy && T->isObjCObjectPointerType()) 933234287Sdim // All other scalar cases are assumed to be dictionary indexing which 934234287Sdim // caller handles, with diagnostics if needed. 935234287Sdim return OS_Dictionary; 936234287Sdim if (!getLangOpts().CPlusPlus || 937234287Sdim !RecordTy || RecordTy->isIncompleteType()) { 938234287Sdim // No indexing can be done. Issue diagnostics and quit. 939234287Sdim const Expr *IndexExpr = FromE->IgnoreParenImpCasts(); 940234287Sdim if (isa<StringLiteral>(IndexExpr)) 941234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_pointer) 942234287Sdim << T << FixItHint::CreateInsertion(FromE->getExprLoc(), "@"); 943234287Sdim else 944234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) 945234287Sdim << T; 946234287Sdim return OS_Error; 947234287Sdim } 948234287Sdim 949234287Sdim // We must have a complete class type. 950234287Sdim if (RequireCompleteType(FromE->getExprLoc(), T, 951239462Sdim diag::err_objc_index_incomplete_class_type, FromE)) 952234287Sdim return OS_Error; 953234287Sdim 954234287Sdim // Look for a conversion to an integral, enumeration type, or 955234287Sdim // objective-C pointer type. 956234287Sdim UnresolvedSet<4> ViableConversions; 957234287Sdim UnresolvedSet<4> ExplicitConversions; 958249423Sdim std::pair<CXXRecordDecl::conversion_iterator, 959249423Sdim CXXRecordDecl::conversion_iterator> Conversions 960234287Sdim = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions(); 961234287Sdim 962234287Sdim int NoIntegrals=0, NoObjCIdPointers=0; 963234287Sdim SmallVector<CXXConversionDecl *, 4> ConversionDecls; 964234287Sdim 965249423Sdim for (CXXRecordDecl::conversion_iterator 966249423Sdim I = Conversions.first, E = Conversions.second; I != E; ++I) { 967234287Sdim if (CXXConversionDecl *Conversion 968234287Sdim = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) { 969234287Sdim QualType CT = Conversion->getConversionType().getNonReferenceType(); 970234287Sdim if (CT->isIntegralOrEnumerationType()) { 971234287Sdim ++NoIntegrals; 972234287Sdim ConversionDecls.push_back(Conversion); 973234287Sdim } 974234287Sdim else if (CT->isObjCIdType() ||CT->isBlockPointerType()) { 975234287Sdim ++NoObjCIdPointers; 976234287Sdim ConversionDecls.push_back(Conversion); 977234287Sdim } 978234287Sdim } 979234287Sdim } 980234287Sdim if (NoIntegrals ==1 && NoObjCIdPointers == 0) 981234287Sdim return OS_Array; 982234287Sdim if (NoIntegrals == 0 && NoObjCIdPointers == 1) 983234287Sdim return OS_Dictionary; 984234287Sdim if (NoIntegrals == 0 && NoObjCIdPointers == 0) { 985234287Sdim // No conversion function was found. Issue diagnostic and return. 986234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) 987234287Sdim << FromE->getType(); 988234287Sdim return OS_Error; 989234287Sdim } 990234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_multiple_subscript_type_conversion) 991234287Sdim << FromE->getType(); 992234287Sdim for (unsigned int i = 0; i < ConversionDecls.size(); i++) 993234287Sdim Diag(ConversionDecls[i]->getLocation(), diag::not_conv_function_declared_at); 994234287Sdim 995234287Sdim return OS_Error; 996234287Sdim} 997234287Sdim 998239462Sdim/// CheckKeyForObjCARCConversion - This routine suggests bridge casting of CF 999239462Sdim/// objects used as dictionary subscript key objects. 1000239462Sdimstatic void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT, 1001239462Sdim Expr *Key) { 1002239462Sdim if (ContainerT.isNull()) 1003239462Sdim return; 1004239462Sdim // dictionary subscripting. 1005239462Sdim // - (id)objectForKeyedSubscript:(id)key; 1006239462Sdim IdentifierInfo *KeyIdents[] = { 1007239462Sdim &S.Context.Idents.get("objectForKeyedSubscript") 1008239462Sdim }; 1009239462Sdim Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1010239462Sdim ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT, 1011239462Sdim true /*instance*/); 1012239462Sdim if (!Getter) 1013239462Sdim return; 1014239462Sdim QualType T = Getter->param_begin()[0]->getType(); 1015239462Sdim S.CheckObjCARCConversion(Key->getSourceRange(), 1016239462Sdim T, Key, Sema::CCK_ImplicitConversion); 1017239462Sdim} 1018239462Sdim 1019234287Sdimbool ObjCSubscriptOpBuilder::findAtIndexGetter() { 1020234287Sdim if (AtIndexGetter) 1021234287Sdim return true; 1022234287Sdim 1023234287Sdim Expr *BaseExpr = RefExpr->getBaseExpr(); 1024234287Sdim QualType BaseT = BaseExpr->getType(); 1025234287Sdim 1026234287Sdim QualType ResultType; 1027234287Sdim if (const ObjCObjectPointerType *PTy = 1028234287Sdim BaseT->getAs<ObjCObjectPointerType>()) { 1029234287Sdim ResultType = PTy->getPointeeType(); 1030234287Sdim if (const ObjCObjectType *iQFaceTy = 1031234287Sdim ResultType->getAsObjCQualifiedInterfaceType()) 1032234287Sdim ResultType = iQFaceTy->getBaseType(); 1033234287Sdim } 1034234287Sdim Sema::ObjCSubscriptKind Res = 1035234287Sdim S.CheckSubscriptingKind(RefExpr->getKeyExpr()); 1036239462Sdim if (Res == Sema::OS_Error) { 1037239462Sdim if (S.getLangOpts().ObjCAutoRefCount) 1038239462Sdim CheckKeyForObjCARCConversion(S, ResultType, 1039239462Sdim RefExpr->getKeyExpr()); 1040234287Sdim return false; 1041239462Sdim } 1042234287Sdim bool arrayRef = (Res == Sema::OS_Array); 1043234287Sdim 1044234287Sdim if (ResultType.isNull()) { 1045234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) 1046234287Sdim << BaseExpr->getType() << arrayRef; 1047234287Sdim return false; 1048234287Sdim } 1049234287Sdim if (!arrayRef) { 1050234287Sdim // dictionary subscripting. 1051234287Sdim // - (id)objectForKeyedSubscript:(id)key; 1052234287Sdim IdentifierInfo *KeyIdents[] = { 1053234287Sdim &S.Context.Idents.get("objectForKeyedSubscript") 1054234287Sdim }; 1055234287Sdim AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1056234287Sdim } 1057234287Sdim else { 1058234287Sdim // - (id)objectAtIndexedSubscript:(size_t)index; 1059234287Sdim IdentifierInfo *KeyIdents[] = { 1060234287Sdim &S.Context.Idents.get("objectAtIndexedSubscript") 1061234287Sdim }; 1062234287Sdim 1063234287Sdim AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1064234287Sdim } 1065234287Sdim 1066234287Sdim AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType, 1067234287Sdim true /*instance*/); 1068234287Sdim bool receiverIdType = (BaseT->isObjCIdType() || 1069234287Sdim BaseT->isObjCQualifiedIdType()); 1070234287Sdim 1071234287Sdim if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { 1072234287Sdim AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), 1073234287Sdim SourceLocation(), AtIndexGetterSelector, 1074234287Sdim S.Context.getObjCIdType() /*ReturnType*/, 1075234287Sdim 0 /*TypeSourceInfo */, 1076234287Sdim S.Context.getTranslationUnitDecl(), 1077234287Sdim true /*Instance*/, false/*isVariadic*/, 1078243830Sdim /*isPropertyAccessor=*/false, 1079234287Sdim /*isImplicitlyDeclared=*/true, /*isDefined=*/false, 1080234287Sdim ObjCMethodDecl::Required, 1081234287Sdim false); 1082234287Sdim ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, 1083234287Sdim SourceLocation(), SourceLocation(), 1084234287Sdim arrayRef ? &S.Context.Idents.get("index") 1085234287Sdim : &S.Context.Idents.get("key"), 1086234287Sdim arrayRef ? S.Context.UnsignedLongTy 1087234287Sdim : S.Context.getObjCIdType(), 1088234287Sdim /*TInfo=*/0, 1089234287Sdim SC_None, 1090234287Sdim 0); 1091234287Sdim AtIndexGetter->setMethodParams(S.Context, Argument, 1092234287Sdim ArrayRef<SourceLocation>()); 1093234287Sdim } 1094234287Sdim 1095234287Sdim if (!AtIndexGetter) { 1096234287Sdim if (!receiverIdType) { 1097234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) 1098234287Sdim << BaseExpr->getType() << 0 << arrayRef; 1099234287Sdim return false; 1100234287Sdim } 1101234287Sdim AtIndexGetter = 1102234287Sdim S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector, 1103234287Sdim RefExpr->getSourceRange(), 1104234287Sdim true, false); 1105234287Sdim } 1106234287Sdim 1107234287Sdim if (AtIndexGetter) { 1108234287Sdim QualType T = AtIndexGetter->param_begin()[0]->getType(); 1109234287Sdim if ((arrayRef && !T->isIntegralOrEnumerationType()) || 1110234287Sdim (!arrayRef && !T->isObjCObjectPointerType())) { 1111234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1112234287Sdim arrayRef ? diag::err_objc_subscript_index_type 1113234287Sdim : diag::err_objc_subscript_key_type) << T; 1114234287Sdim S.Diag(AtIndexGetter->param_begin()[0]->getLocation(), 1115234287Sdim diag::note_parameter_type) << T; 1116234287Sdim return false; 1117234287Sdim } 1118234287Sdim QualType R = AtIndexGetter->getResultType(); 1119234287Sdim if (!R->isObjCObjectPointerType()) { 1120234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1121234287Sdim diag::err_objc_indexing_method_result_type) << R << arrayRef; 1122234287Sdim S.Diag(AtIndexGetter->getLocation(), diag::note_method_declared_at) << 1123234287Sdim AtIndexGetter->getDeclName(); 1124234287Sdim } 1125234287Sdim } 1126234287Sdim return true; 1127234287Sdim} 1128234287Sdim 1129234287Sdimbool ObjCSubscriptOpBuilder::findAtIndexSetter() { 1130234287Sdim if (AtIndexSetter) 1131234287Sdim return true; 1132234287Sdim 1133234287Sdim Expr *BaseExpr = RefExpr->getBaseExpr(); 1134234287Sdim QualType BaseT = BaseExpr->getType(); 1135234287Sdim 1136234287Sdim QualType ResultType; 1137234287Sdim if (const ObjCObjectPointerType *PTy = 1138234287Sdim BaseT->getAs<ObjCObjectPointerType>()) { 1139234287Sdim ResultType = PTy->getPointeeType(); 1140234287Sdim if (const ObjCObjectType *iQFaceTy = 1141234287Sdim ResultType->getAsObjCQualifiedInterfaceType()) 1142234287Sdim ResultType = iQFaceTy->getBaseType(); 1143234287Sdim } 1144234287Sdim 1145234287Sdim Sema::ObjCSubscriptKind Res = 1146234287Sdim S.CheckSubscriptingKind(RefExpr->getKeyExpr()); 1147239462Sdim if (Res == Sema::OS_Error) { 1148239462Sdim if (S.getLangOpts().ObjCAutoRefCount) 1149239462Sdim CheckKeyForObjCARCConversion(S, ResultType, 1150239462Sdim RefExpr->getKeyExpr()); 1151234287Sdim return false; 1152239462Sdim } 1153234287Sdim bool arrayRef = (Res == Sema::OS_Array); 1154234287Sdim 1155234287Sdim if (ResultType.isNull()) { 1156234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) 1157234287Sdim << BaseExpr->getType() << arrayRef; 1158234287Sdim return false; 1159234287Sdim } 1160234287Sdim 1161234287Sdim if (!arrayRef) { 1162234287Sdim // dictionary subscripting. 1163234287Sdim // - (void)setObject:(id)object forKeyedSubscript:(id)key; 1164234287Sdim IdentifierInfo *KeyIdents[] = { 1165234287Sdim &S.Context.Idents.get("setObject"), 1166234287Sdim &S.Context.Idents.get("forKeyedSubscript") 1167234287Sdim }; 1168234287Sdim AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); 1169234287Sdim } 1170234287Sdim else { 1171234287Sdim // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; 1172234287Sdim IdentifierInfo *KeyIdents[] = { 1173234287Sdim &S.Context.Idents.get("setObject"), 1174234287Sdim &S.Context.Idents.get("atIndexedSubscript") 1175234287Sdim }; 1176234287Sdim AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); 1177234287Sdim } 1178234287Sdim AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, 1179234287Sdim true /*instance*/); 1180234287Sdim 1181234287Sdim bool receiverIdType = (BaseT->isObjCIdType() || 1182234287Sdim BaseT->isObjCQualifiedIdType()); 1183234287Sdim 1184234287Sdim if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) { 1185234287Sdim TypeSourceInfo *ResultTInfo = 0; 1186234287Sdim QualType ReturnType = S.Context.VoidTy; 1187234287Sdim AtIndexSetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), 1188234287Sdim SourceLocation(), AtIndexSetterSelector, 1189234287Sdim ReturnType, 1190234287Sdim ResultTInfo, 1191234287Sdim S.Context.getTranslationUnitDecl(), 1192234287Sdim true /*Instance*/, false/*isVariadic*/, 1193243830Sdim /*isPropertyAccessor=*/false, 1194234287Sdim /*isImplicitlyDeclared=*/true, /*isDefined=*/false, 1195234287Sdim ObjCMethodDecl::Required, 1196234287Sdim false); 1197234287Sdim SmallVector<ParmVarDecl *, 2> Params; 1198234287Sdim ParmVarDecl *object = ParmVarDecl::Create(S.Context, AtIndexSetter, 1199234287Sdim SourceLocation(), SourceLocation(), 1200234287Sdim &S.Context.Idents.get("object"), 1201234287Sdim S.Context.getObjCIdType(), 1202234287Sdim /*TInfo=*/0, 1203234287Sdim SC_None, 1204234287Sdim 0); 1205234287Sdim Params.push_back(object); 1206234287Sdim ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter, 1207234287Sdim SourceLocation(), SourceLocation(), 1208234287Sdim arrayRef ? &S.Context.Idents.get("index") 1209234287Sdim : &S.Context.Idents.get("key"), 1210234287Sdim arrayRef ? S.Context.UnsignedLongTy 1211234287Sdim : S.Context.getObjCIdType(), 1212234287Sdim /*TInfo=*/0, 1213234287Sdim SC_None, 1214234287Sdim 0); 1215234287Sdim Params.push_back(key); 1216234287Sdim AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>()); 1217234287Sdim } 1218234287Sdim 1219234287Sdim if (!AtIndexSetter) { 1220234287Sdim if (!receiverIdType) { 1221234287Sdim S.Diag(BaseExpr->getExprLoc(), 1222234287Sdim diag::err_objc_subscript_method_not_found) 1223234287Sdim << BaseExpr->getType() << 1 << arrayRef; 1224234287Sdim return false; 1225234287Sdim } 1226234287Sdim AtIndexSetter = 1227234287Sdim S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector, 1228234287Sdim RefExpr->getSourceRange(), 1229234287Sdim true, false); 1230234287Sdim } 1231234287Sdim 1232234287Sdim bool err = false; 1233234287Sdim if (AtIndexSetter && arrayRef) { 1234234287Sdim QualType T = AtIndexSetter->param_begin()[1]->getType(); 1235234287Sdim if (!T->isIntegralOrEnumerationType()) { 1236234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1237234287Sdim diag::err_objc_subscript_index_type) << T; 1238234287Sdim S.Diag(AtIndexSetter->param_begin()[1]->getLocation(), 1239234287Sdim diag::note_parameter_type) << T; 1240234287Sdim err = true; 1241234287Sdim } 1242234287Sdim T = AtIndexSetter->param_begin()[0]->getType(); 1243234287Sdim if (!T->isObjCObjectPointerType()) { 1244234287Sdim S.Diag(RefExpr->getBaseExpr()->getExprLoc(), 1245234287Sdim diag::err_objc_subscript_object_type) << T << arrayRef; 1246234287Sdim S.Diag(AtIndexSetter->param_begin()[0]->getLocation(), 1247234287Sdim diag::note_parameter_type) << T; 1248234287Sdim err = true; 1249234287Sdim } 1250234287Sdim } 1251234287Sdim else if (AtIndexSetter && !arrayRef) 1252234287Sdim for (unsigned i=0; i <2; i++) { 1253234287Sdim QualType T = AtIndexSetter->param_begin()[i]->getType(); 1254234287Sdim if (!T->isObjCObjectPointerType()) { 1255234287Sdim if (i == 1) 1256234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1257234287Sdim diag::err_objc_subscript_key_type) << T; 1258234287Sdim else 1259234287Sdim S.Diag(RefExpr->getBaseExpr()->getExprLoc(), 1260234287Sdim diag::err_objc_subscript_dic_object_type) << T; 1261234287Sdim S.Diag(AtIndexSetter->param_begin()[i]->getLocation(), 1262234287Sdim diag::note_parameter_type) << T; 1263234287Sdim err = true; 1264234287Sdim } 1265234287Sdim } 1266234287Sdim 1267234287Sdim return !err; 1268234287Sdim} 1269234287Sdim 1270234287Sdim// Get the object at "Index" position in the container. 1271234287Sdim// [BaseExpr objectAtIndexedSubscript : IndexExpr]; 1272234287SdimExprResult ObjCSubscriptOpBuilder::buildGet() { 1273234287Sdim if (!findAtIndexGetter()) 1274234287Sdim return ExprError(); 1275234287Sdim 1276234287Sdim QualType receiverType = InstanceBase->getType(); 1277234287Sdim 1278234287Sdim // Build a message-send. 1279234287Sdim ExprResult msg; 1280234287Sdim Expr *Index = InstanceKey; 1281234287Sdim 1282234287Sdim // Arguments. 1283234287Sdim Expr *args[] = { Index }; 1284234287Sdim assert(InstanceBase); 1285234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, 1286234287Sdim GenericLoc, 1287234287Sdim AtIndexGetterSelector, AtIndexGetter, 1288234287Sdim MultiExprArg(args, 1)); 1289234287Sdim return msg; 1290234287Sdim} 1291234287Sdim 1292234287Sdim/// Store into the container the "op" object at "Index"'ed location 1293234287Sdim/// by building this messaging expression: 1294234287Sdim/// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; 1295243830Sdim/// \param captureSetValueAsResult If true, capture the actual 1296234287Sdim/// value being set as the value of the property operation. 1297234287SdimExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, 1298234287Sdim bool captureSetValueAsResult) { 1299234287Sdim if (!findAtIndexSetter()) 1300234287Sdim return ExprError(); 1301234287Sdim 1302234287Sdim QualType receiverType = InstanceBase->getType(); 1303234287Sdim Expr *Index = InstanceKey; 1304234287Sdim 1305234287Sdim // Arguments. 1306234287Sdim Expr *args[] = { op, Index }; 1307234287Sdim 1308234287Sdim // Build a message-send. 1309234287Sdim ExprResult msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, 1310234287Sdim GenericLoc, 1311234287Sdim AtIndexSetterSelector, 1312234287Sdim AtIndexSetter, 1313234287Sdim MultiExprArg(args, 2)); 1314234287Sdim 1315234287Sdim if (!msg.isInvalid() && captureSetValueAsResult) { 1316234287Sdim ObjCMessageExpr *msgExpr = 1317234287Sdim cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); 1318234287Sdim Expr *arg = msgExpr->getArg(0); 1319243830Sdim if (CanCaptureValueOfType(arg->getType())) 1320243830Sdim msgExpr->setArg(0, captureValueAsResult(arg)); 1321234287Sdim } 1322234287Sdim 1323234287Sdim return msg; 1324234287Sdim} 1325234287Sdim 1326234287Sdim//===----------------------------------------------------------------------===// 1327234287Sdim// General Sema routines. 1328234287Sdim//===----------------------------------------------------------------------===// 1329234287Sdim 1330234287SdimExprResult Sema::checkPseudoObjectRValue(Expr *E) { 1331234287Sdim Expr *opaqueRef = E->IgnoreParens(); 1332234287Sdim if (ObjCPropertyRefExpr *refExpr 1333234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1334234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1335234287Sdim return builder.buildRValueOperation(E); 1336234287Sdim } 1337234287Sdim else if (ObjCSubscriptRefExpr *refExpr 1338234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1339234287Sdim ObjCSubscriptOpBuilder builder(*this, refExpr); 1340234287Sdim return builder.buildRValueOperation(E); 1341234287Sdim } else { 1342234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1343234287Sdim } 1344234287Sdim} 1345234287Sdim 1346234287Sdim/// Check an increment or decrement of a pseudo-object expression. 1347234287SdimExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, 1348234287Sdim UnaryOperatorKind opcode, Expr *op) { 1349234287Sdim // Do nothing if the operand is dependent. 1350234287Sdim if (op->isTypeDependent()) 1351234287Sdim return new (Context) UnaryOperator(op, opcode, Context.DependentTy, 1352234287Sdim VK_RValue, OK_Ordinary, opcLoc); 1353234287Sdim 1354234287Sdim assert(UnaryOperator::isIncrementDecrementOp(opcode)); 1355234287Sdim Expr *opaqueRef = op->IgnoreParens(); 1356234287Sdim if (ObjCPropertyRefExpr *refExpr 1357234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1358234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1359234287Sdim return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); 1360234287Sdim } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) { 1361234287Sdim Diag(opcLoc, diag::err_illegal_container_subscripting_op); 1362234287Sdim return ExprError(); 1363234287Sdim } else { 1364234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1365234287Sdim } 1366234287Sdim} 1367234287Sdim 1368234287SdimExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, 1369234287Sdim BinaryOperatorKind opcode, 1370234287Sdim Expr *LHS, Expr *RHS) { 1371234287Sdim // Do nothing if either argument is dependent. 1372234287Sdim if (LHS->isTypeDependent() || RHS->isTypeDependent()) 1373234287Sdim return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, 1374243830Sdim VK_RValue, OK_Ordinary, opcLoc, false); 1375234287Sdim 1376234287Sdim // Filter out non-overload placeholder types in the RHS. 1377234287Sdim if (RHS->getType()->isNonOverloadPlaceholderType()) { 1378234287Sdim ExprResult result = CheckPlaceholderExpr(RHS); 1379234287Sdim if (result.isInvalid()) return ExprError(); 1380234287Sdim RHS = result.take(); 1381234287Sdim } 1382234287Sdim 1383234287Sdim Expr *opaqueRef = LHS->IgnoreParens(); 1384234287Sdim if (ObjCPropertyRefExpr *refExpr 1385234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1386234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1387234287Sdim return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 1388234287Sdim } else if (ObjCSubscriptRefExpr *refExpr 1389234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1390234287Sdim ObjCSubscriptOpBuilder builder(*this, refExpr); 1391234287Sdim return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 1392234287Sdim } else { 1393234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1394234287Sdim } 1395234287Sdim} 1396234287Sdim 1397234287Sdim/// Given a pseudo-object reference, rebuild it without the opaque 1398234287Sdim/// values. Basically, undo the behavior of rebuildAndCaptureObject. 1399234287Sdim/// This should never operate in-place. 1400234287Sdimstatic Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { 1401234287Sdim Expr *opaqueRef = E->IgnoreParens(); 1402234287Sdim if (ObjCPropertyRefExpr *refExpr 1403234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1404234982Sdim // Class and super property references don't have opaque values in them. 1405234982Sdim if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) 1406234982Sdim return E; 1407234982Sdim 1408234982Sdim assert(refExpr->isObjectReceiver() && "Unknown receiver kind?"); 1409234287Sdim OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase()); 1410234287Sdim return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); 1411234287Sdim } else if (ObjCSubscriptRefExpr *refExpr 1412234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1413234287Sdim OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr()); 1414234287Sdim OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr()); 1415234287Sdim return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), 1416234287Sdim keyOVE->getSourceExpr()).rebuild(E); 1417234287Sdim } else { 1418234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1419234287Sdim } 1420234287Sdim} 1421234287Sdim 1422234287Sdim/// Given a pseudo-object expression, recreate what it looks like 1423234287Sdim/// syntactically without the attendant OpaqueValueExprs. 1424234287Sdim/// 1425234287Sdim/// This is a hack which should be removed when TreeTransform is 1426234287Sdim/// capable of rebuilding a tree without stripping implicit 1427234287Sdim/// operations. 1428234287SdimExpr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { 1429234287Sdim Expr *syntax = E->getSyntacticForm(); 1430234287Sdim if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { 1431234287Sdim Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); 1432234287Sdim return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), 1433234287Sdim uop->getValueKind(), uop->getObjectKind(), 1434234287Sdim uop->getOperatorLoc()); 1435234287Sdim } else if (CompoundAssignOperator *cop 1436234287Sdim = dyn_cast<CompoundAssignOperator>(syntax)) { 1437234287Sdim Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); 1438234287Sdim Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); 1439234287Sdim return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), 1440234287Sdim cop->getType(), 1441234287Sdim cop->getValueKind(), 1442234287Sdim cop->getObjectKind(), 1443234287Sdim cop->getComputationLHSType(), 1444234287Sdim cop->getComputationResultType(), 1445243830Sdim cop->getOperatorLoc(), false); 1446234287Sdim } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { 1447234287Sdim Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); 1448234287Sdim Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); 1449234287Sdim return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), 1450234287Sdim bop->getType(), bop->getValueKind(), 1451234287Sdim bop->getObjectKind(), 1452243830Sdim bop->getOperatorLoc(), false); 1453234287Sdim } else { 1454234287Sdim assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); 1455234287Sdim return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); 1456234287Sdim } 1457234287Sdim} 1458