From: Fariborz Jahanian Date: Tue, 21 Dec 2010 00:44:01 +0000 (+0000) Subject: Warn when message is sent to receiver of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e5fc9be37c6828ad008f22730e3baac1bef1686;p=clang Warn when message is sent to receiver of unknown type and there is a possibility that at runtime method is resolved to a deprecated or unavailable method. Addreses // rdar://8769853 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122294 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a6f4cc8130..b53fb416be 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1878,10 +1878,15 @@ def warn_deprecated : Warning<"%0 is deprecated">, InGroup; def warn_deprecated_message : Warning<"%0 is deprecated: %1">, InGroup; +def warn_deprecated_fwdclass_message : Warning< + "%0 maybe deprecated because receiver type is unknown">, + InGroup; def err_unavailable : Error<"%0 is unavailable">; def err_unavailable_message : Error<"%0 is unavailable: %1">; +def warn_unavailable_fwdclass_message : Warning< + "%0 maybe unavailable because receiver type is unknown">; def note_unavailable_here : Note< - "function has been explicitly marked %select{unavailable|deleted}0 here">; + "function has been explicitly marked %select{unavailable|deleted|deprecated}0 here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">; def warn_missing_sentinel : Warning < diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 77ecde89e1..24f1b217e0 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1704,14 +1704,15 @@ public: ParsingDeclStackState PushParsingDeclaration(); void PopParsingDeclaration(ParsingDeclStackState S, Decl *D); void EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, - SourceLocation Loc); + SourceLocation Loc, bool UnkownObjCClass=false); void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. - bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + bool UnkownObjCClass=false); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index e77a660ada..06cb42ec0e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -2903,7 +2903,8 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, } void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, - SourceLocation Loc) { + SourceLocation Loc, + bool UnkownObjCClass) { // Delay if we're currently parsing a declaration. if (ParsingDeclDepth) { DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D, @@ -2917,6 +2918,10 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, if (!Message.empty()) Diag(Loc, diag::warn_deprecated_message) << D->getDeclName() << Message; - else - Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + else { + if (!UnkownObjCClass) + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + else + Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName(); + } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 38e91465d2..5d9a924ed8 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1302,7 +1302,21 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, // signature. for (ObjCMethodList *List = &Entry; List; List = List->Next) if (MatchTwoMethodDeclarations(Method, List->Method)) { - List->Method->setDefined(impl); + ObjCMethodDecl *PrevObjCMethod = List->Method; + PrevObjCMethod->setDefined(impl); + // If a method is deprecated, push it in the global pool. + // This is used for better diagnostics. + if (Method->getAttr()) { + if (!PrevObjCMethod->getAttr()) + List->Method = Method; + } + // If new method is unavailable, push it into global pool + // unless previous one is deprecated. + if (Method->getAttr()) { + if (!PrevObjCMethod->getAttr() && + !PrevObjCMethod->getAttr()) + List->Method = Method; + } return; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 01a505bb08..56ad9b4241 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -49,13 +49,14 @@ using namespace sema; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// -/// If IgnoreDeprecated is set to true, this should not want about deprecated +/// If IgnoreDeprecated is set to true, this should not warn about deprecated /// decls. /// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// -bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { +bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + bool UnkownObjCClass) { if (getLangOptions().CPlusPlus && isa(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -76,13 +77,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // See if the decl is deprecated. if (const DeprecatedAttr *DA = D->getAttr()) - EmitDeprecationWarning(D, DA->getMessage(), Loc); + EmitDeprecationWarning(D, DA->getMessage(), Loc, UnkownObjCClass); // See if the decl is unavailable if (const UnavailableAttr *UA = D->getAttr()) { - if (UA->getMessage().empty()) - Diag(Loc, diag::err_unavailable) << D->getDeclName(); - else + if (UA->getMessage().empty()) { + if (!UnkownObjCClass) + Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else Diag(Loc, diag::err_unavailable_message) << D->getDeclName() << UA->getMessage(); Diag(D->getLocation(), diag::note_unavailable_here) << 0; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index baa34f9ce8..bbb047990b 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1023,6 +1023,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, break; } } + bool forwardClass = false; if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); @@ -1033,14 +1034,15 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) + SourceRange(LBracLoc, RBracLoc)); + forwardClass = OCIType->getInterfaceDecl()->isForwardDecl(); + if (Method && !forwardClass) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; } } } - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || diff --git a/test/SemaObjC/special-dep-unavail-warning.m b/test/SemaObjC/special-dep-unavail-warning.m new file mode 100644 index 0000000000..b7a2d66344 --- /dev/null +++ b/test/SemaObjC/special-dep-unavail-warning.m @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// rdar://8769853 + +@interface B +- (void) depInA; +- (void) unavailMeth __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}} +- (void) depInA1 __attribute__((deprecated)); +- (void) unavailMeth1; +- (void) depInA2 __attribute__((deprecated)); +- (void) unavailMeth2 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}} +- (void) depunavailInA; +- (void) depunavailInA1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}} +- (void)FuzzyMeth __attribute__((deprecated)); +- (void)FuzzyMeth1 __attribute__((unavailable)); +@end + +@interface A +- (void) unavailMeth1 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}} +- (void) depInA __attribute__((deprecated)); +- (void) depInA2 __attribute__((deprecated)); +- (void) depInA1; +- (void) unavailMeth2 __attribute__((unavailable)); +- (void) depunavailInA __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}} +- (void) depunavailInA1; +- (void)FuzzyMeth __attribute__((unavailable)); +- (void)FuzzyMeth1 __attribute__((deprecated)); +@end + + +@class C; + +void test(C *c) { + [c depInA]; // expected-warning {{'depInA' maybe deprecated because receiver type is unknown}} + [c unavailMeth]; // expected-warning {{'unavailMeth' maybe unavailable because receiver type is unknown}} + [c depInA1]; // expected-warning {{'depInA1' maybe deprecated because receiver type is unknown}} + [c unavailMeth1]; // expected-warning {{'unavailMeth1' maybe unavailable because receiver type is unknown}} + [c depInA2]; // expected-warning {{'depInA2' maybe deprecated because receiver type is unknown}} + [c unavailMeth2]; // expected-warning {{'unavailMeth2' maybe unavailable because receiver type is unknown}} + [c depunavailInA]; // expected-warning {{'depunavailInA' maybe deprecated because receiver type is unknown}} \ + // expected-warning {{'depunavailInA' maybe unavailable because receiver type is unknown}} + [c depunavailInA1]; // expected-warning {{'depunavailInA1' maybe deprecated because receiver type is unknown}} \ + // expected-warning {{'depunavailInA1' maybe unavailable because receiver type is unknown}} + [c FuzzyMeth]; // expected-warning {{'FuzzyMeth' maybe deprecated because receiver type is unknown}} + [c FuzzyMeth1]; // expected-warning {{'FuzzyMeth1' maybe deprecated because receiver type is unknown}} + +} +