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 104263508Sdim if (ChooseExpr *ce = dyn_cast<ChooseExpr>(e)) { 105263508Sdim assert(!ce->isConditionDependent()); 106263508Sdim 107263508Sdim Expr *LHS = ce->getLHS(), *RHS = ce->getRHS(); 108263508Sdim Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS : RHS; 109263508Sdim rebuiltExpr = rebuild(rebuiltExpr); 110263508Sdim 111263508Sdim return new (S.Context) ChooseExpr(ce->getBuiltinLoc(), 112263508Sdim ce->getCond(), 113263508Sdim LHS, RHS, 114263508Sdim rebuiltExpr->getType(), 115263508Sdim rebuiltExpr->getValueKind(), 116263508Sdim rebuiltExpr->getObjectKind(), 117263508Sdim ce->getRParenLoc(), 118263508Sdim ce->isConditionTrue(), 119263508Sdim rebuiltExpr->isTypeDependent(), 120263508Sdim rebuiltExpr->isValueDependent()); 121263508Sdim } 122263508Sdim 123234287Sdim llvm_unreachable("bad expression to rebuild!"); 124234287Sdim } 125234287Sdim }; 126234287Sdim 127234287Sdim struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> { 128234287Sdim Expr *NewBase; 129234287Sdim ObjCPropertyRefRebuilder(Sema &S, Expr *newBase) 130234287Sdim : Rebuilder<ObjCPropertyRefRebuilder>(S), NewBase(newBase) {} 131234287Sdim 132234287Sdim typedef ObjCPropertyRefExpr specific_type; 133234287Sdim Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) { 134234287Sdim // Fortunately, the constraint that we're rebuilding something 135234287Sdim // with a base limits the number of cases here. 136249423Sdim assert(refExpr->isObjectReceiver()); 137234287Sdim 138234287Sdim if (refExpr->isExplicitProperty()) { 139234287Sdim return new (S.Context) 140234287Sdim ObjCPropertyRefExpr(refExpr->getExplicitProperty(), 141234287Sdim refExpr->getType(), refExpr->getValueKind(), 142234287Sdim refExpr->getObjectKind(), refExpr->getLocation(), 143234287Sdim NewBase); 144234287Sdim } 145234287Sdim return new (S.Context) 146234287Sdim ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(), 147234287Sdim refExpr->getImplicitPropertySetter(), 148234287Sdim refExpr->getType(), refExpr->getValueKind(), 149234287Sdim refExpr->getObjectKind(),refExpr->getLocation(), 150234287Sdim NewBase); 151234287Sdim } 152234287Sdim }; 153234287Sdim 154234287Sdim struct ObjCSubscriptRefRebuilder : Rebuilder<ObjCSubscriptRefRebuilder> { 155234287Sdim Expr *NewBase; 156234287Sdim Expr *NewKeyExpr; 157234287Sdim ObjCSubscriptRefRebuilder(Sema &S, Expr *newBase, Expr *newKeyExpr) 158234287Sdim : Rebuilder<ObjCSubscriptRefRebuilder>(S), 159234287Sdim NewBase(newBase), NewKeyExpr(newKeyExpr) {} 160234287Sdim 161234287Sdim typedef ObjCSubscriptRefExpr specific_type; 162234287Sdim Expr *rebuildSpecific(ObjCSubscriptRefExpr *refExpr) { 163234287Sdim assert(refExpr->getBaseExpr()); 164234287Sdim assert(refExpr->getKeyExpr()); 165234287Sdim 166234287Sdim return new (S.Context) 167234287Sdim ObjCSubscriptRefExpr(NewBase, 168234287Sdim NewKeyExpr, 169234287Sdim refExpr->getType(), refExpr->getValueKind(), 170234287Sdim refExpr->getObjectKind(),refExpr->getAtIndexMethodDecl(), 171234287Sdim refExpr->setAtIndexMethodDecl(), 172234287Sdim refExpr->getRBracket()); 173234287Sdim } 174234287Sdim }; 175251662Sdim 176251662Sdim struct MSPropertyRefRebuilder : Rebuilder<MSPropertyRefRebuilder> { 177251662Sdim Expr *NewBase; 178251662Sdim MSPropertyRefRebuilder(Sema &S, Expr *newBase) 179251662Sdim : Rebuilder<MSPropertyRefRebuilder>(S), NewBase(newBase) {} 180251662Sdim 181251662Sdim typedef MSPropertyRefExpr specific_type; 182251662Sdim Expr *rebuildSpecific(MSPropertyRefExpr *refExpr) { 183251662Sdim assert(refExpr->getBaseExpr()); 184251662Sdim 185251662Sdim return new (S.Context) 186251662Sdim MSPropertyRefExpr(NewBase, refExpr->getPropertyDecl(), 187251662Sdim refExpr->isArrow(), refExpr->getType(), 188251662Sdim refExpr->getValueKind(), refExpr->getQualifierLoc(), 189251662Sdim refExpr->getMemberLoc()); 190251662Sdim } 191251662Sdim }; 192234287Sdim 193234287Sdim class PseudoOpBuilder { 194234287Sdim public: 195234287Sdim Sema &S; 196234287Sdim unsigned ResultIndex; 197234287Sdim SourceLocation GenericLoc; 198234287Sdim SmallVector<Expr *, 4> Semantics; 199234287Sdim 200234287Sdim PseudoOpBuilder(Sema &S, SourceLocation genericLoc) 201234287Sdim : S(S), ResultIndex(PseudoObjectExpr::NoResult), 202234287Sdim GenericLoc(genericLoc) {} 203234287Sdim 204234287Sdim virtual ~PseudoOpBuilder() {} 205234287Sdim 206234287Sdim /// Add a normal semantic expression. 207234287Sdim void addSemanticExpr(Expr *semantic) { 208234287Sdim Semantics.push_back(semantic); 209234287Sdim } 210234287Sdim 211234287Sdim /// Add the 'result' semantic expression. 212234287Sdim void addResultSemanticExpr(Expr *resultExpr) { 213234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 214234287Sdim ResultIndex = Semantics.size(); 215234287Sdim Semantics.push_back(resultExpr); 216234287Sdim } 217234287Sdim 218234287Sdim ExprResult buildRValueOperation(Expr *op); 219234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 220234287Sdim SourceLocation opLoc, 221234287Sdim BinaryOperatorKind opcode, 222234287Sdim Expr *LHS, Expr *RHS); 223234287Sdim ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 224234287Sdim UnaryOperatorKind opcode, 225234287Sdim Expr *op); 226234287Sdim 227243830Sdim virtual ExprResult complete(Expr *syntacticForm); 228234287Sdim 229234287Sdim OpaqueValueExpr *capture(Expr *op); 230234287Sdim OpaqueValueExpr *captureValueAsResult(Expr *op); 231234287Sdim 232234287Sdim void setResultToLastSemantic() { 233234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 234234287Sdim ResultIndex = Semantics.size() - 1; 235234287Sdim } 236234287Sdim 237234287Sdim /// Return true if assignments have a non-void result. 238243830Sdim bool CanCaptureValueOfType(QualType ty) { 239243830Sdim assert(!ty->isIncompleteType()); 240243830Sdim assert(!ty->isDependentType()); 241234287Sdim 242243830Sdim if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl()) 243243830Sdim return ClassDecl->isTriviallyCopyable(); 244243830Sdim return true; 245243830Sdim } 246243830Sdim 247234287Sdim virtual Expr *rebuildAndCaptureObject(Expr *) = 0; 248234287Sdim virtual ExprResult buildGet() = 0; 249234287Sdim virtual ExprResult buildSet(Expr *, SourceLocation, 250234287Sdim bool captureSetValueAsResult) = 0; 251234287Sdim }; 252234287Sdim 253243830Sdim /// A PseudoOpBuilder for Objective-C \@properties. 254234287Sdim class ObjCPropertyOpBuilder : public PseudoOpBuilder { 255234287Sdim ObjCPropertyRefExpr *RefExpr; 256234287Sdim ObjCPropertyRefExpr *SyntacticRefExpr; 257234287Sdim OpaqueValueExpr *InstanceReceiver; 258234287Sdim ObjCMethodDecl *Getter; 259234287Sdim 260234287Sdim ObjCMethodDecl *Setter; 261234287Sdim Selector SetterSelector; 262234982Sdim Selector GetterSelector; 263234287Sdim 264234287Sdim public: 265234287Sdim ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : 266234287Sdim PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), 267234287Sdim SyntacticRefExpr(0), InstanceReceiver(0), Getter(0), Setter(0) { 268234287Sdim } 269234287Sdim 270234287Sdim ExprResult buildRValueOperation(Expr *op); 271234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 272234287Sdim SourceLocation opLoc, 273234287Sdim BinaryOperatorKind opcode, 274234287Sdim Expr *LHS, Expr *RHS); 275234287Sdim ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 276234287Sdim UnaryOperatorKind opcode, 277234287Sdim Expr *op); 278234287Sdim 279234287Sdim bool tryBuildGetOfReference(Expr *op, ExprResult &result); 280239462Sdim bool findSetter(bool warn=true); 281234287Sdim bool findGetter(); 282234287Sdim 283234287Sdim Expr *rebuildAndCaptureObject(Expr *syntacticBase); 284234287Sdim ExprResult buildGet(); 285234287Sdim ExprResult buildSet(Expr *op, SourceLocation, bool); 286243830Sdim ExprResult complete(Expr *SyntacticForm); 287243830Sdim 288243830Sdim bool isWeakProperty() const; 289234287Sdim }; 290234287Sdim 291234287Sdim /// A PseudoOpBuilder for Objective-C array/dictionary indexing. 292234287Sdim class ObjCSubscriptOpBuilder : public PseudoOpBuilder { 293234287Sdim ObjCSubscriptRefExpr *RefExpr; 294234287Sdim OpaqueValueExpr *InstanceBase; 295234287Sdim OpaqueValueExpr *InstanceKey; 296234287Sdim ObjCMethodDecl *AtIndexGetter; 297234287Sdim Selector AtIndexGetterSelector; 298234287Sdim 299234287Sdim ObjCMethodDecl *AtIndexSetter; 300234287Sdim Selector AtIndexSetterSelector; 301234287Sdim 302234287Sdim public: 303234287Sdim ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) : 304234287Sdim PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), 305234287Sdim RefExpr(refExpr), 306234287Sdim InstanceBase(0), InstanceKey(0), 307234287Sdim AtIndexGetter(0), AtIndexSetter(0) { } 308234287Sdim 309234287Sdim ExprResult buildRValueOperation(Expr *op); 310234287Sdim ExprResult buildAssignmentOperation(Scope *Sc, 311234287Sdim SourceLocation opLoc, 312234287Sdim BinaryOperatorKind opcode, 313234287Sdim Expr *LHS, Expr *RHS); 314234287Sdim Expr *rebuildAndCaptureObject(Expr *syntacticBase); 315234287Sdim 316234287Sdim bool findAtIndexGetter(); 317234287Sdim bool findAtIndexSetter(); 318234287Sdim 319234287Sdim ExprResult buildGet(); 320234287Sdim ExprResult buildSet(Expr *op, SourceLocation, bool); 321234287Sdim }; 322234287Sdim 323251662Sdim class MSPropertyOpBuilder : public PseudoOpBuilder { 324251662Sdim MSPropertyRefExpr *RefExpr; 325251662Sdim 326251662Sdim public: 327251662Sdim MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : 328251662Sdim PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), 329251662Sdim RefExpr(refExpr) {} 330251662Sdim 331251662Sdim Expr *rebuildAndCaptureObject(Expr *); 332251662Sdim ExprResult buildGet(); 333251662Sdim ExprResult buildSet(Expr *op, SourceLocation, bool); 334251662Sdim }; 335234287Sdim} 336234287Sdim 337234287Sdim/// Capture the given expression in an OpaqueValueExpr. 338234287SdimOpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { 339234287Sdim // Make a new OVE whose source is the given expression. 340234287Sdim OpaqueValueExpr *captured = 341234287Sdim new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(), 342234287Sdim e->getValueKind(), e->getObjectKind(), 343234287Sdim e); 344234287Sdim 345234287Sdim // Make sure we bind that in the semantics. 346234287Sdim addSemanticExpr(captured); 347234287Sdim return captured; 348234287Sdim} 349234287Sdim 350234287Sdim/// Capture the given expression as the result of this pseudo-object 351234287Sdim/// operation. This routine is safe against expressions which may 352234287Sdim/// already be captured. 353234287Sdim/// 354243830Sdim/// \returns the captured expression, which will be the 355234287Sdim/// same as the input if the input was already captured 356234287SdimOpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { 357234287Sdim assert(ResultIndex == PseudoObjectExpr::NoResult); 358234287Sdim 359234287Sdim // If the expression hasn't already been captured, just capture it 360234287Sdim // and set the new semantic 361234287Sdim if (!isa<OpaqueValueExpr>(e)) { 362234287Sdim OpaqueValueExpr *cap = capture(e); 363234287Sdim setResultToLastSemantic(); 364234287Sdim return cap; 365234287Sdim } 366234287Sdim 367234287Sdim // Otherwise, it must already be one of our semantic expressions; 368234287Sdim // set ResultIndex to its index. 369234287Sdim unsigned index = 0; 370234287Sdim for (;; ++index) { 371234287Sdim assert(index < Semantics.size() && 372234287Sdim "captured expression not found in semantics!"); 373234287Sdim if (e == Semantics[index]) break; 374234287Sdim } 375234287Sdim ResultIndex = index; 376234287Sdim return cast<OpaqueValueExpr>(e); 377234287Sdim} 378234287Sdim 379234287Sdim/// The routine which creates the final PseudoObjectExpr. 380234287SdimExprResult PseudoOpBuilder::complete(Expr *syntactic) { 381234287Sdim return PseudoObjectExpr::Create(S.Context, syntactic, 382234287Sdim Semantics, ResultIndex); 383234287Sdim} 384234287Sdim 385234287Sdim/// The main skeleton for building an r-value operation. 386234287SdimExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) { 387234287Sdim Expr *syntacticBase = rebuildAndCaptureObject(op); 388234287Sdim 389234287Sdim ExprResult getExpr = buildGet(); 390234287Sdim if (getExpr.isInvalid()) return ExprError(); 391234287Sdim addResultSemanticExpr(getExpr.take()); 392234287Sdim 393234287Sdim return complete(syntacticBase); 394234287Sdim} 395234287Sdim 396234287Sdim/// The basic skeleton for building a simple or compound 397234287Sdim/// assignment operation. 398234287SdimExprResult 399234287SdimPseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, 400234287Sdim BinaryOperatorKind opcode, 401234287Sdim Expr *LHS, Expr *RHS) { 402234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 403234287Sdim 404234287Sdim Expr *syntacticLHS = rebuildAndCaptureObject(LHS); 405234287Sdim OpaqueValueExpr *capturedRHS = capture(RHS); 406234287Sdim 407234287Sdim Expr *syntactic; 408234287Sdim 409234287Sdim ExprResult result; 410234287Sdim if (opcode == BO_Assign) { 411234287Sdim result = capturedRHS; 412234287Sdim syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, 413234287Sdim opcode, capturedRHS->getType(), 414234287Sdim capturedRHS->getValueKind(), 415243830Sdim OK_Ordinary, opcLoc, false); 416234287Sdim } else { 417234287Sdim ExprResult opLHS = buildGet(); 418234287Sdim if (opLHS.isInvalid()) return ExprError(); 419234287Sdim 420234287Sdim // Build an ordinary, non-compound operation. 421234287Sdim BinaryOperatorKind nonCompound = 422234287Sdim BinaryOperator::getOpForCompoundAssignment(opcode); 423234287Sdim result = S.BuildBinOp(Sc, opcLoc, nonCompound, 424234287Sdim opLHS.take(), capturedRHS); 425234287Sdim if (result.isInvalid()) return ExprError(); 426234287Sdim 427234287Sdim syntactic = 428234287Sdim new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, 429234287Sdim result.get()->getType(), 430234287Sdim result.get()->getValueKind(), 431234287Sdim OK_Ordinary, 432234287Sdim opLHS.get()->getType(), 433234287Sdim result.get()->getType(), 434243830Sdim opcLoc, false); 435234287Sdim } 436234287Sdim 437234287Sdim // The result of the assignment, if not void, is the value set into 438234287Sdim // the l-value. 439243830Sdim result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true); 440234287Sdim if (result.isInvalid()) return ExprError(); 441234287Sdim addSemanticExpr(result.take()); 442234287Sdim 443234287Sdim return complete(syntactic); 444234287Sdim} 445234287Sdim 446234287Sdim/// The basic skeleton for building an increment or decrement 447234287Sdim/// operation. 448234287SdimExprResult 449234287SdimPseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 450234287Sdim UnaryOperatorKind opcode, 451234287Sdim Expr *op) { 452234287Sdim assert(UnaryOperator::isIncrementDecrementOp(opcode)); 453234287Sdim 454234287Sdim Expr *syntacticOp = rebuildAndCaptureObject(op); 455234287Sdim 456234287Sdim // Load the value. 457234287Sdim ExprResult result = buildGet(); 458234287Sdim if (result.isInvalid()) return ExprError(); 459234287Sdim 460234287Sdim QualType resultType = result.get()->getType(); 461234287Sdim 462234287Sdim // That's the postfix result. 463251662Sdim if (UnaryOperator::isPostfix(opcode) && 464251662Sdim (result.get()->isTypeDependent() || CanCaptureValueOfType(resultType))) { 465234287Sdim result = capture(result.take()); 466234287Sdim setResultToLastSemantic(); 467234287Sdim } 468234287Sdim 469234287Sdim // Add or subtract a literal 1. 470234287Sdim llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1); 471234287Sdim Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy, 472234287Sdim GenericLoc); 473234287Sdim 474234287Sdim if (UnaryOperator::isIncrementOp(opcode)) { 475234287Sdim result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one); 476234287Sdim } else { 477234287Sdim result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one); 478234287Sdim } 479234287Sdim if (result.isInvalid()) return ExprError(); 480234287Sdim 481234287Sdim // Store that back into the result. The value stored is the result 482234287Sdim // of a prefix operation. 483243830Sdim result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode)); 484234287Sdim if (result.isInvalid()) return ExprError(); 485234287Sdim addSemanticExpr(result.take()); 486234287Sdim 487234287Sdim UnaryOperator *syntactic = 488234287Sdim new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, 489234287Sdim VK_LValue, OK_Ordinary, opcLoc); 490234287Sdim return complete(syntactic); 491234287Sdim} 492234287Sdim 493234287Sdim 494234287Sdim//===----------------------------------------------------------------------===// 495234287Sdim// Objective-C @property and implicit property references 496234287Sdim//===----------------------------------------------------------------------===// 497234287Sdim 498234287Sdim/// Look up a method in the receiver type of an Objective-C property 499234287Sdim/// reference. 500234287Sdimstatic ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel, 501234287Sdim const ObjCPropertyRefExpr *PRE) { 502234287Sdim if (PRE->isObjectReceiver()) { 503234287Sdim const ObjCObjectPointerType *PT = 504234287Sdim PRE->getBase()->getType()->castAs<ObjCObjectPointerType>(); 505234287Sdim 506234287Sdim // Special case for 'self' in class method implementations. 507234287Sdim if (PT->isObjCClassType() && 508234287Sdim S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) { 509234287Sdim // This cast is safe because isSelfExpr is only true within 510234287Sdim // methods. 511234287Sdim ObjCMethodDecl *method = 512234287Sdim cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor()); 513234287Sdim return S.LookupMethodInObjectType(sel, 514234287Sdim S.Context.getObjCInterfaceType(method->getClassInterface()), 515234287Sdim /*instance*/ false); 516234287Sdim } 517234287Sdim 518234287Sdim return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 519234287Sdim } 520234287Sdim 521234287Sdim if (PRE->isSuperReceiver()) { 522234287Sdim if (const ObjCObjectPointerType *PT = 523234287Sdim PRE->getSuperReceiverType()->getAs<ObjCObjectPointerType>()) 524234287Sdim return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 525234287Sdim 526234287Sdim return S.LookupMethodInObjectType(sel, PRE->getSuperReceiverType(), false); 527234287Sdim } 528234287Sdim 529234287Sdim assert(PRE->isClassReceiver() && "Invalid expression"); 530234287Sdim QualType IT = S.Context.getObjCInterfaceType(PRE->getClassReceiver()); 531234287Sdim return S.LookupMethodInObjectType(sel, IT, false); 532234287Sdim} 533234287Sdim 534243830Sdimbool ObjCPropertyOpBuilder::isWeakProperty() const { 535243830Sdim QualType T; 536243830Sdim if (RefExpr->isExplicitProperty()) { 537243830Sdim const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); 538243830Sdim if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) 539243830Sdim return true; 540243830Sdim 541243830Sdim T = Prop->getType(); 542243830Sdim } else if (Getter) { 543243830Sdim T = Getter->getResultType(); 544243830Sdim } else { 545243830Sdim return false; 546243830Sdim } 547243830Sdim 548243830Sdim return T.getObjCLifetime() == Qualifiers::OCL_Weak; 549243830Sdim} 550243830Sdim 551234287Sdimbool ObjCPropertyOpBuilder::findGetter() { 552234287Sdim if (Getter) return true; 553234287Sdim 554234287Sdim // For implicit properties, just trust the lookup we already did. 555234287Sdim if (RefExpr->isImplicitProperty()) { 556234982Sdim if ((Getter = RefExpr->getImplicitPropertyGetter())) { 557234982Sdim GetterSelector = Getter->getSelector(); 558234982Sdim return true; 559234982Sdim } 560234982Sdim else { 561234982Sdim // Must build the getter selector the hard way. 562234982Sdim ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); 563234982Sdim assert(setter && "both setter and getter are null - cannot happen"); 564234982Sdim IdentifierInfo *setterName = 565234982Sdim setter->getSelector().getIdentifierInfoForSlot(0); 566234982Sdim const char *compStr = setterName->getNameStart(); 567234982Sdim compStr += 3; 568234982Sdim IdentifierInfo *getterName = &S.Context.Idents.get(compStr); 569234982Sdim GetterSelector = 570234982Sdim S.PP.getSelectorTable().getNullarySelector(getterName); 571234982Sdim return false; 572234982Sdim 573234982Sdim } 574234287Sdim } 575234287Sdim 576234287Sdim ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); 577234287Sdim Getter = LookupMethodInReceiverType(S, prop->getGetterName(), RefExpr); 578234287Sdim return (Getter != 0); 579234287Sdim} 580234287Sdim 581234287Sdim/// Try to find the most accurate setter declaration for the property 582234287Sdim/// reference. 583234287Sdim/// 584234287Sdim/// \return true if a setter was found, in which case Setter 585239462Sdimbool ObjCPropertyOpBuilder::findSetter(bool warn) { 586234287Sdim // For implicit properties, just trust the lookup we already did. 587234287Sdim if (RefExpr->isImplicitProperty()) { 588234287Sdim if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) { 589234287Sdim Setter = setter; 590234287Sdim SetterSelector = setter->getSelector(); 591234287Sdim return true; 592234287Sdim } else { 593234287Sdim IdentifierInfo *getterName = 594234287Sdim RefExpr->getImplicitPropertyGetter()->getSelector() 595234287Sdim .getIdentifierInfoForSlot(0); 596234287Sdim SetterSelector = 597263508Sdim SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(), 598263508Sdim S.PP.getSelectorTable(), 599263508Sdim getterName); 600234287Sdim return false; 601234287Sdim } 602234287Sdim } 603234287Sdim 604234287Sdim // For explicit properties, this is more involved. 605234287Sdim ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); 606234287Sdim SetterSelector = prop->getSetterName(); 607234287Sdim 608234287Sdim // Do a normal method lookup first. 609234287Sdim if (ObjCMethodDecl *setter = 610234287Sdim LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { 611243830Sdim if (setter->isPropertyAccessor() && warn) 612239462Sdim if (const ObjCInterfaceDecl *IFace = 613239462Sdim dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) { 614239462Sdim const StringRef thisPropertyName(prop->getName()); 615249423Sdim // Try flipping the case of the first character. 616239462Sdim char front = thisPropertyName.front(); 617249423Sdim front = isLowercase(front) ? toUppercase(front) : toLowercase(front); 618239462Sdim SmallString<100> PropertyName = thisPropertyName; 619239462Sdim PropertyName[0] = front; 620239462Sdim IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); 621239462Sdim if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember)) 622239462Sdim if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { 623239462Sdim S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use) 624239462Sdim << prop->getName() << prop1->getName() << setter->getSelector(); 625239462Sdim S.Diag(prop->getLocation(), diag::note_property_declare); 626239462Sdim S.Diag(prop1->getLocation(), diag::note_property_declare); 627239462Sdim } 628239462Sdim } 629234287Sdim Setter = setter; 630234287Sdim return true; 631234287Sdim } 632234287Sdim 633234287Sdim // That can fail in the somewhat crazy situation that we're 634234287Sdim // type-checking a message send within the @interface declaration 635234287Sdim // that declared the @property. But it's not clear that that's 636234287Sdim // valuable to support. 637234287Sdim 638234287Sdim return false; 639234287Sdim} 640234287Sdim 641234287Sdim/// Capture the base object of an Objective-C property expression. 642234287SdimExpr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 643234287Sdim assert(InstanceReceiver == 0); 644234287Sdim 645234287Sdim // If we have a base, capture it in an OVE and rebuild the syntactic 646234287Sdim // form to use the OVE as its base. 647234287Sdim if (RefExpr->isObjectReceiver()) { 648234287Sdim InstanceReceiver = capture(RefExpr->getBase()); 649234287Sdim 650234287Sdim syntacticBase = 651234287Sdim ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase); 652234287Sdim } 653234287Sdim 654234287Sdim if (ObjCPropertyRefExpr * 655234287Sdim refE = dyn_cast<ObjCPropertyRefExpr>(syntacticBase->IgnoreParens())) 656234287Sdim SyntacticRefExpr = refE; 657234287Sdim 658234287Sdim return syntacticBase; 659234287Sdim} 660234287Sdim 661234287Sdim/// Load from an Objective-C property reference. 662234287SdimExprResult ObjCPropertyOpBuilder::buildGet() { 663234287Sdim findGetter(); 664234287Sdim assert(Getter); 665234287Sdim 666234287Sdim if (SyntacticRefExpr) 667234287Sdim SyntacticRefExpr->setIsMessagingGetter(); 668234287Sdim 669234287Sdim QualType receiverType; 670234287Sdim if (RefExpr->isClassReceiver()) { 671234287Sdim receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 672234287Sdim } else if (RefExpr->isSuperReceiver()) { 673234287Sdim receiverType = RefExpr->getSuperReceiverType(); 674234287Sdim } else { 675234287Sdim assert(InstanceReceiver); 676234287Sdim receiverType = InstanceReceiver->getType(); 677234287Sdim } 678234287Sdim 679234287Sdim // Build a message-send. 680234287Sdim ExprResult msg; 681234287Sdim if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 682234287Sdim assert(InstanceReceiver || RefExpr->isSuperReceiver()); 683234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, 684234287Sdim GenericLoc, Getter->getSelector(), 685251662Sdim Getter, None); 686234287Sdim } else { 687234287Sdim msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), 688251662Sdim GenericLoc, Getter->getSelector(), 689251662Sdim Getter, None); 690234287Sdim } 691234287Sdim return msg; 692234287Sdim} 693234287Sdim 694234287Sdim/// Store to an Objective-C property reference. 695234287Sdim/// 696243830Sdim/// \param captureSetValueAsResult If true, capture the actual 697234287Sdim/// value being set as the value of the property operation. 698234287SdimExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, 699234287Sdim bool captureSetValueAsResult) { 700239462Sdim bool hasSetter = findSetter(false); 701234287Sdim assert(hasSetter); (void) hasSetter; 702234287Sdim 703234287Sdim if (SyntacticRefExpr) 704234287Sdim SyntacticRefExpr->setIsMessagingSetter(); 705234287Sdim 706234287Sdim QualType receiverType; 707234287Sdim if (RefExpr->isClassReceiver()) { 708234287Sdim receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 709234287Sdim } else if (RefExpr->isSuperReceiver()) { 710234287Sdim receiverType = RefExpr->getSuperReceiverType(); 711234287Sdim } else { 712234287Sdim assert(InstanceReceiver); 713234287Sdim receiverType = InstanceReceiver->getType(); 714234287Sdim } 715234287Sdim 716234287Sdim // Use assignment constraints when possible; they give us better 717234287Sdim // diagnostics. "When possible" basically means anything except a 718234287Sdim // C++ class type. 719234287Sdim if (!S.getLangOpts().CPlusPlus || !op->getType()->isRecordType()) { 720234287Sdim QualType paramType = (*Setter->param_begin())->getType(); 721234287Sdim if (!S.getLangOpts().CPlusPlus || !paramType->isRecordType()) { 722234287Sdim ExprResult opResult = op; 723234287Sdim Sema::AssignConvertType assignResult 724234287Sdim = S.CheckSingleAssignmentConstraints(paramType, opResult); 725234287Sdim if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, 726234287Sdim op->getType(), opResult.get(), 727234287Sdim Sema::AA_Assigning)) 728234287Sdim return ExprError(); 729234287Sdim 730234287Sdim op = opResult.take(); 731234287Sdim assert(op && "successful assignment left argument invalid?"); 732234287Sdim } 733263508Sdim else if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(op)) { 734263508Sdim Expr *Initializer = OVE->getSourceExpr(); 735263508Sdim // passing C++11 style initialized temporaries to objc++ properties 736263508Sdim // requires special treatment by removing OpaqueValueExpr so type 737263508Sdim // conversion takes place and adding the OpaqueValueExpr later on. 738263508Sdim if (isa<InitListExpr>(Initializer) && 739263508Sdim Initializer->getType()->isVoidType()) { 740263508Sdim op = Initializer; 741263508Sdim } 742263508Sdim } 743234287Sdim } 744234287Sdim 745234287Sdim // Arguments. 746234287Sdim Expr *args[] = { op }; 747234287Sdim 748234287Sdim // Build a message-send. 749234287Sdim ExprResult msg; 750234287Sdim if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 751234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, 752234287Sdim GenericLoc, SetterSelector, Setter, 753234287Sdim MultiExprArg(args, 1)); 754234287Sdim } else { 755234287Sdim msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), 756234287Sdim GenericLoc, 757234287Sdim SetterSelector, Setter, 758234287Sdim MultiExprArg(args, 1)); 759234287Sdim } 760234287Sdim 761234287Sdim if (!msg.isInvalid() && captureSetValueAsResult) { 762234287Sdim ObjCMessageExpr *msgExpr = 763234287Sdim cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); 764234287Sdim Expr *arg = msgExpr->getArg(0); 765243830Sdim if (CanCaptureValueOfType(arg->getType())) 766243830Sdim msgExpr->setArg(0, captureValueAsResult(arg)); 767234287Sdim } 768234287Sdim 769234287Sdim return msg; 770234287Sdim} 771234287Sdim 772234287Sdim/// @property-specific behavior for doing lvalue-to-rvalue conversion. 773234287SdimExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { 774234287Sdim // Explicit properties always have getters, but implicit ones don't. 775234287Sdim // Check that before proceeding. 776249423Sdim if (RefExpr->isImplicitProperty() && !RefExpr->getImplicitPropertyGetter()) { 777234287Sdim S.Diag(RefExpr->getLocation(), diag::err_getter_not_found) 778249423Sdim << RefExpr->getSourceRange(); 779234287Sdim return ExprError(); 780234287Sdim } 781234287Sdim 782234287Sdim ExprResult result = PseudoOpBuilder::buildRValueOperation(op); 783234287Sdim if (result.isInvalid()) return ExprError(); 784234287Sdim 785234287Sdim if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType()) 786234287Sdim S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(), 787234287Sdim Getter, RefExpr->getLocation()); 788234287Sdim 789234287Sdim // As a special case, if the method returns 'id', try to get 790234287Sdim // a better type from the property. 791234287Sdim if (RefExpr->isExplicitProperty() && result.get()->isRValue() && 792234287Sdim result.get()->getType()->isObjCIdType()) { 793234287Sdim QualType propType = RefExpr->getExplicitProperty()->getType(); 794234287Sdim if (const ObjCObjectPointerType *ptr 795234287Sdim = propType->getAs<ObjCObjectPointerType>()) { 796234287Sdim if (!ptr->isObjCIdType()) 797234287Sdim result = S.ImpCastExprToType(result.get(), propType, CK_BitCast); 798234287Sdim } 799234287Sdim } 800234287Sdim 801234287Sdim return result; 802234287Sdim} 803234287Sdim 804234287Sdim/// Try to build this as a call to a getter that returns a reference. 805234287Sdim/// 806234287Sdim/// \return true if it was possible, whether or not it actually 807234287Sdim/// succeeded 808234287Sdimbool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op, 809234287Sdim ExprResult &result) { 810234287Sdim if (!S.getLangOpts().CPlusPlus) return false; 811234287Sdim 812234287Sdim findGetter(); 813234287Sdim assert(Getter && "property has no setter and no getter!"); 814234287Sdim 815234287Sdim // Only do this if the getter returns an l-value reference type. 816234287Sdim QualType resultType = Getter->getResultType(); 817234287Sdim if (!resultType->isLValueReferenceType()) return false; 818234287Sdim 819234287Sdim result = buildRValueOperation(op); 820234287Sdim return true; 821234287Sdim} 822234287Sdim 823234287Sdim/// @property-specific behavior for doing assignments. 824234287SdimExprResult 825234287SdimObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc, 826234287Sdim SourceLocation opcLoc, 827234287Sdim BinaryOperatorKind opcode, 828234287Sdim Expr *LHS, Expr *RHS) { 829234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 830234287Sdim 831234287Sdim // If there's no setter, we have no choice but to try to assign to 832234287Sdim // the result of the getter. 833234287Sdim if (!findSetter()) { 834234287Sdim ExprResult result; 835234287Sdim if (tryBuildGetOfReference(LHS, result)) { 836234287Sdim if (result.isInvalid()) return ExprError(); 837234287Sdim return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS); 838234287Sdim } 839234287Sdim 840234287Sdim // Otherwise, it's an error. 841234287Sdim S.Diag(opcLoc, diag::err_nosetter_property_assignment) 842234287Sdim << unsigned(RefExpr->isImplicitProperty()) 843234287Sdim << SetterSelector 844234287Sdim << LHS->getSourceRange() << RHS->getSourceRange(); 845234287Sdim return ExprError(); 846234287Sdim } 847234287Sdim 848234287Sdim // If there is a setter, we definitely want to use it. 849234287Sdim 850234287Sdim // Verify that we can do a compound assignment. 851234287Sdim if (opcode != BO_Assign && !findGetter()) { 852234287Sdim S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment) 853234287Sdim << LHS->getSourceRange() << RHS->getSourceRange(); 854234287Sdim return ExprError(); 855234287Sdim } 856234287Sdim 857234287Sdim ExprResult result = 858234287Sdim PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); 859234287Sdim if (result.isInvalid()) return ExprError(); 860234287Sdim 861234287Sdim // Various warnings about property assignments in ARC. 862234287Sdim if (S.getLangOpts().ObjCAutoRefCount && InstanceReceiver) { 863234287Sdim S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS); 864234287Sdim S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); 865234287Sdim } 866234287Sdim 867234287Sdim return result; 868234287Sdim} 869234287Sdim 870234287Sdim/// @property-specific behavior for doing increments and decrements. 871234287SdimExprResult 872234287SdimObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 873234287Sdim UnaryOperatorKind opcode, 874234287Sdim Expr *op) { 875234287Sdim // If there's no setter, we have no choice but to try to assign to 876234287Sdim // the result of the getter. 877234287Sdim if (!findSetter()) { 878234287Sdim ExprResult result; 879234287Sdim if (tryBuildGetOfReference(op, result)) { 880234287Sdim if (result.isInvalid()) return ExprError(); 881234287Sdim return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take()); 882234287Sdim } 883234287Sdim 884234287Sdim // Otherwise, it's an error. 885234287Sdim S.Diag(opcLoc, diag::err_nosetter_property_incdec) 886234287Sdim << unsigned(RefExpr->isImplicitProperty()) 887234287Sdim << unsigned(UnaryOperator::isDecrementOp(opcode)) 888234287Sdim << SetterSelector 889234287Sdim << op->getSourceRange(); 890234287Sdim return ExprError(); 891234287Sdim } 892234287Sdim 893234287Sdim // If there is a setter, we definitely want to use it. 894234287Sdim 895234287Sdim // We also need a getter. 896234287Sdim if (!findGetter()) { 897234287Sdim assert(RefExpr->isImplicitProperty()); 898234287Sdim S.Diag(opcLoc, diag::err_nogetter_property_incdec) 899234287Sdim << unsigned(UnaryOperator::isDecrementOp(opcode)) 900234982Sdim << GetterSelector 901234287Sdim << op->getSourceRange(); 902234287Sdim return ExprError(); 903234287Sdim } 904234287Sdim 905234287Sdim return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op); 906234287Sdim} 907234287Sdim 908243830SdimExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { 909243830Sdim if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) { 910243830Sdim DiagnosticsEngine::Level Level = 911243830Sdim S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, 912243830Sdim SyntacticForm->getLocStart()); 913243830Sdim if (Level != DiagnosticsEngine::Ignored) 914263508Sdim S.recordUseOfEvaluatedWeak(SyntacticRefExpr, 915263508Sdim SyntacticRefExpr->isMessagingGetter()); 916243830Sdim } 917243830Sdim 918243830Sdim return PseudoOpBuilder::complete(SyntacticForm); 919243830Sdim} 920243830Sdim 921234287Sdim// ObjCSubscript build stuff. 922234287Sdim// 923234287Sdim 924234287Sdim/// objective-c subscripting-specific behavior for doing lvalue-to-rvalue 925234287Sdim/// conversion. 926234287Sdim/// FIXME. Remove this routine if it is proven that no additional 927234287Sdim/// specifity is needed. 928234287SdimExprResult ObjCSubscriptOpBuilder::buildRValueOperation(Expr *op) { 929234287Sdim ExprResult result = PseudoOpBuilder::buildRValueOperation(op); 930234287Sdim if (result.isInvalid()) return ExprError(); 931234287Sdim return result; 932234287Sdim} 933234287Sdim 934234287Sdim/// objective-c subscripting-specific behavior for doing assignments. 935234287SdimExprResult 936234287SdimObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc, 937234287Sdim SourceLocation opcLoc, 938234287Sdim BinaryOperatorKind opcode, 939234287Sdim Expr *LHS, Expr *RHS) { 940234287Sdim assert(BinaryOperator::isAssignmentOp(opcode)); 941234287Sdim // There must be a method to do the Index'ed assignment. 942234287Sdim if (!findAtIndexSetter()) 943234287Sdim return ExprError(); 944234287Sdim 945234287Sdim // Verify that we can do a compound assignment. 946234287Sdim if (opcode != BO_Assign && !findAtIndexGetter()) 947234287Sdim return ExprError(); 948234287Sdim 949234287Sdim ExprResult result = 950234287Sdim PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); 951234287Sdim if (result.isInvalid()) return ExprError(); 952234287Sdim 953234287Sdim // Various warnings about objc Index'ed assignments in ARC. 954234287Sdim if (S.getLangOpts().ObjCAutoRefCount && InstanceBase) { 955234287Sdim S.checkRetainCycles(InstanceBase->getSourceExpr(), RHS); 956234287Sdim S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); 957234287Sdim } 958234287Sdim 959234287Sdim return result; 960234287Sdim} 961234287Sdim 962234287Sdim/// Capture the base object of an Objective-C Index'ed expression. 963234287SdimExpr *ObjCSubscriptOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 964234287Sdim assert(InstanceBase == 0); 965234287Sdim 966234287Sdim // Capture base expression in an OVE and rebuild the syntactic 967234287Sdim // form to use the OVE as its base expression. 968234287Sdim InstanceBase = capture(RefExpr->getBaseExpr()); 969234287Sdim InstanceKey = capture(RefExpr->getKeyExpr()); 970234287Sdim 971234287Sdim syntacticBase = 972234287Sdim ObjCSubscriptRefRebuilder(S, InstanceBase, 973234287Sdim InstanceKey).rebuild(syntacticBase); 974234287Sdim 975234287Sdim return syntacticBase; 976234287Sdim} 977234287Sdim 978234287Sdim/// CheckSubscriptingKind - This routine decide what type 979234287Sdim/// of indexing represented by "FromE" is being done. 980234287SdimSema::ObjCSubscriptKind 981234287Sdim Sema::CheckSubscriptingKind(Expr *FromE) { 982234287Sdim // If the expression already has integral or enumeration type, we're golden. 983234287Sdim QualType T = FromE->getType(); 984234287Sdim if (T->isIntegralOrEnumerationType()) 985234287Sdim return OS_Array; 986234287Sdim 987234287Sdim // If we don't have a class type in C++, there's no way we can get an 988234287Sdim // expression of integral or enumeration type. 989234287Sdim const RecordType *RecordTy = T->getAs<RecordType>(); 990234287Sdim if (!RecordTy && T->isObjCObjectPointerType()) 991234287Sdim // All other scalar cases are assumed to be dictionary indexing which 992234287Sdim // caller handles, with diagnostics if needed. 993234287Sdim return OS_Dictionary; 994234287Sdim if (!getLangOpts().CPlusPlus || 995234287Sdim !RecordTy || RecordTy->isIncompleteType()) { 996234287Sdim // No indexing can be done. Issue diagnostics and quit. 997234287Sdim const Expr *IndexExpr = FromE->IgnoreParenImpCasts(); 998234287Sdim if (isa<StringLiteral>(IndexExpr)) 999234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_pointer) 1000234287Sdim << T << FixItHint::CreateInsertion(FromE->getExprLoc(), "@"); 1001234287Sdim else 1002234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) 1003234287Sdim << T; 1004234287Sdim return OS_Error; 1005234287Sdim } 1006234287Sdim 1007234287Sdim // We must have a complete class type. 1008234287Sdim if (RequireCompleteType(FromE->getExprLoc(), T, 1009239462Sdim diag::err_objc_index_incomplete_class_type, FromE)) 1010234287Sdim return OS_Error; 1011234287Sdim 1012234287Sdim // Look for a conversion to an integral, enumeration type, or 1013234287Sdim // objective-C pointer type. 1014234287Sdim UnresolvedSet<4> ViableConversions; 1015234287Sdim UnresolvedSet<4> ExplicitConversions; 1016249423Sdim std::pair<CXXRecordDecl::conversion_iterator, 1017249423Sdim CXXRecordDecl::conversion_iterator> Conversions 1018234287Sdim = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions(); 1019234287Sdim 1020234287Sdim int NoIntegrals=0, NoObjCIdPointers=0; 1021234287Sdim SmallVector<CXXConversionDecl *, 4> ConversionDecls; 1022234287Sdim 1023249423Sdim for (CXXRecordDecl::conversion_iterator 1024249423Sdim I = Conversions.first, E = Conversions.second; I != E; ++I) { 1025234287Sdim if (CXXConversionDecl *Conversion 1026234287Sdim = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) { 1027234287Sdim QualType CT = Conversion->getConversionType().getNonReferenceType(); 1028234287Sdim if (CT->isIntegralOrEnumerationType()) { 1029234287Sdim ++NoIntegrals; 1030234287Sdim ConversionDecls.push_back(Conversion); 1031234287Sdim } 1032234287Sdim else if (CT->isObjCIdType() ||CT->isBlockPointerType()) { 1033234287Sdim ++NoObjCIdPointers; 1034234287Sdim ConversionDecls.push_back(Conversion); 1035234287Sdim } 1036234287Sdim } 1037234287Sdim } 1038234287Sdim if (NoIntegrals ==1 && NoObjCIdPointers == 0) 1039234287Sdim return OS_Array; 1040234287Sdim if (NoIntegrals == 0 && NoObjCIdPointers == 1) 1041234287Sdim return OS_Dictionary; 1042234287Sdim if (NoIntegrals == 0 && NoObjCIdPointers == 0) { 1043234287Sdim // No conversion function was found. Issue diagnostic and return. 1044234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) 1045234287Sdim << FromE->getType(); 1046234287Sdim return OS_Error; 1047234287Sdim } 1048234287Sdim Diag(FromE->getExprLoc(), diag::err_objc_multiple_subscript_type_conversion) 1049234287Sdim << FromE->getType(); 1050234287Sdim for (unsigned int i = 0; i < ConversionDecls.size(); i++) 1051234287Sdim Diag(ConversionDecls[i]->getLocation(), diag::not_conv_function_declared_at); 1052234287Sdim 1053234287Sdim return OS_Error; 1054234287Sdim} 1055234287Sdim 1056239462Sdim/// CheckKeyForObjCARCConversion - This routine suggests bridge casting of CF 1057239462Sdim/// objects used as dictionary subscript key objects. 1058239462Sdimstatic void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT, 1059239462Sdim Expr *Key) { 1060239462Sdim if (ContainerT.isNull()) 1061239462Sdim return; 1062239462Sdim // dictionary subscripting. 1063239462Sdim // - (id)objectForKeyedSubscript:(id)key; 1064239462Sdim IdentifierInfo *KeyIdents[] = { 1065239462Sdim &S.Context.Idents.get("objectForKeyedSubscript") 1066239462Sdim }; 1067239462Sdim Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1068239462Sdim ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT, 1069239462Sdim true /*instance*/); 1070239462Sdim if (!Getter) 1071239462Sdim return; 1072239462Sdim QualType T = Getter->param_begin()[0]->getType(); 1073239462Sdim S.CheckObjCARCConversion(Key->getSourceRange(), 1074239462Sdim T, Key, Sema::CCK_ImplicitConversion); 1075239462Sdim} 1076239462Sdim 1077234287Sdimbool ObjCSubscriptOpBuilder::findAtIndexGetter() { 1078234287Sdim if (AtIndexGetter) 1079234287Sdim return true; 1080234287Sdim 1081234287Sdim Expr *BaseExpr = RefExpr->getBaseExpr(); 1082234287Sdim QualType BaseT = BaseExpr->getType(); 1083234287Sdim 1084234287Sdim QualType ResultType; 1085234287Sdim if (const ObjCObjectPointerType *PTy = 1086234287Sdim BaseT->getAs<ObjCObjectPointerType>()) { 1087234287Sdim ResultType = PTy->getPointeeType(); 1088234287Sdim if (const ObjCObjectType *iQFaceTy = 1089234287Sdim ResultType->getAsObjCQualifiedInterfaceType()) 1090234287Sdim ResultType = iQFaceTy->getBaseType(); 1091234287Sdim } 1092234287Sdim Sema::ObjCSubscriptKind Res = 1093234287Sdim S.CheckSubscriptingKind(RefExpr->getKeyExpr()); 1094239462Sdim if (Res == Sema::OS_Error) { 1095239462Sdim if (S.getLangOpts().ObjCAutoRefCount) 1096239462Sdim CheckKeyForObjCARCConversion(S, ResultType, 1097239462Sdim RefExpr->getKeyExpr()); 1098234287Sdim return false; 1099239462Sdim } 1100234287Sdim bool arrayRef = (Res == Sema::OS_Array); 1101234287Sdim 1102234287Sdim if (ResultType.isNull()) { 1103234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) 1104234287Sdim << BaseExpr->getType() << arrayRef; 1105234287Sdim return false; 1106234287Sdim } 1107234287Sdim if (!arrayRef) { 1108234287Sdim // dictionary subscripting. 1109234287Sdim // - (id)objectForKeyedSubscript:(id)key; 1110234287Sdim IdentifierInfo *KeyIdents[] = { 1111234287Sdim &S.Context.Idents.get("objectForKeyedSubscript") 1112234287Sdim }; 1113234287Sdim AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1114234287Sdim } 1115234287Sdim else { 1116234287Sdim // - (id)objectAtIndexedSubscript:(size_t)index; 1117234287Sdim IdentifierInfo *KeyIdents[] = { 1118234287Sdim &S.Context.Idents.get("objectAtIndexedSubscript") 1119234287Sdim }; 1120234287Sdim 1121234287Sdim AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); 1122234287Sdim } 1123234287Sdim 1124234287Sdim AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType, 1125234287Sdim true /*instance*/); 1126234287Sdim bool receiverIdType = (BaseT->isObjCIdType() || 1127234287Sdim BaseT->isObjCQualifiedIdType()); 1128234287Sdim 1129234287Sdim if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { 1130234287Sdim AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), 1131234287Sdim SourceLocation(), AtIndexGetterSelector, 1132234287Sdim S.Context.getObjCIdType() /*ReturnType*/, 1133234287Sdim 0 /*TypeSourceInfo */, 1134234287Sdim S.Context.getTranslationUnitDecl(), 1135234287Sdim true /*Instance*/, false/*isVariadic*/, 1136243830Sdim /*isPropertyAccessor=*/false, 1137234287Sdim /*isImplicitlyDeclared=*/true, /*isDefined=*/false, 1138234287Sdim ObjCMethodDecl::Required, 1139234287Sdim false); 1140234287Sdim ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, 1141234287Sdim SourceLocation(), SourceLocation(), 1142234287Sdim arrayRef ? &S.Context.Idents.get("index") 1143234287Sdim : &S.Context.Idents.get("key"), 1144234287Sdim arrayRef ? S.Context.UnsignedLongTy 1145234287Sdim : S.Context.getObjCIdType(), 1146234287Sdim /*TInfo=*/0, 1147234287Sdim SC_None, 1148234287Sdim 0); 1149251662Sdim AtIndexGetter->setMethodParams(S.Context, Argument, None); 1150234287Sdim } 1151234287Sdim 1152234287Sdim if (!AtIndexGetter) { 1153234287Sdim if (!receiverIdType) { 1154234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) 1155234287Sdim << BaseExpr->getType() << 0 << arrayRef; 1156234287Sdim return false; 1157234287Sdim } 1158234287Sdim AtIndexGetter = 1159234287Sdim S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector, 1160234287Sdim RefExpr->getSourceRange(), 1161234287Sdim true, false); 1162234287Sdim } 1163234287Sdim 1164234287Sdim if (AtIndexGetter) { 1165234287Sdim QualType T = AtIndexGetter->param_begin()[0]->getType(); 1166234287Sdim if ((arrayRef && !T->isIntegralOrEnumerationType()) || 1167234287Sdim (!arrayRef && !T->isObjCObjectPointerType())) { 1168234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1169234287Sdim arrayRef ? diag::err_objc_subscript_index_type 1170234287Sdim : diag::err_objc_subscript_key_type) << T; 1171234287Sdim S.Diag(AtIndexGetter->param_begin()[0]->getLocation(), 1172234287Sdim diag::note_parameter_type) << T; 1173234287Sdim return false; 1174234287Sdim } 1175234287Sdim QualType R = AtIndexGetter->getResultType(); 1176234287Sdim if (!R->isObjCObjectPointerType()) { 1177234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1178234287Sdim diag::err_objc_indexing_method_result_type) << R << arrayRef; 1179234287Sdim S.Diag(AtIndexGetter->getLocation(), diag::note_method_declared_at) << 1180234287Sdim AtIndexGetter->getDeclName(); 1181234287Sdim } 1182234287Sdim } 1183234287Sdim return true; 1184234287Sdim} 1185234287Sdim 1186234287Sdimbool ObjCSubscriptOpBuilder::findAtIndexSetter() { 1187234287Sdim if (AtIndexSetter) 1188234287Sdim return true; 1189234287Sdim 1190234287Sdim Expr *BaseExpr = RefExpr->getBaseExpr(); 1191234287Sdim QualType BaseT = BaseExpr->getType(); 1192234287Sdim 1193234287Sdim QualType ResultType; 1194234287Sdim if (const ObjCObjectPointerType *PTy = 1195234287Sdim BaseT->getAs<ObjCObjectPointerType>()) { 1196234287Sdim ResultType = PTy->getPointeeType(); 1197234287Sdim if (const ObjCObjectType *iQFaceTy = 1198234287Sdim ResultType->getAsObjCQualifiedInterfaceType()) 1199234287Sdim ResultType = iQFaceTy->getBaseType(); 1200234287Sdim } 1201234287Sdim 1202234287Sdim Sema::ObjCSubscriptKind Res = 1203234287Sdim S.CheckSubscriptingKind(RefExpr->getKeyExpr()); 1204239462Sdim if (Res == Sema::OS_Error) { 1205239462Sdim if (S.getLangOpts().ObjCAutoRefCount) 1206239462Sdim CheckKeyForObjCARCConversion(S, ResultType, 1207239462Sdim RefExpr->getKeyExpr()); 1208234287Sdim return false; 1209239462Sdim } 1210234287Sdim bool arrayRef = (Res == Sema::OS_Array); 1211234287Sdim 1212234287Sdim if (ResultType.isNull()) { 1213234287Sdim S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) 1214234287Sdim << BaseExpr->getType() << arrayRef; 1215234287Sdim return false; 1216234287Sdim } 1217234287Sdim 1218234287Sdim if (!arrayRef) { 1219234287Sdim // dictionary subscripting. 1220234287Sdim // - (void)setObject:(id)object forKeyedSubscript:(id)key; 1221234287Sdim IdentifierInfo *KeyIdents[] = { 1222234287Sdim &S.Context.Idents.get("setObject"), 1223234287Sdim &S.Context.Idents.get("forKeyedSubscript") 1224234287Sdim }; 1225234287Sdim AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); 1226234287Sdim } 1227234287Sdim else { 1228234287Sdim // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; 1229234287Sdim IdentifierInfo *KeyIdents[] = { 1230234287Sdim &S.Context.Idents.get("setObject"), 1231234287Sdim &S.Context.Idents.get("atIndexedSubscript") 1232234287Sdim }; 1233234287Sdim AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); 1234234287Sdim } 1235234287Sdim AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, 1236234287Sdim true /*instance*/); 1237234287Sdim 1238234287Sdim bool receiverIdType = (BaseT->isObjCIdType() || 1239234287Sdim BaseT->isObjCQualifiedIdType()); 1240234287Sdim 1241234287Sdim if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) { 1242234287Sdim TypeSourceInfo *ResultTInfo = 0; 1243234287Sdim QualType ReturnType = S.Context.VoidTy; 1244234287Sdim AtIndexSetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), 1245234287Sdim SourceLocation(), AtIndexSetterSelector, 1246234287Sdim ReturnType, 1247234287Sdim ResultTInfo, 1248234287Sdim S.Context.getTranslationUnitDecl(), 1249234287Sdim true /*Instance*/, false/*isVariadic*/, 1250243830Sdim /*isPropertyAccessor=*/false, 1251234287Sdim /*isImplicitlyDeclared=*/true, /*isDefined=*/false, 1252234287Sdim ObjCMethodDecl::Required, 1253234287Sdim false); 1254234287Sdim SmallVector<ParmVarDecl *, 2> Params; 1255234287Sdim ParmVarDecl *object = ParmVarDecl::Create(S.Context, AtIndexSetter, 1256234287Sdim SourceLocation(), SourceLocation(), 1257234287Sdim &S.Context.Idents.get("object"), 1258234287Sdim S.Context.getObjCIdType(), 1259234287Sdim /*TInfo=*/0, 1260234287Sdim SC_None, 1261234287Sdim 0); 1262234287Sdim Params.push_back(object); 1263234287Sdim ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter, 1264234287Sdim SourceLocation(), SourceLocation(), 1265234287Sdim arrayRef ? &S.Context.Idents.get("index") 1266234287Sdim : &S.Context.Idents.get("key"), 1267234287Sdim arrayRef ? S.Context.UnsignedLongTy 1268234287Sdim : S.Context.getObjCIdType(), 1269234287Sdim /*TInfo=*/0, 1270234287Sdim SC_None, 1271234287Sdim 0); 1272234287Sdim Params.push_back(key); 1273251662Sdim AtIndexSetter->setMethodParams(S.Context, Params, None); 1274234287Sdim } 1275234287Sdim 1276234287Sdim if (!AtIndexSetter) { 1277234287Sdim if (!receiverIdType) { 1278234287Sdim S.Diag(BaseExpr->getExprLoc(), 1279234287Sdim diag::err_objc_subscript_method_not_found) 1280234287Sdim << BaseExpr->getType() << 1 << arrayRef; 1281234287Sdim return false; 1282234287Sdim } 1283234287Sdim AtIndexSetter = 1284234287Sdim S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector, 1285234287Sdim RefExpr->getSourceRange(), 1286234287Sdim true, false); 1287234287Sdim } 1288234287Sdim 1289234287Sdim bool err = false; 1290234287Sdim if (AtIndexSetter && arrayRef) { 1291234287Sdim QualType T = AtIndexSetter->param_begin()[1]->getType(); 1292234287Sdim if (!T->isIntegralOrEnumerationType()) { 1293234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1294234287Sdim diag::err_objc_subscript_index_type) << T; 1295234287Sdim S.Diag(AtIndexSetter->param_begin()[1]->getLocation(), 1296234287Sdim diag::note_parameter_type) << T; 1297234287Sdim err = true; 1298234287Sdim } 1299234287Sdim T = AtIndexSetter->param_begin()[0]->getType(); 1300234287Sdim if (!T->isObjCObjectPointerType()) { 1301234287Sdim S.Diag(RefExpr->getBaseExpr()->getExprLoc(), 1302234287Sdim diag::err_objc_subscript_object_type) << T << arrayRef; 1303234287Sdim S.Diag(AtIndexSetter->param_begin()[0]->getLocation(), 1304234287Sdim diag::note_parameter_type) << T; 1305234287Sdim err = true; 1306234287Sdim } 1307234287Sdim } 1308234287Sdim else if (AtIndexSetter && !arrayRef) 1309234287Sdim for (unsigned i=0; i <2; i++) { 1310234287Sdim QualType T = AtIndexSetter->param_begin()[i]->getType(); 1311234287Sdim if (!T->isObjCObjectPointerType()) { 1312234287Sdim if (i == 1) 1313234287Sdim S.Diag(RefExpr->getKeyExpr()->getExprLoc(), 1314234287Sdim diag::err_objc_subscript_key_type) << T; 1315234287Sdim else 1316234287Sdim S.Diag(RefExpr->getBaseExpr()->getExprLoc(), 1317234287Sdim diag::err_objc_subscript_dic_object_type) << T; 1318234287Sdim S.Diag(AtIndexSetter->param_begin()[i]->getLocation(), 1319234287Sdim diag::note_parameter_type) << T; 1320234287Sdim err = true; 1321234287Sdim } 1322234287Sdim } 1323234287Sdim 1324234287Sdim return !err; 1325234287Sdim} 1326234287Sdim 1327234287Sdim// Get the object at "Index" position in the container. 1328234287Sdim// [BaseExpr objectAtIndexedSubscript : IndexExpr]; 1329234287SdimExprResult ObjCSubscriptOpBuilder::buildGet() { 1330234287Sdim if (!findAtIndexGetter()) 1331234287Sdim return ExprError(); 1332234287Sdim 1333234287Sdim QualType receiverType = InstanceBase->getType(); 1334234287Sdim 1335234287Sdim // Build a message-send. 1336234287Sdim ExprResult msg; 1337234287Sdim Expr *Index = InstanceKey; 1338234287Sdim 1339234287Sdim // Arguments. 1340234287Sdim Expr *args[] = { Index }; 1341234287Sdim assert(InstanceBase); 1342234287Sdim msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, 1343234287Sdim GenericLoc, 1344234287Sdim AtIndexGetterSelector, AtIndexGetter, 1345234287Sdim MultiExprArg(args, 1)); 1346234287Sdim return msg; 1347234287Sdim} 1348234287Sdim 1349234287Sdim/// Store into the container the "op" object at "Index"'ed location 1350234287Sdim/// by building this messaging expression: 1351234287Sdim/// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; 1352243830Sdim/// \param captureSetValueAsResult If true, capture the actual 1353234287Sdim/// value being set as the value of the property operation. 1354234287SdimExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, 1355234287Sdim bool captureSetValueAsResult) { 1356234287Sdim if (!findAtIndexSetter()) 1357234287Sdim return ExprError(); 1358234287Sdim 1359234287Sdim QualType receiverType = InstanceBase->getType(); 1360234287Sdim Expr *Index = InstanceKey; 1361234287Sdim 1362234287Sdim // Arguments. 1363234287Sdim Expr *args[] = { op, Index }; 1364234287Sdim 1365234287Sdim // Build a message-send. 1366234287Sdim ExprResult msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, 1367234287Sdim GenericLoc, 1368234287Sdim AtIndexSetterSelector, 1369234287Sdim AtIndexSetter, 1370234287Sdim MultiExprArg(args, 2)); 1371234287Sdim 1372234287Sdim if (!msg.isInvalid() && captureSetValueAsResult) { 1373234287Sdim ObjCMessageExpr *msgExpr = 1374234287Sdim cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); 1375234287Sdim Expr *arg = msgExpr->getArg(0); 1376243830Sdim if (CanCaptureValueOfType(arg->getType())) 1377243830Sdim msgExpr->setArg(0, captureValueAsResult(arg)); 1378234287Sdim } 1379234287Sdim 1380234287Sdim return msg; 1381234287Sdim} 1382234287Sdim 1383234287Sdim//===----------------------------------------------------------------------===// 1384251662Sdim// MSVC __declspec(property) references 1385251662Sdim//===----------------------------------------------------------------------===// 1386251662Sdim 1387251662SdimExpr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 1388251662Sdim Expr *NewBase = capture(RefExpr->getBaseExpr()); 1389251662Sdim 1390251662Sdim syntacticBase = 1391251662Sdim MSPropertyRefRebuilder(S, NewBase).rebuild(syntacticBase); 1392251662Sdim 1393251662Sdim return syntacticBase; 1394251662Sdim} 1395251662Sdim 1396251662SdimExprResult MSPropertyOpBuilder::buildGet() { 1397251662Sdim if (!RefExpr->getPropertyDecl()->hasGetter()) { 1398251662Sdim S.Diag(RefExpr->getMemberLoc(), diag::err_no_getter_for_property) 1399251662Sdim << RefExpr->getPropertyDecl()->getName(); 1400251662Sdim return ExprError(); 1401251662Sdim } 1402251662Sdim 1403251662Sdim UnqualifiedId GetterName; 1404251662Sdim IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); 1405251662Sdim GetterName.setIdentifier(II, RefExpr->getMemberLoc()); 1406251662Sdim CXXScopeSpec SS; 1407251662Sdim SS.Adopt(RefExpr->getQualifierLoc()); 1408251662Sdim ExprResult GetterExpr = S.ActOnMemberAccessExpr( 1409251662Sdim S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), 1410251662Sdim RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), 1411251662Sdim GetterName, 0, true); 1412251662Sdim if (GetterExpr.isInvalid()) { 1413251662Sdim S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_getter) 1414251662Sdim << RefExpr->getPropertyDecl()->getName(); 1415251662Sdim return ExprError(); 1416251662Sdim } 1417251662Sdim 1418251662Sdim MultiExprArg ArgExprs; 1419251662Sdim return S.ActOnCallExpr(S.getCurScope(), GetterExpr.take(), 1420251662Sdim RefExpr->getSourceRange().getBegin(), ArgExprs, 1421251662Sdim RefExpr->getSourceRange().getEnd()); 1422251662Sdim} 1423251662Sdim 1424251662SdimExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, 1425251662Sdim bool captureSetValueAsResult) { 1426251662Sdim if (!RefExpr->getPropertyDecl()->hasSetter()) { 1427251662Sdim S.Diag(RefExpr->getMemberLoc(), diag::err_no_setter_for_property) 1428251662Sdim << RefExpr->getPropertyDecl()->getName(); 1429251662Sdim return ExprError(); 1430251662Sdim } 1431251662Sdim 1432251662Sdim UnqualifiedId SetterName; 1433251662Sdim IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); 1434251662Sdim SetterName.setIdentifier(II, RefExpr->getMemberLoc()); 1435251662Sdim CXXScopeSpec SS; 1436251662Sdim SS.Adopt(RefExpr->getQualifierLoc()); 1437251662Sdim ExprResult SetterExpr = S.ActOnMemberAccessExpr( 1438251662Sdim S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), 1439251662Sdim RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), 1440251662Sdim SetterName, 0, true); 1441251662Sdim if (SetterExpr.isInvalid()) { 1442251662Sdim S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_setter) 1443251662Sdim << RefExpr->getPropertyDecl()->getName(); 1444251662Sdim return ExprError(); 1445251662Sdim } 1446251662Sdim 1447251662Sdim SmallVector<Expr*, 1> ArgExprs; 1448251662Sdim ArgExprs.push_back(op); 1449251662Sdim return S.ActOnCallExpr(S.getCurScope(), SetterExpr.take(), 1450251662Sdim RefExpr->getSourceRange().getBegin(), ArgExprs, 1451251662Sdim op->getSourceRange().getEnd()); 1452251662Sdim} 1453251662Sdim 1454251662Sdim//===----------------------------------------------------------------------===// 1455234287Sdim// General Sema routines. 1456234287Sdim//===----------------------------------------------------------------------===// 1457234287Sdim 1458234287SdimExprResult Sema::checkPseudoObjectRValue(Expr *E) { 1459234287Sdim Expr *opaqueRef = E->IgnoreParens(); 1460234287Sdim if (ObjCPropertyRefExpr *refExpr 1461234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1462234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1463234287Sdim return builder.buildRValueOperation(E); 1464234287Sdim } 1465234287Sdim else if (ObjCSubscriptRefExpr *refExpr 1466234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1467234287Sdim ObjCSubscriptOpBuilder builder(*this, refExpr); 1468234287Sdim return builder.buildRValueOperation(E); 1469251662Sdim } else if (MSPropertyRefExpr *refExpr 1470251662Sdim = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { 1471251662Sdim MSPropertyOpBuilder builder(*this, refExpr); 1472251662Sdim return builder.buildRValueOperation(E); 1473234287Sdim } else { 1474234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1475234287Sdim } 1476234287Sdim} 1477234287Sdim 1478234287Sdim/// Check an increment or decrement of a pseudo-object expression. 1479234287SdimExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, 1480234287Sdim UnaryOperatorKind opcode, Expr *op) { 1481234287Sdim // Do nothing if the operand is dependent. 1482234287Sdim if (op->isTypeDependent()) 1483234287Sdim return new (Context) UnaryOperator(op, opcode, Context.DependentTy, 1484234287Sdim VK_RValue, OK_Ordinary, opcLoc); 1485234287Sdim 1486234287Sdim assert(UnaryOperator::isIncrementDecrementOp(opcode)); 1487234287Sdim Expr *opaqueRef = op->IgnoreParens(); 1488234287Sdim if (ObjCPropertyRefExpr *refExpr 1489234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1490234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1491234287Sdim return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); 1492234287Sdim } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) { 1493234287Sdim Diag(opcLoc, diag::err_illegal_container_subscripting_op); 1494234287Sdim return ExprError(); 1495251662Sdim } else if (MSPropertyRefExpr *refExpr 1496251662Sdim = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { 1497251662Sdim MSPropertyOpBuilder builder(*this, refExpr); 1498251662Sdim return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); 1499234287Sdim } else { 1500234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1501234287Sdim } 1502234287Sdim} 1503234287Sdim 1504234287SdimExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, 1505234287Sdim BinaryOperatorKind opcode, 1506234287Sdim Expr *LHS, Expr *RHS) { 1507234287Sdim // Do nothing if either argument is dependent. 1508234287Sdim if (LHS->isTypeDependent() || RHS->isTypeDependent()) 1509234287Sdim return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, 1510243830Sdim VK_RValue, OK_Ordinary, opcLoc, false); 1511234287Sdim 1512234287Sdim // Filter out non-overload placeholder types in the RHS. 1513234287Sdim if (RHS->getType()->isNonOverloadPlaceholderType()) { 1514234287Sdim ExprResult result = CheckPlaceholderExpr(RHS); 1515234287Sdim if (result.isInvalid()) return ExprError(); 1516234287Sdim RHS = result.take(); 1517234287Sdim } 1518234287Sdim 1519234287Sdim Expr *opaqueRef = LHS->IgnoreParens(); 1520234287Sdim if (ObjCPropertyRefExpr *refExpr 1521234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1522234287Sdim ObjCPropertyOpBuilder builder(*this, refExpr); 1523234287Sdim return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 1524234287Sdim } else if (ObjCSubscriptRefExpr *refExpr 1525234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1526234287Sdim ObjCSubscriptOpBuilder builder(*this, refExpr); 1527234287Sdim return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 1528251662Sdim } else if (MSPropertyRefExpr *refExpr 1529251662Sdim = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { 1530251662Sdim MSPropertyOpBuilder builder(*this, refExpr); 1531251662Sdim return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 1532234287Sdim } else { 1533234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1534234287Sdim } 1535234287Sdim} 1536234287Sdim 1537234287Sdim/// Given a pseudo-object reference, rebuild it without the opaque 1538234287Sdim/// values. Basically, undo the behavior of rebuildAndCaptureObject. 1539234287Sdim/// This should never operate in-place. 1540234287Sdimstatic Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { 1541234287Sdim Expr *opaqueRef = E->IgnoreParens(); 1542234287Sdim if (ObjCPropertyRefExpr *refExpr 1543234287Sdim = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 1544234982Sdim // Class and super property references don't have opaque values in them. 1545234982Sdim if (refExpr->isClassReceiver() || refExpr->isSuperReceiver()) 1546234982Sdim return E; 1547234982Sdim 1548234982Sdim assert(refExpr->isObjectReceiver() && "Unknown receiver kind?"); 1549234287Sdim OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase()); 1550234287Sdim return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); 1551234287Sdim } else if (ObjCSubscriptRefExpr *refExpr 1552234287Sdim = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { 1553234287Sdim OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr()); 1554234287Sdim OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr()); 1555234287Sdim return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), 1556234287Sdim keyOVE->getSourceExpr()).rebuild(E); 1557251662Sdim } else if (MSPropertyRefExpr *refExpr 1558251662Sdim = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { 1559251662Sdim OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr()); 1560251662Sdim return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); 1561234287Sdim } else { 1562234287Sdim llvm_unreachable("unknown pseudo-object kind!"); 1563234287Sdim } 1564234287Sdim} 1565234287Sdim 1566234287Sdim/// Given a pseudo-object expression, recreate what it looks like 1567234287Sdim/// syntactically without the attendant OpaqueValueExprs. 1568234287Sdim/// 1569234287Sdim/// This is a hack which should be removed when TreeTransform is 1570234287Sdim/// capable of rebuilding a tree without stripping implicit 1571234287Sdim/// operations. 1572234287SdimExpr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { 1573234287Sdim Expr *syntax = E->getSyntacticForm(); 1574234287Sdim if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { 1575234287Sdim Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); 1576234287Sdim return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), 1577234287Sdim uop->getValueKind(), uop->getObjectKind(), 1578234287Sdim uop->getOperatorLoc()); 1579234287Sdim } else if (CompoundAssignOperator *cop 1580234287Sdim = dyn_cast<CompoundAssignOperator>(syntax)) { 1581234287Sdim Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); 1582234287Sdim Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); 1583234287Sdim return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), 1584234287Sdim cop->getType(), 1585234287Sdim cop->getValueKind(), 1586234287Sdim cop->getObjectKind(), 1587234287Sdim cop->getComputationLHSType(), 1588234287Sdim cop->getComputationResultType(), 1589243830Sdim cop->getOperatorLoc(), false); 1590234287Sdim } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { 1591234287Sdim Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); 1592234287Sdim Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); 1593234287Sdim return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), 1594234287Sdim bop->getType(), bop->getValueKind(), 1595234287Sdim bop->getObjectKind(), 1596243830Sdim bop->getOperatorLoc(), false); 1597234287Sdim } else { 1598234287Sdim assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); 1599234287Sdim return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); 1600234287Sdim } 1601234287Sdim} 1602