diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp | 925 |
1 files changed, 562 insertions, 363 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index b62d56e..0aabf8b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -111,7 +111,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ Ty = Context.getObjCIdType(); } } else { - IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); + IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString); NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc, LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { @@ -140,20 +140,47 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ return new (Context) ObjCStringLiteral(S, Ty, AtLoc); } +/// \brief Emits an error if the given method does not exist, or if the return +/// type is not an Objective-C object. +static bool validateBoxingMethod(Sema &S, SourceLocation Loc, + const ObjCInterfaceDecl *Class, + Selector Sel, const ObjCMethodDecl *Method) { + if (!Method) { + // FIXME: Is there a better way to avoid quotes than using getName()? + S.Diag(Loc, diag::err_undeclared_boxing_method) << Sel << Class->getName(); + return false; + } + + // Make sure the return type is reasonable. + QualType ReturnType = Method->getResultType(); + if (!ReturnType->isObjCObjectPointerType()) { + S.Diag(Loc, diag::err_objc_literal_method_sig) + << Sel; + S.Diag(Method->getLocation(), diag::note_objc_literal_method_return) + << ReturnType; + return false; + } + + return true; +} + /// \brief Retrieve the NSNumber factory method that should be used to create /// an Objective-C literal for the given type. static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, - QualType T, QualType ReturnType, - SourceRange Range) { + QualType NumberType, + bool isLiteral = false, + SourceRange R = SourceRange()) { llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind - = S.NSAPIObj->getNSNumberFactoryMethodKind(T); + = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType); if (!Kind) { - S.Diag(Loc, diag::err_invalid_nsnumber_type) - << T << Range; + if (isLiteral) { + S.Diag(Loc, diag::err_invalid_nsnumber_type) + << NumberType << R; + } return 0; } - + // If we already looked up this method, we're done. if (S.NSNumberLiteralMethods[*Kind]) return S.NSNumberLiteralMethods[*Kind]; @@ -161,39 +188,62 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind, /*Instance=*/false); + ASTContext &CX = S.Context; + + // Look up the NSNumber class, if we haven't done so already. It's cached + // in the Sema instance. + if (!S.NSNumberDecl) { + IdentifierInfo *NSNumberId = + S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber); + NamedDecl *IF = S.LookupSingleName(S.TUScope, NSNumberId, + Loc, Sema::LookupOrdinaryName); + S.NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (!S.NSNumberDecl) { + if (S.getLangOpts().DebuggerObjCLiteral) { + // Create a stub definition of NSNumber. + S.NSNumberDecl = ObjCInterfaceDecl::Create(CX, + CX.getTranslationUnitDecl(), + SourceLocation(), NSNumberId, + 0, SourceLocation()); + } else { + // Otherwise, require a declaration of NSNumber. + S.Diag(Loc, diag::err_undeclared_nsnumber); + return 0; + } + } else if (!S.NSNumberDecl->hasDefinition()) { + S.Diag(Loc, diag::err_undeclared_nsnumber); + return 0; + } + + // generate the pointer to NSNumber type. + QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl); + S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject); + } + // Look for the appropriate method within NSNumber. - ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);; + ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel); if (!Method && S.getLangOpts().DebuggerObjCLiteral) { + // create a stub definition this NSNumber factory method. TypeSourceInfo *ResultTInfo = 0; - Method = ObjCMethodDecl::Create(S.Context, SourceLocation(), SourceLocation(), Sel, - ReturnType, - ResultTInfo, - S.Context.getTranslationUnitDecl(), - false /*Instance*/, false/*isVariadic*/, - /*isSynthesized=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); + Method = ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel, + S.NSNumberPointer, ResultTInfo, + S.NSNumberDecl, + /*isInstance=*/false, /*isVariadic=*/false, + /*isSynthesized=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, + ObjCMethodDecl::Required, + /*HasRelatedResultType=*/false); ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method, SourceLocation(), SourceLocation(), - &S.Context.Idents.get("value"), - T, /*TInfo=*/0, SC_None, SC_None, 0); + &CX.Idents.get("value"), + NumberType, /*TInfo=*/0, SC_None, + SC_None, 0); Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>()); } - if (!Method) { - S.Diag(Loc, diag::err_undeclared_nsnumber_method) << Sel; - return 0; - } - - // Make sure the return type is reasonable. - if (!Method->getResultType()->isObjCObjectPointerType()) { - S.Diag(Loc, diag::err_objc_literal_method_sig) - << Sel; - S.Diag(Method->getLocation(), diag::note_objc_literal_method_return) - << Method->getResultType(); + if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method)) return 0; - } // Note: if the parameter type is out-of-line, we'll catch it later in the // implicit conversion. @@ -202,29 +252,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, return Method; } -/// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the -/// numeric literal expression. Type of the expression will be "NSNumber *" -/// or "id" if NSNumber is unavailable. +/// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the +/// numeric literal expression. Type of the expression will be "NSNumber *". ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) { - // Look up the NSNumber class, if we haven't done so already. - if (!NSNumberDecl) { - NamedDecl *IF = LookupSingleName(TUScope, - NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber), - AtLoc, LookupOrdinaryName); - NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); - - if (!NSNumberDecl && getLangOpts().DebuggerObjCLiteral) - NSNumberDecl = ObjCInterfaceDecl::Create (Context, - Context.getTranslationUnitDecl(), - SourceLocation(), - NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber), - 0, SourceLocation()); - if (!NSNumberDecl) { - Diag(AtLoc, diag::err_undeclared_nsnumber); - return ExprError(); - } - } - // Determine the type of the literal. QualType NumberType = Number->getType(); if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) { @@ -249,29 +279,29 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) { } } - ObjCMethodDecl *Method = 0; // Look for the appropriate method within NSNumber. // Construct the literal. - QualType Ty - = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(NSNumberDecl)); - Method = getNSNumberFactoryMethod(*this, AtLoc, - NumberType, Ty, - Number->getSourceRange()); - + SourceRange NR(Number->getSourceRange()); + ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType, + true, NR); if (!Method) return ExprError(); // Convert the number to the type that the parameter expects. - QualType ElementT = Method->param_begin()[0]->getType(); - ExprResult ConvertedNumber = PerformImplicitConversion(Number, ElementT, - AA_Sending); + ParmVarDecl *ParamDecl = Method->param_begin()[0]; + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + ParamDecl); + ExprResult ConvertedNumber = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(Number)); if (ConvertedNumber.isInvalid()) return ExprError(); Number = ConvertedNumber.get(); + // Use the effective source range of the literal, including the leading '@'. return MaybeBindToTemporary( - new (Context) ObjCNumericLiteral(Number, Ty, Method, AtLoc)); + new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method, + SourceRange(AtLoc, NR.getEnd()))); } ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, @@ -308,9 +338,11 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, // type. if (S.getLangOpts().CPlusPlus && Element->getType()->isRecordType()) { InitializedEntity Entity - = InitializedEntity::InitializeParameter(S.Context, T, /*Consumed=*/false); + = InitializedEntity::InitializeParameter(S.Context, T, + /*Consumed=*/false); InitializationKind Kind - = InitializationKind::CreateCopy(Element->getLocStart(), SourceLocation()); + = InitializationKind::CreateCopy(Element->getLocStart(), + SourceLocation()); InitializationSequence Seq(S, Entity, Kind, &Element, 1); if (!Seq.Failed()) return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1)); @@ -385,26 +417,191 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, Element->getLocStart(), Element); } +ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { + if (ValueExpr->isTypeDependent()) { + ObjCBoxedExpr *BoxedExpr = + new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, NULL, SR); + return Owned(BoxedExpr); + } + ObjCMethodDecl *BoxingMethod = NULL; + QualType BoxedType; + // Convert the expression to an RValue, so we can check for pointer types... + ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr); + if (RValue.isInvalid()) { + return ExprError(); + } + ValueExpr = RValue.get(); + QualType ValueType(ValueExpr->getType()); + if (const PointerType *PT = ValueType->getAs<PointerType>()) { + QualType PointeeType = PT->getPointeeType(); + if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) { + + if (!NSStringDecl) { + IdentifierInfo *NSStringId = + NSAPIObj->getNSClassId(NSAPI::ClassId_NSString); + NamedDecl *Decl = LookupSingleName(TUScope, NSStringId, + SR.getBegin(), LookupOrdinaryName); + NSStringDecl = dyn_cast_or_null<ObjCInterfaceDecl>(Decl); + if (!NSStringDecl) { + if (getLangOpts().DebuggerObjCLiteral) { + // Support boxed expressions in the debugger w/o NSString declaration. + DeclContext *TU = Context.getTranslationUnitDecl(); + NSStringDecl = ObjCInterfaceDecl::Create(Context, TU, + SourceLocation(), + NSStringId, + 0, SourceLocation()); + } else { + Diag(SR.getBegin(), diag::err_undeclared_nsstring); + return ExprError(); + } + } else if (!NSStringDecl->hasDefinition()) { + Diag(SR.getBegin(), diag::err_undeclared_nsstring); + return ExprError(); + } + assert(NSStringDecl && "NSStringDecl should not be NULL"); + QualType NSStringObject = Context.getObjCInterfaceType(NSStringDecl); + NSStringPointer = Context.getObjCObjectPointerType(NSStringObject); + } + + if (!StringWithUTF8StringMethod) { + IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String"); + Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II); + + // Look for the appropriate method within NSString. + BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String); + if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) { + // Debugger needs to work even if NSString hasn't been defined. + TypeSourceInfo *ResultTInfo = 0; + ObjCMethodDecl *M = + ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(), + stringWithUTF8String, NSStringPointer, + ResultTInfo, NSStringDecl, + /*isInstance=*/false, /*isVariadic=*/false, + /*isSynthesized=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, + ObjCMethodDecl::Required, + /*HasRelatedResultType=*/false); + QualType ConstCharType = Context.CharTy.withConst(); + ParmVarDecl *value = + ParmVarDecl::Create(Context, M, + SourceLocation(), SourceLocation(), + &Context.Idents.get("value"), + Context.getPointerType(ConstCharType), + /*TInfo=*/0, + SC_None, SC_None, 0); + M->setMethodParams(Context, value, ArrayRef<SourceLocation>()); + BoxingMethod = M; + } + + if (!validateBoxingMethod(*this, SR.getBegin(), NSStringDecl, + stringWithUTF8String, BoxingMethod)) + return ExprError(); + + StringWithUTF8StringMethod = BoxingMethod; + } + + BoxingMethod = StringWithUTF8StringMethod; + BoxedType = NSStringPointer; + } + } else if (ValueType->isBuiltinType()) { + // The other types we support are numeric, char and BOOL/bool. We could also + // provide limited support for structure types, such as NSRange, NSRect, and + // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h> + // for more details. + + // Check for a top-level character literal. + if (const CharacterLiteral *Char = + dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) { + // In C, character literals have type 'int'. That's not the type we want + // to use to determine the Objective-c literal kind. + switch (Char->getKind()) { + case CharacterLiteral::Ascii: + ValueType = Context.CharTy; + break; + + case CharacterLiteral::Wide: + ValueType = Context.getWCharType(); + break; + + case CharacterLiteral::UTF16: + ValueType = Context.Char16Ty; + break; + + case CharacterLiteral::UTF32: + ValueType = Context.Char32Ty; + break; + } + } + + // FIXME: Do I need to do anything special with BoolTy expressions? + + // Look for the appropriate method within NSNumber. + BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ValueType); + BoxedType = NSNumberPointer; + + } else if (const EnumType *ET = ValueType->getAs<EnumType>()) { + if (!ET->getDecl()->isComplete()) { + Diag(SR.getBegin(), diag::err_objc_incomplete_boxed_expression_type) + << ValueType << ValueExpr->getSourceRange(); + return ExprError(); + } + + BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), + ET->getDecl()->getIntegerType()); + BoxedType = NSNumberPointer; + } + + if (!BoxingMethod) { + Diag(SR.getBegin(), diag::err_objc_illegal_boxed_expression_type) + << ValueType << ValueExpr->getSourceRange(); + return ExprError(); + } + + // Convert the expression to the type that the parameter requires. + ParmVarDecl *ParamDecl = BoxingMethod->param_begin()[0]; + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + ParamDecl); + ExprResult ConvertedValueExpr = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(ValueExpr)); + if (ConvertedValueExpr.isInvalid()) + return ExprError(); + ValueExpr = ConvertedValueExpr.get(); + + ObjCBoxedExpr *BoxedExpr = + new (Context) ObjCBoxedExpr(ValueExpr, BoxedType, + BoxingMethod, SR); + return MaybeBindToTemporary(BoxedExpr); +} + +/// Build an ObjC subscript pseudo-object expression, given that +/// that's supported by the runtime. ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod) { - // Feature support is for modern abi. - if (!LangOpts.ObjCNonFragileABI) - return ExprError(); - // If the expression is type-dependent, there's nothing for us to do. - assert ((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) && - "base or index cannot have dependent type here"); + assert(!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic()); + + // We can't get dependent types here; our callers should have + // filtered them out. + assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) && + "base or index cannot have dependent type here"); + + // Filter out placeholders in the index. In theory, overloads could + // be preserved here, although that might not actually work correctly. ExprResult Result = CheckPlaceholderExpr(IndexExpr); if (Result.isInvalid()) return ExprError(); IndexExpr = Result.get(); - // Perform lvalue-to-rvalue conversion. + // Perform lvalue-to-rvalue conversion on the base. Result = DefaultLvalueConversion(BaseExpr); if (Result.isInvalid()) return ExprError(); BaseExpr = Result.get(); + + // Build the pseudo-object expression. return Owned(ObjCSubscriptRefExpr::Create(Context, BaseExpr, IndexExpr, @@ -440,11 +637,10 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { if (!ArrayWithObjectsMethod) { Selector Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount); - ArrayWithObjectsMethod = NSArrayDecl->lookupClassMethod(Sel); - if (!ArrayWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) { + ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel); + if (!Method && getLangOpts().DebuggerObjCLiteral) { TypeSourceInfo *ResultTInfo = 0; - ArrayWithObjectsMethod = - ObjCMethodDecl::Create(Context, + Method = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(), Sel, IdT, ResultTInfo, @@ -455,80 +651,68 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { ObjCMethodDecl::Required, false); SmallVector<ParmVarDecl *, 2> Params; - ParmVarDecl *objects = ParmVarDecl::Create(Context, ArrayWithObjectsMethod, - SourceLocation(), SourceLocation(), - &Context.Idents.get("objects"), - Context.getPointerType(IdT), - /*TInfo=*/0, - SC_None, - SC_None, - 0); + ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, + SourceLocation(), + SourceLocation(), + &Context.Idents.get("objects"), + Context.getPointerType(IdT), + /*TInfo=*/0, SC_None, SC_None, + 0); Params.push_back(objects); - ParmVarDecl *cnt = ParmVarDecl::Create(Context, ArrayWithObjectsMethod, - SourceLocation(), SourceLocation(), - &Context.Idents.get("cnt"), - Context.UnsignedLongTy, - /*TInfo=*/0, - SC_None, - SC_None, - 0); + ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, + SourceLocation(), + SourceLocation(), + &Context.Idents.get("cnt"), + Context.UnsignedLongTy, + /*TInfo=*/0, SC_None, SC_None, + 0); Params.push_back(cnt); - ArrayWithObjectsMethod->setMethodParams(Context, Params, - ArrayRef<SourceLocation>()); - - + Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); } - if (!ArrayWithObjectsMethod) { - Diag(SR.getBegin(), diag::err_undeclared_arraywithobjects) << Sel; + if (!validateBoxingMethod(*this, SR.getBegin(), NSArrayDecl, Sel, Method)) + return ExprError(); + + // Dig out the type that all elements should be converted to. + QualType T = Method->param_begin()[0]->getType(); + const PointerType *PtrT = T->getAs<PointerType>(); + if (!PtrT || + !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) { + Diag(SR.getBegin(), diag::err_objc_literal_method_sig) + << Sel; + Diag(Method->param_begin()[0]->getLocation(), + diag::note_objc_literal_method_param) + << 0 << T + << Context.getPointerType(IdT.withConst()); return ExprError(); } - } - // Make sure the return type is reasonable. - if (!ArrayWithObjectsMethod->getResultType()->isObjCObjectPointerType()) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << ArrayWithObjectsMethod->getSelector(); - Diag(ArrayWithObjectsMethod->getLocation(), - diag::note_objc_literal_method_return) - << ArrayWithObjectsMethod->getResultType(); - return ExprError(); - } + // Check that the 'count' parameter is integral. + if (!Method->param_begin()[1]->getType()->isIntegerType()) { + Diag(SR.getBegin(), diag::err_objc_literal_method_sig) + << Sel; + Diag(Method->param_begin()[1]->getLocation(), + diag::note_objc_literal_method_param) + << 1 + << Method->param_begin()[1]->getType() + << "integral"; + return ExprError(); + } - // Dig out the type that all elements should be converted to. - QualType T = ArrayWithObjectsMethod->param_begin()[0]->getType(); - const PointerType *PtrT = T->getAs<PointerType>(); - if (!PtrT || - !Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << ArrayWithObjectsMethod->getSelector(); - Diag(ArrayWithObjectsMethod->param_begin()[0]->getLocation(), - diag::note_objc_literal_method_param) - << 0 << T - << Context.getPointerType(IdT.withConst()); - return ExprError(); - } - T = PtrT->getPointeeType(); - - // Check that the 'count' parameter is integral. - if (!ArrayWithObjectsMethod->param_begin()[1]->getType()->isIntegerType()) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << ArrayWithObjectsMethod->getSelector(); - Diag(ArrayWithObjectsMethod->param_begin()[1]->getLocation(), - diag::note_objc_literal_method_param) - << 1 - << ArrayWithObjectsMethod->param_begin()[1]->getType() - << "integral"; - return ExprError(); + // We've found a good +arrayWithObjects:count: method. Save it! + ArrayWithObjectsMethod = Method; } + QualType ObjectsType = ArrayWithObjectsMethod->param_begin()[0]->getType(); + QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType(); + // Check that each of the elements provided is valid in a collection literal, // performing conversions as necessary. Expr **ElementsBuffer = Elements.get(); for (unsigned I = 0, N = Elements.size(); I != N; ++I) { ExprResult Converted = CheckObjCCollectionLiteralElement(*this, ElementsBuffer[I], - T); + RequiredType); if (Converted.isInvalid()) return ExprError(); @@ -573,11 +757,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, QualType IdT = Context.getObjCIdType(); if (!DictionaryWithObjectsMethod) { Selector Sel = NSAPIObj->getNSDictionarySelector( - NSAPI::NSDict_dictionaryWithObjectsForKeysCount); - DictionaryWithObjectsMethod = NSDictionaryDecl->lookupClassMethod(Sel); - if (!DictionaryWithObjectsMethod && getLangOpts().DebuggerObjCLiteral) { - DictionaryWithObjectsMethod = - ObjCMethodDecl::Create(Context, + NSAPI::NSDict_dictionaryWithObjectsForKeysCount); + ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel); + if (!Method && getLangOpts().DebuggerObjCLiteral) { + Method = ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(), Sel, IdT, 0 /*TypeSourceInfo */, @@ -588,117 +771,107 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, ObjCMethodDecl::Required, false); SmallVector<ParmVarDecl *, 3> Params; - ParmVarDecl *objects = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod, - SourceLocation(), SourceLocation(), - &Context.Idents.get("objects"), - Context.getPointerType(IdT), - /*TInfo=*/0, - SC_None, - SC_None, - 0); + ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, + SourceLocation(), + SourceLocation(), + &Context.Idents.get("objects"), + Context.getPointerType(IdT), + /*TInfo=*/0, SC_None, SC_None, + 0); Params.push_back(objects); - ParmVarDecl *keys = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod, - SourceLocation(), SourceLocation(), - &Context.Idents.get("keys"), - Context.getPointerType(IdT), - /*TInfo=*/0, - SC_None, - SC_None, - 0); + ParmVarDecl *keys = ParmVarDecl::Create(Context, Method, + SourceLocation(), + SourceLocation(), + &Context.Idents.get("keys"), + Context.getPointerType(IdT), + /*TInfo=*/0, SC_None, SC_None, + 0); Params.push_back(keys); - ParmVarDecl *cnt = ParmVarDecl::Create(Context, DictionaryWithObjectsMethod, - SourceLocation(), SourceLocation(), - &Context.Idents.get("cnt"), - Context.UnsignedLongTy, - /*TInfo=*/0, - SC_None, - SC_None, - 0); + ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method, + SourceLocation(), + SourceLocation(), + &Context.Idents.get("cnt"), + Context.UnsignedLongTy, + /*TInfo=*/0, SC_None, SC_None, + 0); Params.push_back(cnt); - DictionaryWithObjectsMethod->setMethodParams(Context, Params, - ArrayRef<SourceLocation>()); + Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); } - if (!DictionaryWithObjectsMethod) { - Diag(SR.getBegin(), diag::err_undeclared_dictwithobjects) << Sel; - return ExprError(); + if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel, + Method)) + return ExprError(); + + // Dig out the type that all values should be converted to. + QualType ValueT = Method->param_begin()[0]->getType(); + const PointerType *PtrValue = ValueT->getAs<PointerType>(); + if (!PtrValue || + !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) { + Diag(SR.getBegin(), diag::err_objc_literal_method_sig) + << Sel; + Diag(Method->param_begin()[0]->getLocation(), + diag::note_objc_literal_method_param) + << 0 << ValueT + << Context.getPointerType(IdT.withConst()); + return ExprError(); } - } - - // Make sure the return type is reasonable. - if (!DictionaryWithObjectsMethod->getResultType()->isObjCObjectPointerType()){ - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << DictionaryWithObjectsMethod->getSelector(); - Diag(DictionaryWithObjectsMethod->getLocation(), - diag::note_objc_literal_method_return) - << DictionaryWithObjectsMethod->getResultType(); - return ExprError(); - } - // Dig out the type that all values should be converted to. - QualType ValueT = DictionaryWithObjectsMethod->param_begin()[0]->getType(); - const PointerType *PtrValue = ValueT->getAs<PointerType>(); - if (!PtrValue || - !Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << DictionaryWithObjectsMethod->getSelector(); - Diag(DictionaryWithObjectsMethod->param_begin()[0]->getLocation(), - diag::note_objc_literal_method_param) - << 0 << ValueT - << Context.getPointerType(IdT.withConst()); - return ExprError(); - } - ValueT = PtrValue->getPointeeType(); - - // Dig out the type that all keys should be converted to. - QualType KeyT = DictionaryWithObjectsMethod->param_begin()[1]->getType(); - const PointerType *PtrKey = KeyT->getAs<PointerType>(); - if (!PtrKey || - !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), - IdT)) { - bool err = true; - if (PtrKey) { - if (QIDNSCopying.isNull()) { - // key argument of selector is id<NSCopying>? - if (ObjCProtocolDecl *NSCopyingPDecl = - LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { - ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; - QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ,1); - QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); + // Dig out the type that all keys should be converted to. + QualType KeyT = Method->param_begin()[1]->getType(); + const PointerType *PtrKey = KeyT->getAs<PointerType>(); + if (!PtrKey || + !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), + IdT)) { + bool err = true; + if (PtrKey) { + if (QIDNSCopying.isNull()) { + // key argument of selector is id<NSCopying>? + if (ObjCProtocolDecl *NSCopyingPDecl = + LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { + ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; + QIDNSCopying = + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, + (ObjCProtocolDecl**) PQ,1); + QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); + } } + if (!QIDNSCopying.isNull()) + err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), + QIDNSCopying); } - if (!QIDNSCopying.isNull()) - err = !Context.hasSameUnqualifiedType(PtrKey->getPointeeType(), - QIDNSCopying); - } - if (err) { + if (err) { + Diag(SR.getBegin(), diag::err_objc_literal_method_sig) + << Sel; + Diag(Method->param_begin()[1]->getLocation(), + diag::note_objc_literal_method_param) + << 1 << KeyT + << Context.getPointerType(IdT.withConst()); + return ExprError(); + } + } + + // Check that the 'count' parameter is integral. + QualType CountType = Method->param_begin()[2]->getType(); + if (!CountType->isIntegerType()) { Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << DictionaryWithObjectsMethod->getSelector(); - Diag(DictionaryWithObjectsMethod->param_begin()[1]->getLocation(), + << Sel; + Diag(Method->param_begin()[2]->getLocation(), diag::note_objc_literal_method_param) - << 1 << KeyT - << Context.getPointerType(IdT.withConst()); + << 2 << CountType + << "integral"; return ExprError(); } - } - KeyT = PtrKey->getPointeeType(); - // Check that the 'count' parameter is integral. - if (!DictionaryWithObjectsMethod->param_begin()[2]->getType() - ->isIntegerType()) { - Diag(SR.getBegin(), diag::err_objc_literal_method_sig) - << DictionaryWithObjectsMethod->getSelector(); - Diag(DictionaryWithObjectsMethod->param_begin()[2]->getLocation(), - diag::note_objc_literal_method_param) - << 2 - << DictionaryWithObjectsMethod->param_begin()[2]->getType() - << "integral"; - return ExprError(); + // We've found a good +dictionaryWithObjects:keys:count: method; save it! + DictionaryWithObjectsMethod = Method; } + QualType ValuesT = DictionaryWithObjectsMethod->param_begin()[0]->getType(); + QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType(); + QualType KeysT = DictionaryWithObjectsMethod->param_begin()[1]->getType(); + QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType(); + // Check that each of the keys and values provided is valid in a collection // literal, performing conversions as necessary. bool HasPackExpansions = false; @@ -757,8 +930,8 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled. !EncodedType->isVoidType()) // void is handled too. if (RequireCompleteType(AtLoc, EncodedType, - PDiag(diag::err_incomplete_type_objc_at_encode) - << EncodedTypeInfo->getTypeLoc().getSourceRange())) + diag::err_incomplete_type_objc_at_encode, + EncodedTypeInfo->getTypeLoc())) return ExprError(); std::string Str; @@ -846,8 +1019,9 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, + SourceLocation ProtoIdLoc, SourceLocation RParenLoc) { - ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc); + ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoIdLoc); if (!PDecl) { Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; @@ -857,7 +1031,7 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, if (Ty.isNull()) return true; Ty = Context.getObjCObjectPointerType(Ty); - return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc); + return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, ProtoIdLoc, RParenLoc); } /// Try to capture an implicit reference to 'self'. @@ -1023,8 +1197,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, if (RequireCompleteType(argExpr->getSourceRange().getBegin(), param->getType(), - PDiag(diag::err_call_incomplete_argument) - << argExpr->getSourceRange())) + diag::err_call_incomplete_argument, argExpr)) return true; InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, @@ -1042,7 +1215,8 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, if (Args[i]->isTypeDependent()) continue; - ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, + 0); IsError |= Arg.isInvalid(); Args[i] = Arg.take(); } @@ -1079,57 +1253,6 @@ bool Sema::isSelfExpr(Expr *receiver) { return false; } -// Helper method for ActOnClassMethod/ActOnInstanceMethod. -// Will search "local" class/category implementations for a method decl. -// If failed, then we search in class's root for an instance method. -// Returns 0 if no method is found. -ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel, - ObjCInterfaceDecl *ClassDecl) { - ObjCMethodDecl *Method = 0; - // lookup in class and all superclasses - while (ClassDecl && !Method) { - if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) - Method = ImpDecl->getClassMethod(Sel); - - // Look through local category implementations associated with the class. - if (!Method) - Method = ClassDecl->getCategoryClassMethod(Sel); - - // Before we give up, check if the selector is an instance method. - // But only in the root. This matches gcc's behaviour and what the - // runtime expects. - if (!Method && !ClassDecl->getSuperClass()) { - Method = ClassDecl->lookupInstanceMethod(Sel); - // Look through local category implementations associated - // with the root class. - if (!Method) - Method = LookupPrivateInstanceMethod(Sel, ClassDecl); - } - - ClassDecl = ClassDecl->getSuperClass(); - } - return Method; -} - -ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, - ObjCInterfaceDecl *ClassDecl) { - if (!ClassDecl->hasDefinition()) - return 0; - - ObjCMethodDecl *Method = 0; - while (ClassDecl && !Method) { - // If we have implementations in scope, check "private" methods. - if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation()) - Method = ImpDecl->getInstanceMethod(Sel); - - // Look through local category implementations associated with the class. - if (!Method) - Method = ClassDecl->getCategoryInstanceMethod(Sel); - ClassDecl = ClassDecl->getSuperClass(); - } - return Method; -} - /// LookupMethodInType - Look up a method in an ObjCObjectType. ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type, bool isInstance) { @@ -1141,13 +1264,8 @@ ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type, // Okay, look for "private" methods declared in any // @implementations we've seen. - if (isInstance) { - if (ObjCMethodDecl *method = LookupPrivateInstanceMethod(sel, iface)) - return method; - } else { - if (ObjCMethodDecl *method = LookupPrivateClassMethod(sel, iface)) - return method; - } + if (ObjCMethodDecl *method = iface->lookupPrivateMethod(sel, isInstance)) + return method; } // Check qualifiers. @@ -1176,6 +1294,69 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, return 0; } +static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) { + if (!Receiver) + return; + + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Receiver)) + Receiver = OVE->getSourceExpr(); + + Expr *RExpr = Receiver->IgnoreParenImpCasts(); + SourceLocation Loc = RExpr->getLocStart(); + QualType T = RExpr->getType(); + ObjCPropertyDecl *PDecl = 0; + ObjCMethodDecl *GDecl = 0; + if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) { + RExpr = POE->getSyntacticForm(); + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) { + if (PRE->isImplicitProperty()) { + GDecl = PRE->getImplicitPropertyGetter(); + if (GDecl) { + T = GDecl->getResultType(); + } + } + else { + PDecl = PRE->getExplicitProperty(); + if (PDecl) { + T = PDecl->getType(); + } + } + } + } + else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RExpr)) { + // See if receiver is a method which envokes a synthesized getter + // backing a 'weak' property. + ObjCMethodDecl *Method = ME->getMethodDecl(); + if (Method && Method->isSynthesized()) { + Selector Sel = Method->getSelector(); + if (Sel.getNumArgs() == 0) { + const DeclContext *Container = Method->getDeclContext(); + PDecl = + S.LookupPropertyDecl(cast<ObjCContainerDecl>(Container), + Sel.getIdentifierInfoForSlot(0)); + } + if (PDecl) + T = PDecl->getType(); + } + } + + if (T.getObjCLifetime() == Qualifiers::OCL_Weak) { + S.Diag(Loc, diag::warn_receiver_is_weak) + << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2)); + if (PDecl) + S.Diag(PDecl->getLocation(), diag::note_property_declare); + else if (GDecl) + S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl; + return; + } + + if (PDecl && + (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) { + S.Diag(Loc, diag::warn_receiver_is_weak) << 1; + S.Diag(PDecl->getLocation(), diag::note_property_declare); + } +} + /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. ExprResult Sema:: @@ -1187,19 +1368,20 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, bool Super) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); - - if (MemberName.getNameKind() != DeclarationName::Identifier) { + + if (!MemberName.isIdentifier()) { Diag(MemberLoc, diag::err_invalid_property_name) << MemberName << QualType(OPT, 0); return ExprError(); } - + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + SourceRange BaseRange = Super? SourceRange(SuperLoc) : BaseExpr->getSourceRange(); if (RequireCompleteType(MemberLoc, OPT->getPointeeType(), - PDiag(diag::err_property_not_found_forward_class) - << MemberName << BaseRange)) + diag::err_property_not_found_forward_class, + MemberName, BaseRange)) return ExprError(); // Search for a declared property first. @@ -1207,7 +1389,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, @@ -1225,7 +1406,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); - + if (Super) return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, @@ -1258,9 +1439,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (!Getter) Getter = IFace->lookupPrivateMethod(Sel); - // Look through local category implementations associated with the class. - if (!Getter) - Getter = IFace->getCategoryInstanceMethod(Sel); if (Getter) { // Check if we can reference this property. if (DiagnoseUseOfDecl(Getter, MemberLoc)) @@ -1272,7 +1450,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - + // May be founf in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); @@ -1282,9 +1460,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // methods. Setter = IFace->lookupPrivateMethod(SetterSel); } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryInstanceMethod(SetterSel); if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); @@ -1328,8 +1503,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (const ObjCObjectPointerType * OBJPT = T->getAsObjCInterfacePointerType()) { if (RequireCompleteType(MemberLoc, OBJPT->getPointeeType(), - PDiag(diag::err_property_not_as_forward_class) - << MemberName << BaseExpr->getSourceRange())) + diag::err_property_not_as_forward_class, + MemberName, BaseExpr)) return ExprError(); } Diag(MemberLoc, @@ -1603,9 +1778,9 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // is acting as a keyword. if (Method->isInstanceMethod()) { if (Sel.getMethodFamily() == OMF_dealloc) - ObjCShouldCallSuperDealloc = false; + getCurFunction()->ObjCShouldCallSuperDealloc = false; if (Sel.getMethodFamily() == OMF_finalize) - ObjCShouldCallSuperFinalize = false; + getCurFunction()->ObjCShouldCallSuperFinalize = false; // Since we are in an instance method, this is an instance // message to the superclass instance. @@ -1711,9 +1886,9 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { /// /// \param LBracLoc The location of the opening square bracket ']'. /// -/// \param RBrac The location of the closing square bracket ']'. +/// \param RBracLoc The location of the closing square bracket ']'. /// -/// \param Args The message arguments. +/// \param ArgsIn The message arguments. ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, @@ -1762,11 +1937,11 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, SourceRange TypeRange = SuperLoc.isValid()? SourceRange(SuperLoc) : ReceiverTypeInfo->getTypeLoc().getSourceRange(); - if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class), + if (RequireCompleteType(Loc, Context.getObjCInterfaceType(Class), (getLangOpts().ObjCAutoRefCount - ? PDiag(diag::err_arc_receiver_forward_class) - : PDiag(diag::warn_receiver_forward_class)) - << TypeRange)) { + ? diag::err_arc_receiver_forward_class + : diag::warn_receiver_forward_class), + TypeRange)) { // A forward class used in messaging is treated as a 'Class' Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); @@ -1779,7 +1954,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // If we have an implementation in scope, check "private" methods. if (!Method) - Method = LookupPrivateClassMethod(Sel, Class); + Method = Class->lookupPrivateClassMethod(Sel); if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); @@ -1881,9 +2056,9 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver, /// /// \param LBracLoc The location of the opening square bracket ']'. /// -/// \param RBrac The location of the closing square bracket ']'. +/// \param RBracLoc The location of the closing square bracket ']'. /// -/// \param Args The message arguments. +/// \param ArgsIn The message arguments. ExprResult Sema::BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, @@ -1948,7 +2123,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, receiverIsId); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), + SourceRange(LBracLoc,RBracLoc), receiverIsId); } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { @@ -1976,7 +2151,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = ClassDecl->lookupClassMethod(Sel); if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + Method = ClassDecl->lookupPrivateClassMethod(Sel); } if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); @@ -2009,12 +2184,15 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // We allow sending a message to a qualified ID ("id<foo>"), which is ok as // long as one of the protocols implements the selector (if not, warn). + // And as long as message is not deprecated/unavailable (warn if it is). if (const ObjCObjectPointerType *QIdTy = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). @@ -2025,12 +2203,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, const ObjCInterfaceDecl *forwardClass = 0; if (RequireCompleteType(Loc, OCIType->getPointeeType(), getLangOpts().ObjCAutoRefCount - ? PDiag(diag::err_arc_receiver_forward_instance) - << (Receiver ? Receiver->getSourceRange() - : SourceRange(SuperLoc)) - : PDiag(diag::warn_receiver_forward_instance) - << (Receiver ? Receiver->getSourceRange() - : SourceRange(SuperLoc)))) { + ? diag::err_arc_receiver_forward_instance + : diag::warn_receiver_forward_instance, + Receiver? Receiver->getSourceRange() + : SourceRange(SuperLoc))) { if (getLangOpts().ObjCAutoRefCount) return ExprError(); @@ -2048,7 +2224,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { // If we have implementations in scope, check "private" methods. - Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + Method = ClassDecl->lookupPrivateMethod(Sel); if (!Method && getLangOpts().ObjCAutoRefCount) { Diag(Loc, diag::err_arc_may_not_respond) @@ -2062,7 +2238,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc)); if (Method && !forwardClass) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; @@ -2087,8 +2263,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); + CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer; Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - IsNull ? CK_NullToPointer : CK_IntegralToPointer).take(); + Kind).take(); } ReceiverType = Receiver->getType(); } else { @@ -2232,10 +2409,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } if (getLangOpts().ObjCAutoRefCount) { - if (Receiver && - (Receiver->IgnoreParenImpCasts()->getType().getObjCLifetime() - == Qualifiers::OCL_Weak)) - Diag(Receiver->getLocStart(), diag::warn_receiver_is_weak); + DiagnoseARCUseOfWeakReceiver(*this, Receiver); // In ARC, annotate delegate init calls. if (Result->getMethodFamily() == OMF_init && @@ -2373,6 +2547,7 @@ namespace { ASTContext &Context; ARCConversionTypeClass SourceClass; ARCConversionTypeClass TargetClass; + bool Diagnose; static bool isCFType(QualType type) { // Someday this can use ns_bridged. For now, it has to do this. @@ -2381,8 +2556,9 @@ namespace { public: ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source, - ARCConversionTypeClass target) - : Context(Context), SourceClass(source), TargetClass(target) {} + ARCConversionTypeClass target, bool diagnose) + : Context(Context), SourceClass(source), TargetClass(target), + Diagnose(diagnose) {} using super::Visit; ACCResult Visit(Expr *e) { @@ -2500,7 +2676,8 @@ namespace { // now we're not going to permit implicit handling of +1 results, // because it's a bit frightening. if (fn->hasAttr<CFReturnsRetainedAttr>()) - return ACC_invalid; // ACC_plusOne if we start accepting this + return Diagnose ? ACC_plusOne + : ACC_invalid; // ACC_plusOne if we start accepting this // Recognize this specific builtin function, which is used by CFSTR. unsigned builtinID = fn->getBuiltinID(); @@ -2510,10 +2687,11 @@ namespace { // Otherwise, don't do anything implicit with an unaudited function. if (!fn->hasAttr<CFAuditedTransferAttr>()) return ACC_invalid; - + // Otherwise, it's +0 unless it follows the create convention. if (ento::coreFoundation::followsCreateRule(fn)) - return ACC_invalid; // ACC_plusOne if we start accepting this + return Diagnose ? ACC_plusOne + : ACC_invalid; // ACC_plusOne if we start accepting this return ACC_plusZero; } @@ -2564,11 +2742,12 @@ namespace { }; } -static bool -KnownName(Sema &S, const char *name) { - LookupResult R(S, &S.Context.Idents.get(name), SourceLocation(), +bool Sema::isKnownName(StringRef name) { + if (name.empty()) + return false; + LookupResult R(*this, &Context.Idents.get(name), SourceLocation(), Sema::LookupOrdinaryName); - return S.LookupName(R, S.TUScope, false); + return LookupName(R, TUScope, false); } static void addFixitForObjCARCConversion(Sema &S, @@ -2595,14 +2774,23 @@ static void addFixitForObjCARCConversion(Sema &S, castedE = CCE->getSubExpr(); castedE = castedE->IgnoreImpCasts(); SourceRange range = castedE->getSourceRange(); + + SmallString<32> BridgeCall; + + SourceManager &SM = S.getSourceManager(); + char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1)); + if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts())) + BridgeCall += ' '; + + BridgeCall += CFBridgeName; + if (isa<ParenExpr>(castedE)) { DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - CFBridgeName)); + BridgeCall)); } else { - std::string namePlusParen = CFBridgeName; - namePlusParen += "("; + BridgeCall += '('; DiagB.AddFixItHint(FixItHint::CreateInsertion(range.getBegin(), - namePlusParen)); + BridgeCall)); DiagB.AddFixItHint(FixItHint::CreateInsertion( S.PP.getLocForEndOfToken(range.getEnd()), ")")); @@ -2677,14 +2865,20 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, << castType << castRange << castExpr->getSourceRange(); - bool br = KnownName(S, "CFBridgingRelease"); + bool br = S.isKnownName("CFBridgingRelease"); + ACCResult CreateRule = + ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr); + assert(CreateRule != ACC_bottom && "This cast should already be accepted."); + if (CreateRule != ACC_plusOne) { DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge); addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, castType, castExpr, "__bridge ", 0); } + if (CreateRule != ACC_plusZero) { - DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_transfer) + DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc, + diag::note_arc_bridge_transfer) << castExprType << br; addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, castType, castExpr, "__bridge_transfer ", @@ -2696,7 +2890,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, // Bridge from a CF type to an ARC type. if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { - bool br = KnownName(S, "CFBridgingRetain"); + bool br = S.isKnownName("CFBridgingRetain"); S.Diag(loc, diag::err_arc_cast_requires_bridge) << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type @@ -2705,14 +2899,19 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, << castType << castRange << castExpr->getSourceRange(); - + ACCResult CreateRule = + ARCCastChecker(S.Context, exprACTC, castACTC, true).Visit(castExpr); + assert(CreateRule != ACC_bottom && "This cast should already be accepted."); + if (CreateRule != ACC_plusOne) { DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge); addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, castType, castExpr, "__bridge ", 0); } + if (CreateRule != ACC_plusZero) { - DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge_retained) + DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc, + diag::note_arc_bridge_retained) << castType << br; addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen, castType, castExpr, "__bridge_retained ", @@ -2785,7 +2984,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, CCK != CCK_ImplicitConversion) return ACR_okay; - switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) { + switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { // For invalid casts, fall through. case ACC_invalid: break; @@ -2949,7 +3148,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, break; case OBC_BridgeRetained: { - bool br = KnownName(*this, "CFBridgingRelease"); + bool br = isKnownName("CFBridgingRelease"); Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) << 2 << FromType @@ -2992,7 +3191,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, break; case OBC_BridgeTransfer: { - bool br = KnownName(*this, "CFBridgingRetain"); + bool br = isKnownName("CFBridgingRetain"); Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) << (FromType->isBlockPointerType()? 1 : 0) << FromType |