diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 43 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 12 |
3 files changed, 47 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index db5df4db802..b58976a729b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6967,8 +6967,12 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, /// \param D The declaration to check. /// \param Message If non-null, this will be populated with the message from /// the availability attribute that is selected. +/// \param ClassReceiver If we're checking the the method of a class message +/// send, the class. Otherwise nullptr. static std::pair<AvailabilityResult, const NamedDecl *> -ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { +ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, + std::string *Message, + ObjCInterfaceDecl *ClassReceiver) { AvailabilityResult Result = D->getAvailability(Message); // For typedefs, if the typedef declaration appears available look @@ -7001,6 +7005,20 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } } + // For +new, infer availability from -init. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (S.NSAPIObj && ClassReceiver) { + ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( + S.NSAPIObj->getInitSelector()); + if (Init && Result == AR_Available && MD->isClassMethod() && + MD->getSelector() == S.NSAPIObj->getNewSelector() && + MD->definedInNSObject(S.getASTContext())) { + Result = Init->getAvailability(Message); + D = Init; + } + } + } + return {Result, D}; } @@ -7589,7 +7607,8 @@ class DiagnoseUnguardedAvailability SmallVector<VersionTuple, 8> AvailabilityStack; SmallVector<const Stmt *, 16> StmtStack; - void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range); + void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range, + ObjCInterfaceDecl *ClassReceiver = nullptr); public: DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) @@ -7631,9 +7650,15 @@ public: } bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { - if (ObjCMethodDecl *D = Msg->getMethodDecl()) + if (ObjCMethodDecl *D = Msg->getMethodDecl()) { + ObjCInterfaceDecl *ID = nullptr; + QualType ReceiverTy = Msg->getClassReceiver(); + if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType()) + ID = ReceiverTy->getAsObjCInterfaceType()->getInterface(); + DiagnoseDeclAvailability( - D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc())); + D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID); + } return true; } @@ -7659,11 +7684,11 @@ public: }; void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( - NamedDecl *D, SourceRange Range) { + NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) { AvailabilityResult Result; const NamedDecl *OffendingDecl; std::tie(Result, OffendingDecl) = - ShouldDiagnoseAvailabilityOfDecl(D, nullptr); + ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass); if (Result != AR_Available) { // All other diagnostic kinds have already been handled in // DiagnoseAvailabilityOfDecl. @@ -7845,12 +7870,14 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, - bool AvoidPartialAvailabilityChecks) { + bool AvoidPartialAvailabilityChecks, + ObjCInterfaceDecl *ClassReceiver) { std::string Message; AvailabilityResult Result; const NamedDecl* OffendingDecl; // See if this declaration is unavailable, deprecated, or partial. - std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(D, &Message); + std::tie(Result, OffendingDecl) = + ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); if (Result == AR_Available) return; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index fe48e47ff4f..45510da0b1a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -206,7 +206,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, - bool AvoidPartialAvailabilityChecks) { + bool AvoidPartialAvailabilityChecks, + ObjCInterfaceDecl *ClassReceiver) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, @@ -292,7 +293,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, } DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, - AvoidPartialAvailabilityChecks); + AvoidPartialAvailabilityChecks, ClassReceiver); DiagnoseUnusedOfDecl(*this, D, Loc); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 13a009090f9..bee75e4ae60 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2471,7 +2471,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!Method) Method = Class->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, + nullptr, false, false, Class)) return ExprError(); } @@ -2784,14 +2785,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } else { if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // FIXME: Is this correct? Why are we assuming that a message to + // Class will call a method in the current interface? + // First check the public methods in the class interface. Method = ClassDecl->lookupClassMethod(Sel); if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); + + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, nullptr, + false, false, ClassDecl)) + return ExprError(); } - if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) - return ExprError(); } if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. |