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