diff options
Diffstat (limited to 'lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 215 |
1 files changed, 125 insertions, 90 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c1fb906a5b192..8f0d4ff695769 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1035,7 +1035,6 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, HasPackExpansions = true; } - QualType Ty = Context.getObjCObjectPointerType( @@ -1778,7 +1777,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, MemberName, BaseRange)) return ExprError(); - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -1793,7 +1793,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Check protocols on qualified interfaces. for (const auto *I : OPT->quals()) - if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) { + if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -1816,7 +1817,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Getter) Getter = LookupMethodInQualifiedType(Sel, OPT, true); @@ -1836,7 +1837,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); @@ -1852,8 +1853,9 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Special warning if member name used in a property-dot for a setter accessor // does not use a property with same name; e.g. obj.X = ... for a property with // name 'x'. - if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() - && !IFace->FindPropertyDeclaration(Member)) { + if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() && + !IFace->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { // Do not warn if user is using property-dot syntax to make call to // user named setter. @@ -1883,12 +1885,29 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, LookupOrdinaryName, nullptr, nullptr, llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), CTK_ErrorRecovery, IFace, false, OPT)) { - diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) - << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); - return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, - TypoResult, MemberLoc, - SuperLoc, SuperType, Super); + if (TypoResult.isIdentifier() && + TypoResult.getAsIdentifierInfo() == Member) { + // There is no need to try the correction if it is the same. + NamedDecl *ChosenDecl = + Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl(); + if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl)) + if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) { + // This is a class property, we should not use the instance to + // access it. + Diag(MemberLoc, diag::err_class_property_found) << MemberName + << OPT->getInterfaceDecl()->getName() + << FixItHint::CreateReplacement(BaseExpr->getSourceRange(), + OPT->getInterfaceDecl()->getName()); + return ExprError(); + } + } else { + diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) + << MemberName << QualType(OPT, 0)); + return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, + TypoResult, MemberLoc, + SuperLoc, SuperType, Super); + } } ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = @@ -1916,8 +1935,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); } - - ExprResult Sema:: ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, @@ -2032,7 +2049,7 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { } }; -} +} // end anonymous namespace Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, IdentifierInfo *Name, @@ -2040,7 +2057,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType) { - ReceiverType = ParsedType(); + ReceiverType = nullptr; // If the identifier is "super" and there is no trailing dot, we're // messaging super. If the identifier is "super" and there is a @@ -2183,7 +2200,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, LBracLoc, SelectorLocs, RBracLoc, Args); } - ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, @@ -2198,7 +2214,6 @@ ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(), Sel, Method, Loc, Loc, Loc, Args, /*isImplicit=*/true); - } static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg, @@ -2465,7 +2480,6 @@ ExprResult Sema::ActOnClassMessage(Scope *S, if (ReceiverType.isNull()) return ExprError(); - if (!ReceiverTypeInfo) ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc); @@ -2621,29 +2635,28 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { // Handle messages to id and __kindof types (where we use the // global method pool). - // FIXME: The type bound is currently ignored by lookup in the - // global pool. const ObjCObjectType *typeBound = nullptr; bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context, typeBound); if (receiverIsIdLike || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - receiverIsIdLike); - if (!Method) - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc,RBracLoc), - receiverIsIdLike); - if (Method) { + SmallVector<ObjCMethodDecl*, 4> Methods; + // If we have a type bound, further filter the methods. + CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/, + true/*CheckTheOther*/, typeBound); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try to + // select a better one. + Method = Methods[0]; + if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods)) Method = BestMethod; + if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - receiverIsIdLike)) { - DiagnoseUseOfDecl(Method, SelLoc); - } + receiverIsIdLike, Methods)) + DiagnoseUseOfDecl(Method, SelLoc); } } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2681,25 +2694,32 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(SelLoc, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(LBracLoc, RBracLoc); - } + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + SmallVector<ObjCMethodDecl*, 4> Methods; + CollectMultipleMethodsInGlobalPool(Sel, Methods, + false/*InstanceFirst*/, + true/*CheckTheOther*/); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try + // to select a better one. + Method = Methods[0]; + + // If we find an instance method, emit waring. + if (Method->isInstanceMethod()) { + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(SelLoc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } + + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), + Methods)) + Method = BestMethod; } - if (Method) - if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) - Method = BestMethod; } } } @@ -2764,15 +2784,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method) { - if (auto BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + SmallVector<ObjCMethodDecl*, 4> Methods; + CollectMultipleMethodsInGlobalPool(Sel, Methods, + true/*InstanceFirst*/, + false/*CheckTheOther*/); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try + // to select a better one. + Method = Methods[0]; + + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), + Methods)) Method = BestMethod; + AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - true); + true/*receiverIdOrClass*/, + Methods); } if (Method && !forwardClass) Diag(SelLoc, diag::warn_maynot_respond) @@ -3052,11 +3081,13 @@ enum ARCConversionTypeClass { /// struct A* ACTC_coreFoundation }; + static bool isAnyRetainable(ARCConversionTypeClass ACTC) { return (ACTC == ACTC_retainable || ACTC == ACTC_coreFoundation || ACTC == ACTC_voidPtr); } + static bool isAnyCLike(ARCConversionTypeClass ACTC) { return ACTC == ACTC_none || ACTC == ACTC_voidPtr || @@ -3328,7 +3359,7 @@ namespace { } } }; -} +} // end anonymous namespace bool Sema::isKnownName(StringRef name) { if (name.empty()) @@ -3475,6 +3506,8 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, return; QualType castExprType = castExpr->getType(); + // Defer emitting a diagnostic for bridge-related casts; that will be + // handled by CheckObjCBridgeRelatedConversions. TypedefNameDecl *TDNDecl = nullptr; if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) || @@ -3780,7 +3813,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) { else if (PRE->isImplicitProperty()) { if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) SrcType = Getter->getReturnType(); - } } @@ -3790,7 +3822,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) { return; CheckObjCBridgeRelatedConversions(castExpr->getLocStart(), castType, SrcType, castExpr); - return; } bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, @@ -3919,16 +3950,16 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - QualType receiverType = Context.getObjCInterfaceType(RelatedClass); - // Argument. - Expr *args[] = { SrcExpr }; - ExprResult msg = BuildClassMessageImplicit(receiverType, false, + QualType receiverType = Context.getObjCInterfaceType(RelatedClass); + // Argument. + Expr *args[] = { SrcExpr }; + ExprResult msg = BuildClassMessageImplicit(receiverType, false, ClassMethod->getLocation(), ClassMethod->getSelector(), ClassMethod, MultiExprArg(args, 1)); - SrcExpr = msg.get(); + SrcExpr = msg.get(); + } return true; } } @@ -3962,14 +3993,14 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, } Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - ExprResult msg = - BuildInstanceMessageImplicit(SrcExpr, SrcType, - InstanceMethod->getLocation(), - InstanceMethod->getSelector(), - InstanceMethod, None); - SrcExpr = msg.get(); + ExprResult msg = + BuildInstanceMessageImplicit(SrcExpr, SrcType, + InstanceMethod->getLocation(), + InstanceMethod->getSelector(), + InstanceMethod, None); + SrcExpr = msg.get(); + } return true; } } @@ -3993,9 +4024,9 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); if (exprACTC == castACTC) { - // check for viablity and report error if casting an rvalue to a + // Check for viability and report error if casting an rvalue to a // life-time qualifier. - if (Diagnose && castACTC == ACTC_retainable && + if (castACTC == ACTC_retainable && (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) && castType != castExprType) { const Type *DT = castType.getTypePtr(); @@ -4011,10 +4042,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, QDT = AT->desugar(); if (QDT != castType && QDT.getObjCLifetime() != Qualifiers::OCL_None) { - SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() - : castExpr->getExprLoc()); - Diag(loc, diag::err_arc_nolifetime_behavior); + if (Diagnose) { + SourceLocation loc = (castRange.isValid() ? castRange.getBegin() + : castExpr->getExprLoc()); + Diag(loc, diag::err_arc_nolifetime_behavior); + } + return ACR_error; } } return ACR_okay; @@ -4051,7 +4084,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(), CK_ARCConsumeObject, castExpr, nullptr, VK_RValue); - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); return ACR_okay; } @@ -4062,24 +4095,26 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, CCK != CCK_ImplicitConversion) return ACR_unbridged; - // Do not issue bridge cast" diagnostic when implicit casting a cstring - // to 'NSString *'. Let caller issue a normal mismatched diagnostic with - // suitable fix-it. + // Issue a diagnostic about a missing @-sign when implicit casting a cstring + // to 'NSString *', instead of falling through to report a "bridge cast" + // diagnostic. if (castACTC == ACTC_retainable && exprACTC == ACTC_none && ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) - return ACR_okay; + return ACR_error; // 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 (Diagnose && - (!DiagnoseCFAudited || exprACTC != ACTC_retainable || - castACTC != ACTC_coreFoundation)) - if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && - (Opc == BO_NE || Opc == BO_EQ))) + if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable || + castACTC != ACTC_coreFoundation) && + !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && + (Opc == BO_NE || Opc == BO_EQ))) { + if (Diagnose) diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr, castExpr, exprACTC, CCK); + return ACR_error; + } return ACR_okay; } @@ -4292,7 +4327,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, TSInfo, SubExpr); if (MustConsume) { - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result, nullptr, VK_RValue); } |