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