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