SemaPseudoObject.cpp revision 3c3b7f90a863af43fa63043d396553ecf205351c
1//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file implements semantic analysis for expressions involving
11//  pseudo-object references.  Pseudo-objects are conceptual objects
12//  whose storage is entirely abstract and all accesses to which are
13//  translated through some sort of abstraction barrier.
14//
15//  For example, Objective-C objects can have "properties", either
16//  declared or undeclared.  A property may be accessed by writing
17//    expr.prop
18//  where 'expr' is an r-value of Objective-C pointer type and 'prop'
19//  is the name of the property.  If this expression is used in a context
20//  needing an r-value, it is treated as if it were a message-send
21//  of the associated 'getter' selector, typically:
22//    [expr prop]
23//  If it is used as the LHS of a simple assignment, it is treated
24//  as a message-send of the associated 'setter' selector, typically:
25//    [expr setProp: RHS]
26//  If it is used as the LHS of a compound assignment, or the operand
27//  of a unary increment or decrement, both are required;  for example,
28//  'expr.prop *= 100' would be translated to:
29//    [expr setProp: [expr prop] * 100]
30//
31//===----------------------------------------------------------------------===//
32
33#include "clang/Sema/SemaInternal.h"
34#include "clang/Sema/Initialization.h"
35#include "clang/AST/ExprObjC.h"
36#include "clang/Lex/Preprocessor.h"
37
38using namespace clang;
39using namespace sema;
40
41static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
42                                            const ObjCPropertyRefExpr *PRE) {
43  bool instanceProperty;
44  QualType searchType;
45  if (PRE->isObjectReceiver()) {
46    searchType = PRE->getBase()->getType()
47      ->castAs<ObjCObjectPointerType>()->getPointeeType();
48    instanceProperty = true;
49  } else if (PRE->isSuperReceiver()) {
50    searchType = PRE->getSuperReceiverType();
51    instanceProperty = false;
52    if (const ObjCObjectPointerType *PT
53        = searchType->getAs<ObjCObjectPointerType>()) {
54      searchType = PT->getPointeeType();
55      instanceProperty = true;
56    }
57  } else if (PRE->isClassReceiver()) {
58    searchType = S.Context.getObjCInterfaceType(PRE->getClassReceiver());
59    instanceProperty = false;
60  }
61
62  return S.LookupMethodInObjectType(sel, searchType, instanceProperty);
63}
64
65ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
66  assert(E->getValueKind() == VK_LValue &&
67         E->getObjectKind() == OK_ObjCProperty);
68  const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
69
70  QualType ReceiverType;
71  if (PRE->isObjectReceiver())
72    ReceiverType = PRE->getBase()->getType();
73  else if (PRE->isSuperReceiver())
74    ReceiverType = PRE->getSuperReceiverType();
75  else
76    ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
77
78  ExprValueKind VK = VK_RValue;
79  QualType T;
80  if (PRE->isImplicitProperty()) {
81    if (ObjCMethodDecl *GetterMethod =
82          PRE->getImplicitPropertyGetter()) {
83      T = getMessageSendResultType(ReceiverType, GetterMethod,
84                                   PRE->isClassReceiver(),
85                                   PRE->isSuperReceiver());
86      VK = Expr::getValueKindForType(GetterMethod->getResultType());
87    } else {
88      Diag(PRE->getLocation(), diag::err_getter_not_found)
89            << PRE->getBase()->getType();
90      return ExprError();
91    }
92  } else {
93    ObjCPropertyDecl *prop = PRE->getExplicitProperty();
94
95    ObjCMethodDecl *getter =
96      LookupMethodInReceiverType(*this, prop->getGetterName(), PRE);
97    if (getter && !getter->hasRelatedResultType())
98      DiagnosePropertyAccessorMismatch(prop, getter, PRE->getLocation());
99    if (!getter) getter = prop->getGetterMethodDecl();
100
101    // Figure out the type of the expression.  Mostly this is the
102    // result type of the getter, if possible.
103    if (getter) {
104      T = getMessageSendResultType(ReceiverType, getter,
105                                   PRE->isClassReceiver(),
106                                   PRE->isSuperReceiver());
107      VK = Expr::getValueKindForType(getter->getResultType());
108
109      // As a special case, if the method returns 'id', try to get a
110      // better type from the property.
111      if (VK == VK_RValue && T->isObjCIdType() &&
112          prop->getType()->isObjCRetainableType())
113        T = prop->getType();
114    } else {
115      T = prop->getType();
116      VK = Expr::getValueKindForType(T);
117      T = T.getNonLValueExprType(Context);
118    }
119  }
120
121  E->setType(T);
122  E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
123
124  ExprResult Result = MaybeBindToTemporary(E);
125  if (!Result.isInvalid())
126    E = Result.take();
127
128  return Owned(E);
129}
130
131namespace {
132  struct PseudoObjectInfo {
133    const ObjCPropertyRefExpr *RefExpr;
134    bool HasSetter;
135    Selector SetterSelector;
136    ParmVarDecl *SetterParam;
137    QualType SetterParamType;
138
139    void setSetter(ObjCMethodDecl *setter) {
140      HasSetter = true;
141      SetterParam = *setter->param_begin();
142      SetterParamType = SetterParam->getType().getUnqualifiedType();
143    }
144
145    PseudoObjectInfo(Sema &S, Expr *E)
146      : RefExpr(E->getObjCProperty()), HasSetter(false), SetterParam(0) {
147
148      assert(E->getValueKind() == VK_LValue &&
149             E->getObjectKind() == OK_ObjCProperty);
150
151      // Try to find a setter.
152
153      // For implicit properties, just trust the lookup we already did.
154      if (RefExpr->isImplicitProperty()) {
155        if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
156          setSetter(setter);
157          SetterSelector = setter->getSelector();
158        } else {
159          IdentifierInfo *getterName =
160            RefExpr->getImplicitPropertyGetter()->getSelector()
161              .getIdentifierInfoForSlot(0);
162          SetterSelector =
163            SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
164                                               S.PP.getSelectorTable(),
165                                               getterName);
166        }
167        return;
168      }
169
170      // For explicit properties, this is more involved.
171      ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
172      SetterSelector = prop->getSetterName();
173
174      // Do a normal method lookup first.
175      if (ObjCMethodDecl *setter =
176            LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
177        setSetter(setter);
178        return;
179      }
180
181      // If that failed, trust the type on the @property declaration.
182      if (!prop->isReadOnly()) {
183        HasSetter = true;
184        SetterParamType = prop->getType().getUnqualifiedType();
185      }
186    }
187  };
188}
189
190/// Check an increment or decrement of a pseudo-object expression.
191ExprResult Sema::checkPseudoObjectIncDec(Scope *S, SourceLocation opcLoc,
192                                         UnaryOperatorKind opcode, Expr *op) {
193  assert(UnaryOperator::isIncrementDecrementOp(opcode));
194  PseudoObjectInfo info(*this, op);
195
196  // If there's no setter, we have no choice but to try to assign to
197  // the result of the getter.
198  if (!info.HasSetter) {
199    QualType resultType = info.RefExpr->getGetterResultType();
200    assert(!resultType.isNull() && "property has no setter and no getter!");
201
202    // Only do this if the getter returns an l-value reference type.
203    if (const LValueReferenceType *refType
204          = resultType->getAs<LValueReferenceType>()) {
205      op = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
206                                    CK_GetObjCProperty, op, 0, VK_LValue);
207      return BuildUnaryOp(S, opcLoc, opcode, op);
208    }
209
210    // Otherwise, it's an error.
211    Diag(opcLoc, diag::err_nosetter_property_incdec)
212      << unsigned(info.RefExpr->isImplicitProperty())
213      << unsigned(UnaryOperator::isDecrementOp(opcode))
214      << info.SetterSelector
215      << op->getSourceRange();
216    return ExprError();
217  }
218
219  // ++/-- behave like compound assignments, i.e. they need a getter.
220  QualType getterResultType = info.RefExpr->getGetterResultType();
221  if (getterResultType.isNull()) {
222    assert(info.RefExpr->isImplicitProperty());
223    Diag(opcLoc, diag::err_nogetter_property_incdec)
224      << unsigned(UnaryOperator::isDecrementOp(opcode))
225      << info.RefExpr->getImplicitPropertyGetter()->getSelector()
226      << op->getSourceRange();
227    return ExprError();
228  }
229
230  // HACK: change the type of the operand to prevent further placeholder
231  // transformation.
232  op->setType(getterResultType.getNonLValueExprType(Context));
233  op->setObjectKind(OK_Ordinary);
234
235  ExprResult result = CreateBuiltinUnaryOp(opcLoc, opcode, op);
236  if (result.isInvalid()) return ExprError();
237
238  // Change the object kind back.
239  op->setObjectKind(OK_ObjCProperty);
240  return result;
241}
242
243ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
244                                             BinaryOperatorKind opcode,
245                                             Expr *LHS, Expr *RHS) {
246  assert(BinaryOperator::isAssignmentOp(opcode));
247  PseudoObjectInfo info(*this, LHS);
248
249  // If there's no setter, we have no choice but to try to assign to
250  // the result of the getter.
251  if (!info.HasSetter) {
252    QualType resultType = info.RefExpr->getGetterResultType();
253    assert(!resultType.isNull() && "property has no setter and no getter!");
254
255    // Only do this if the getter returns an l-value reference type.
256    if (const LValueReferenceType *refType
257          = resultType->getAs<LValueReferenceType>()) {
258      LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
259                                     CK_GetObjCProperty, LHS, 0, VK_LValue);
260      return BuildBinOp(S, opcLoc, opcode, LHS, RHS);
261    }
262
263    // Otherwise, it's an error.
264    Diag(opcLoc, diag::err_nosetter_property_assignment)
265      << unsigned(info.RefExpr->isImplicitProperty())
266      << info.SetterSelector
267      << LHS->getSourceRange() << RHS->getSourceRange();
268    return ExprError();
269  }
270
271  // If there is a setter, we definitely want to use it.
272
273  // If this is a simple assignment, just initialize the parameter
274  // with the RHS.
275  if (opcode == BO_Assign) {
276    LHS->setType(info.SetterParamType.getNonLValueExprType(Context));
277
278    // Under certain circumstances, we need to type-check the RHS as a
279    // straight-up parameter initialization.  This gives somewhat
280    // inferior diagnostics, so we try to avoid it.
281
282    if (RHS->isTypeDependent()) {
283      // Just build the expression.
284
285    } else if ((getLangOptions().CPlusPlus && LHS->getType()->isRecordType()) ||
286               (getLangOptions().ObjCAutoRefCount &&
287                info.SetterParam &&
288                info.SetterParam->hasAttr<NSConsumedAttr>())) {
289      InitializedEntity param = (info.SetterParam
290        ? InitializedEntity::InitializeParameter(Context, info.SetterParam)
291        : InitializedEntity::InitializeParameter(Context, info.SetterParamType,
292                                                 /*consumed*/ false));
293      ExprResult arg = PerformCopyInitialization(param, opcLoc, RHS);
294      if (arg.isInvalid()) return ExprError();
295      RHS = arg.take();
296
297      // Warn about assignments of +1 objects to unsafe pointers in ARC.
298      // CheckAssignmentOperands does this on the other path.
299      if (getLangOptions().ObjCAutoRefCount)
300        checkUnsafeExprAssigns(opcLoc, LHS, RHS);
301    } else {
302      ExprResult RHSResult = Owned(RHS);
303
304      LHS->setObjectKind(OK_Ordinary);
305      QualType resultType = CheckAssignmentOperands(LHS, RHSResult, opcLoc,
306                                                    /*compound*/ QualType());
307      LHS->setObjectKind(OK_ObjCProperty);
308
309      if (!RHSResult.isInvalid()) RHS = RHSResult.take();
310      if (resultType.isNull()) return ExprError();
311    }
312
313    // Warn about property sets in ARC that might cause retain cycles.
314    if (getLangOptions().ObjCAutoRefCount && !info.RefExpr->isSuperReceiver())
315      checkRetainCycles(const_cast<Expr*>(info.RefExpr->getBase()), RHS);
316
317    return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),
318                                        RHS->getValueKind(),
319                                        RHS->getObjectKind(),
320                                        opcLoc);
321  }
322
323  // If this is a compound assignment, we need to use the getter, too.
324  QualType getterResultType = info.RefExpr->getGetterResultType();
325  if (getterResultType.isNull()) {
326    Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
327      << LHS->getSourceRange() << RHS->getSourceRange();
328    return ExprError();
329  }
330
331  // HACK: change the type of the LHS to prevent further placeholder
332  // transformation.
333  LHS->setType(getterResultType.getNonLValueExprType(Context));
334  LHS->setObjectKind(OK_Ordinary);
335
336  ExprResult result = CreateBuiltinBinOp(opcLoc, opcode, LHS, RHS);
337  if (result.isInvalid()) return ExprError();
338
339  // Change the object kind back.
340  LHS->setObjectKind(OK_ObjCProperty);
341  return result;
342}
343