diff options
Diffstat (limited to 'lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 296 |
1 files changed, 230 insertions, 66 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index cf77896..cc8eace 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -266,7 +266,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) { break; case CharacterLiteral::Wide: - NumberType = Context.getWCharType(); + NumberType = Context.getWideCharType(); break; case CharacterLiteral::UTF16: @@ -324,7 +324,8 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, /// \brief Check that the given expression is a valid element of an Objective-C /// collection literal. static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, - QualType T) { + QualType T, + bool ArrayLiteral = false) { // If the expression is type-dependent, there's nothing for us to do. if (Element->isTypeDependent()) return Element; @@ -401,14 +402,34 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, Recovered = true; } } - + if (!Recovered) { S.Diag(Element->getLocStart(), diag::err_invalid_collection_element) << Element->getType(); return ExprError(); } } - + if (ArrayLiteral) + if (ObjCStringLiteral *getString = + dyn_cast<ObjCStringLiteral>(OrigElement)) { + if (StringLiteral *SL = getString->getString()) { + unsigned numConcat = SL->getNumConcatenated(); + if (numConcat > 1) { + // Only warn if the concatenated string doesn't come from a macro. + bool hasMacro = false; + for (unsigned i = 0; i < numConcat ; ++i) + if (SL->getStrTokenLoc(i).isMacroID()) { + hasMacro = true; + break; + } + if (!hasMacro) + S.Diag(Element->getLocStart(), + diag::warn_concatenated_nsarray_literal) + << Element->getType(); + } + } + } + // Make sure that the element has the type that the container factory // function expects. return S.PerformCopyInitialization( @@ -521,7 +542,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { break; case CharacterLiteral::Wide: - ValueType = Context.getWCharType(); + ValueType = Context.getWideCharType(); break; case CharacterLiteral::UTF16: @@ -581,7 +602,7 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod) { - assert(!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic()); + assert(!LangOpts.isSubscriptPointerArithmetic()); // We can't get dependent types here; our callers should have // filtered them out. @@ -710,7 +731,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { for (unsigned I = 0, N = Elements.size(); I != N; ++I) { ExprResult Converted = CheckObjCCollectionLiteralElement(*this, ElementsBuffer[I], - RequiredType); + RequiredType, true); if (Converted.isInvalid()) return ExprError(); @@ -902,14 +923,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, QualType Ty = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(NSDictionaryDecl)); - return MaybeBindToTemporary( - ObjCDictionaryLiteral::Create(Context, - llvm::makeArrayRef(Elements, - NumElements), - HasPackExpansions, - Ty, - DictionaryWithObjectsMethod, SR)); + Context.getObjCInterfaceType(NSDictionaryDecl)); + return MaybeBindToTemporary(ObjCDictionaryLiteral::Create( + Context, makeArrayRef(Elements, NumElements), HasPackExpansions, Ty, + DictionaryWithObjectsMethod, SR)); } ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, @@ -968,8 +985,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc)); - if (!Method) - Diag(SelLoc, diag::warn_undeclared_selector) << Sel; + if (!Method) { + if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) { + Selector MatchedSel = OM->getSelector(); + SourceRange SelectorRange(LParenLoc.getLocWithOffset(1), + RParenLoc.getLocWithOffset(-1)); + Diag(SelLoc, diag::warn_undeclared_selector_with_typo) + << Sel << MatchedSel + << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + + } else + Diag(SelLoc, diag::warn_undeclared_selector) << Sel; + } if (!Method || Method->getImplementationControl() != ObjCMethodDecl::Optional) { @@ -1184,8 +1211,8 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) { } bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, - Expr **Args, unsigned NumArgs, - Selector Sel, + MultiExprArg Args, + Selector Sel, ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, @@ -1199,7 +1226,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). - for (unsigned i = 0; i != NumArgs; i++) { + for (unsigned i = 0, e = Args.size(); i != e; i++) { if (Args[i]->isTypeDependent()) continue; @@ -1221,10 +1248,31 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, else DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; - if (!getLangOpts().DebuggerSupport) - Diag(SelLoc, DiagID) - << Sel << isClassMessage << SourceRange(SelectorLocs.front(), + if (!getLangOpts().DebuggerSupport) { + const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType); + if (OMD && !OMD->isInvalidDecl()) { + if (getLangOpts().ObjCAutoRefCount) + DiagID = diag::error_method_not_found_with_typo; + else + DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo + : diag::warn_instance_method_not_found_with_typo; + Selector MatchedSel = OMD->getSelector(); + SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back()); + Diag(SelLoc, DiagID) + << Sel<< isClassMessage << MatchedSel + << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + } + else + Diag(SelLoc, DiagID) + << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); + // Find the class to which we are sending this message. + if (ReceiverType->isObjCObjectPointerType()) { + if (ObjCInterfaceDecl *Class = + ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) + Diag(Class->getLocation(), diag::note_receiver_class_declared); + } + } // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. @@ -1247,9 +1295,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, if (Method->param_size() > Sel.getNumArgs()) NumNamedArgs = Method->param_size(); // FIXME. This need be cleaned up. - if (NumArgs < NumNamedArgs) { + if (Args.size() < NumNamedArgs) { Diag(SelLoc, diag::err_typecheck_call_too_few_args) - << 2 << NumNamedArgs << NumArgs; + << 2 << NumNamedArgs << static_cast<unsigned>(Args.size()); return false; } @@ -1302,7 +1350,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, // Promote additional arguments to variadic methods. if (Method->isVariadic()) { - for (unsigned i = NumNamedArgs; i < NumArgs; ++i) { + for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) { if (Args[i]->isTypeDependent()) continue; @@ -1313,21 +1361,21 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, } } else { // Check for extra arguments to non-variadic methods. - if (NumArgs != NumNamedArgs) { + if (Args.size() != NumNamedArgs) { Diag(Args[NumNamedArgs]->getLocStart(), diag::err_typecheck_call_too_many_args) - << 2 /*method*/ << NumNamedArgs << NumArgs + << 2 /*method*/ << NumNamedArgs << static_cast<unsigned>(Args.size()) << Method->getSourceRange() << SourceRange(Args[NumNamedArgs]->getLocStart(), - Args[NumArgs-1]->getLocEnd()); + Args.back()->getLocEnd()); } } - DiagnoseSentinelCalls(Method, SelLoc, Args, NumArgs); + DiagnoseSentinelCalls(Method, SelLoc, Args); // Do additional checkings on method. - IsError |= CheckObjCMethodCall(Method, SelLoc, - llvm::makeArrayRef<const Expr *>(Args, NumArgs)); + IsError |= CheckObjCMethodCall( + Method, SelLoc, makeArrayRef<const Expr *>(Args.data(), Args.size())); return IsError; } @@ -1534,8 +1582,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // If we found a getter then this may be a valid dot-reference, we // will look for the matching setter, in case it is needed. Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); + SelectorTable::constructSetterSelector(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); // May be founf in property's qualified list. @@ -1569,16 +1617,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Attempt to correct for typos in property names. DeclFilterCCC<ObjCPropertyDecl> Validator; if (TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL, - NULL, Validator, IFace, false, OPT)) { - ObjCPropertyDecl *Property = - Corrected.getCorrectionDeclAs<ObjCPropertyDecl>(); + DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL, + NULL, Validator, IFace, false, OPT)) { + diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) + << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); - Diag(MemberLoc, diag::err_property_not_found_suggest) - << MemberName << QualType(OPT, 0) << TypoResult - << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString()); - Diag(Property->getLocation(), diag::note_previous_decl) - << Property->getDeclName(); return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, TypoResult, MemberLoc, SuperLoc, SuperType, Super); @@ -1681,8 +1724,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, // Look for the matching setter, in case it is needed. Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), &propertyName); + SelectorTable::constructSetterSelector(PP.getIdentifierTable(), + PP.getSelectorTable(), + &propertyName); ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); if (!Setter) { @@ -1809,34 +1853,28 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl()); - if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), - Result.getLookupKind(), S, NULL, - Validator)) { + if (TypoCorrection Corrected = + CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, + NULL, Validator, NULL, false, NULL, false)) { if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be // returned by CorrectTypo), this is a send to super. - Diag(NameLoc, diag::err_unknown_receiver_suggest) - << Name << Corrected.getCorrection() - << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); + diagnoseTypo(Corrected, + PDiag(diag::err_unknown_receiver_suggest) << Name); return ObjCSuperMessage; } else if (ObjCInterfaceDecl *Class = - Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { + Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { // If we found a declaration, correct when it refers to an Objective-C // class. - Diag(NameLoc, diag::err_unknown_receiver_suggest) - << Name << Corrected.getCorrection() - << FixItHint::CreateReplacement(SourceRange(NameLoc), - Class->getNameAsString()); - Diag(Class->getLocation(), diag::note_previous_decl) - << Corrected.getCorrection(); - + diagnoseTypo(Corrected, + PDiag(diag::err_unknown_receiver_suggest) << Name); QualType T = Context.getObjCInterfaceType(Class); TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); ReceiverType = CreateParsedType(T, TSInfo); return ObjCClassMessage; } } - + // Fall back: let the parser try to parse it as an instance message. return ObjCInstanceMessage; } @@ -2065,7 +2103,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, unsigned NumArgs = ArgsIn.size(); Expr **Args = ArgsIn.data(); - if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, SelectorLocs, + if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), + Sel, SelectorLocs, Method, true, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) @@ -2246,6 +2285,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } ReceiverType = Receiver->getType(); } else if (getLangOpts().CPlusPlus) { + // The receiver must be a complete type. + if (RequireCompleteType(Loc, Receiver->getType(), + diag::err_incomplete_receiver_type)) + return ExprError(); + ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver); if (result.isUsable()) { Receiver = result.take(); @@ -2410,8 +2454,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, - SelectorLocs, Method, + if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), + Sel, SelectorLocs, Method, ClassMessage, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); @@ -3121,9 +3165,112 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, << castRange << castExpr->getSourceRange(); } +static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) { + TypedefNameDecl *TDNDecl = TD->getDecl(); + QualType QT = TDNDecl->getUnderlyingType(); + if (QT->isPointerType()) { + QT = QT->getPointeeType(); + if (const RecordType *RT = QT->getAs<RecordType>()) + if (RecordDecl *RD = RT->getDecl()) + if (RD->hasAttr<ObjCBridgeAttr>()) + return RD->getAttr<ObjCBridgeAttr>(); + } + return 0; +} + +static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { + QualType T = castExpr->getType(); + while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { + TypedefNameDecl *TDNDecl = TD->getDecl(); + if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) { + if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + NamedDecl *Target = 0; + // Check for an existing type with this name. + LookupResult R(S, DeclarationName(Parm), SourceLocation(), + Sema::LookupOrdinaryName); + if (S.LookupName(R, S.TUScope)) { + Target = R.getFoundDecl(); + if (Target && isa<ObjCInterfaceDecl>(Target)) { + ObjCInterfaceDecl *ExprClass = cast<ObjCInterfaceDecl>(Target); + if (const ObjCObjectPointerType *InterfacePointerType = + castType->getAsObjCInterfacePointerType()) { + ObjCInterfaceDecl *CastClass + = InterfacePointerType->getObjectType()->getInterface(); + if ((CastClass == ExprClass) || (CastClass && ExprClass->isSuperClassOf(CastClass))) + return true; + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) + << T << Target->getName() << castType->getPointeeType(); + return true; + } else { + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) + << T << Target->getName() << castType; + return true; + } + } + } + S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface) + << castExpr->getType() << Parm->getName(); + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + return true; + } + T = TDNDecl->getUnderlyingType(); + } + return false; +} + +// (CFErrorRef)ns +static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { + QualType T = castType; + while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { + TypedefNameDecl *TDNDecl = TD->getDecl(); + if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) { + if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + NamedDecl *Target = 0; + // Check for an existing type with this name. + LookupResult R(S, DeclarationName(Parm), SourceLocation(), + Sema::LookupOrdinaryName); + if (S.LookupName(R, S.TUScope)) { + Target = R.getFoundDecl(); + if (Target && isa<ObjCInterfaceDecl>(Target)) { + ObjCInterfaceDecl *CastClass = cast<ObjCInterfaceDecl>(Target); + if (const ObjCObjectPointerType *InterfacePointerType = + castExpr->getType()->getAsObjCInterfacePointerType()) { + ObjCInterfaceDecl *ExprClass + = InterfacePointerType->getObjectType()->getInterface(); + if ((CastClass == ExprClass) || (ExprClass && CastClass->isSuperClassOf(ExprClass))) + return true; + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) + << castExpr->getType()->getPointeeType() << T; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return true; + } else { + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) + << castExpr->getType() << castType; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + return true; + } + } + } + S.Diag(castExpr->getLocStart(), diag::err_objc_ns_bridged_invalid_cfobject) + << castExpr->getType() << castType; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + return true; + } + T = TDNDecl->getUnderlyingType(); + } + return false; +} + Sema::ARCConversionResult Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, - Expr *&castExpr, CheckedConversionKind CCK) { + Expr *&castExpr, CheckedConversionKind CCK, + bool DiagnoseCFAudited) { QualType castExprType = castExpr->getType(); // For the purposes of the classification, we assume reference types @@ -3177,6 +3324,17 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && CCK != CCK_ImplicitConversion) return ACR_okay; + + if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation && + (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast)) + if (CheckObjCBridgeNSCast(*this, castType, castExpr)) + return ACR_okay; + + if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && + (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast)) + if (CheckObjCBridgeCFCast(*this, castType, castExpr)) + return ACR_okay; + switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { // For invalid casts, fall through. @@ -3204,8 +3362,14 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, CCK != CCK_ImplicitConversion) return ACR_unbridged; - diagnoseObjCARCConversion(*this, castRange, castType, castACTC, - castExpr, castExpr, exprACTC, CCK); + // Do not issue "bridge cast" diagnostic when implicit casting + // a retainable object to a CF type parameter belonging to an audited + // CF API function. Let caller issue a normal type mismatched diagnostic + // instead. + if (!DiagnoseCFAudited || exprACTC != ACTC_retainable || + castACTC != ACTC_coreFoundation) + diagnoseObjCARCConversion(*this, castRange, castType, castACTC, + castExpr, castExpr, exprACTC, CCK); return ACR_okay; } |