diff options
Diffstat (limited to 'lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 136 |
1 files changed, 118 insertions, 18 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 7dbd660f53ec..9cc443ed4fd9 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1984,13 +1984,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, } } + Selector GetterSel; + Selector SetterSel; + if (auto PD = IFace->FindPropertyDeclaration( + &propertyName, ObjCPropertyQueryKind::OBJC_PR_query_class)) { + GetterSel = PD->getGetterName(); + SetterSel = PD->getSetterName(); + } else { + GetterSel = PP.getSelectorTable().getNullarySelector(&propertyName); + SetterSel = SelectorTable::constructSetterSelector( + PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName); + } + // Search for a declared property first. - Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); - ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel); + ObjCMethodDecl *Getter = IFace->lookupClassMethod(GetterSel); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) - Getter = IFace->lookupPrivateClassMethod(Sel); + Getter = IFace->lookupPrivateClassMethod(GetterSel); if (Getter) { // FIXME: refactor/share with ActOnMemberReference(). @@ -2000,11 +2011,6 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, } // Look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterSelector(PP.getIdentifierTable(), - PP.getSelectorTable(), - &propertyName); - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); if (!Setter) { // If this reference is in an @implementation, also check for 'private' @@ -2260,6 +2266,53 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { edit::rewriteObjCRedundantCallWithLiteral); } +static void checkFoundationAPI(Sema &S, SourceLocation Loc, + const ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, QualType ReceiverType, + bool IsClassObjectCall) { + // Check if this is a performSelector method that uses a selector that returns + // a record or a vector type. + if (Method->getSelector().getMethodFamily() != OMF_performSelector || + Args.empty()) + return; + const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens()); + if (!SE) + return; + ObjCMethodDecl *ImpliedMethod; + if (!IsClassObjectCall) { + const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>(); + if (!OPT || !OPT->getInterfaceDecl()) + return; + ImpliedMethod = + OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector()); + if (!ImpliedMethod) + ImpliedMethod = + OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector()); + } else { + const auto *IT = ReceiverType->getAs<ObjCInterfaceType>(); + if (!IT) + return; + ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector()); + if (!ImpliedMethod) + ImpliedMethod = + IT->getDecl()->lookupPrivateClassMethod(SE->getSelector()); + } + if (!ImpliedMethod) + return; + QualType Ret = ImpliedMethod->getReturnType(); + if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) { + QualType Ret = ImpliedMethod->getReturnType(); + S.Diag(Loc, diag::warn_objc_unsafe_perform_selector) + << Method->getSelector() + << (!Ret->isRecordType() + ? /*Vector*/ 2 + : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0); + S.Diag(ImpliedMethod->getLocStart(), + diag::note_objc_unsafe_perform_selector_method_declared_here) + << ImpliedMethod->getSelector() << Ret; + } +} + /// \brief Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void @@ -2462,6 +2515,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!isImplicit) checkCocoaAPI(*this, Result); } + if (Method) + checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + ReceiverType, /*IsClassObjectCall=*/true); return MaybeBindToTemporary(Result); } @@ -2501,6 +2557,24 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver, /*isImplicit=*/true); } +static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) { + if (!S.NSAPIObj) + return false; + const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext()); + if (!Protocol) + return false; + const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); + if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>( + S.LookupSingleName(S.TUScope, II, Protocol->getLocStart(), + Sema::LookupOrdinaryName))) { + for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) { + if (P->getCanonicalDecl() == Protocol->getCanonicalDecl()) + return true; + } + } + return false; +} + /// \brief Build an Objective-C instance message expression. /// /// This routine takes care of both normal instance messages and @@ -2676,7 +2750,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { Method = LookupMethodInQualifiedType(Sel, QClassTy, true); // warn if instance method found for a Class message. - if (Method) { + if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) { Diag(SelLoc, diag::warn_instance_method_on_class_found) << Method->getSelector() << Sel; Diag(Method->getLocation(), diag::note_method_declared_at) @@ -2920,7 +2994,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_performSelector: if (Method && NumArgs >= 1) { - if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) { + if (const auto *SelExp = + dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens())) { Selector ArgSel = SelExp->getSelector(); ObjCMethodDecl *SelMethod = LookupInstanceMethodInGlobalPool(ArgSel, @@ -2936,7 +3011,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_copy: case OMF_mutableCopy: case OMF_new: - case OMF_self: case OMF_init: // Issue error, unless ns_returns_not_retained. if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { @@ -2987,6 +3061,26 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!isImplicit) checkCocoaAPI(*this, Result); } + if (Method) { + bool IsClassObjectCall = ClassMessage; + // 'self' message receivers in class methods should be treated as message + // sends to the class object in order for the semantic checks to be + // performed correctly. Messages to 'super' already count as class messages, + // so they don't need to be handled here. + if (Receiver && isSelfExpr(Receiver)) { + if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) { + if (OPT->getObjectType()->isObjCClass()) { + if (const auto *CurMeth = getCurMethodDecl()) { + IsClassObjectCall = true; + ReceiverType = + Context.getObjCInterfaceType(CurMeth->getClassInterface()); + } + } + } + } + checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + ReceiverType, IsClassObjectCall); + } if (getLangOpts().ObjCAutoRefCount) { // In ARC, annotate delegate init calls. @@ -3006,7 +3100,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // In ARC, check for message sends which are likely to introduce // retain cycles. checkRetainCycles(Result); + } + if (getLangOpts().ObjCWeak) { if (!isImplicit && Method) { if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) { bool IsWeak = @@ -3259,7 +3355,7 @@ namespace { if (isAnyRetainable(TargetClass) && isAnyRetainable(SourceClass) && var && - var->getStorageClass() == SC_Extern && + !var->hasDefinition(Context) && var->getType().isConstQualified()) { // In system headers, they can also be assumed to be immune to retains. @@ -4012,11 +4108,10 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, } Sema::ARCConversionResult -Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, - Expr *&castExpr, CheckedConversionKind CCK, - bool Diagnose, - bool DiagnoseCFAudited, - BinaryOperatorKind Opc) { +Sema::CheckObjCConversion(SourceRange castRange, QualType castType, + Expr *&castExpr, CheckedConversionKind CCK, + bool Diagnose, bool DiagnoseCFAudited, + BinaryOperatorKind Opc) { QualType castExprType = castExpr->getType(); // For the purposes of the classification, we assume reference types @@ -4056,7 +4151,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, } return ACR_okay; } - + + // The life-time qualifier cast check above is all we need for ObjCWeak. + // ObjCAutoRefCount has more restrictions on what is legal. + if (!getLangOpts().ObjCAutoRefCount) + return ACR_okay; + if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay; // Allow all of these types to be cast to integer types (but not |