diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2018-09-10 22:20:09 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2018-09-10 22:20:09 +0000 |
commit | 04c9c6990ba088f1a07e4acce1faf91ce5adb1b1 (patch) | |
tree | 0f6bcd0724533531535a9408f3af7bf5ef445a99 /lib/Sema/SemaDeclAttr.cpp | |
parent | fc73f1c46418634a9db66da860c9ce1ee57363f9 (diff) | |
download | clang-04c9c6990ba088f1a07e4acce1faf91ce5adb1b1.tar.gz |
[Sema][ObjC] Infer availability of +new from availability of -init.
When defined in NSObject, +new will call -init. If -init has been marked
unavailable, diagnose uses of +new.
rdar://18335828
Differential revision: https://reviews.llvm.org/D51189
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341874 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index db5df4db80..b58976a729 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/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; |