diff options
| author | Volodymyr Sapsai <vsapsai@apple.com> | 2018-03-29 17:34:09 +0000 |
|---|---|---|
| committer | Volodymyr Sapsai <vsapsai@apple.com> | 2018-03-29 17:34:09 +0000 |
| commit | 7d89ce97ecab86c0b48bce46ab51535ec9950c68 (patch) | |
| tree | be47aa354efb4f3d41cf7f9a1f45eeb16645e424 /clang/lib | |
| parent | 2fa1436206177291edb2d78c84d5822bb6e58cc9 (diff) | |
| download | bcm5719-llvm-7d89ce97ecab86c0b48bce46ab51535ec9950c68.tar.gz bcm5719-llvm-7d89ce97ecab86c0b48bce46ab51535ec9950c68.zip | |
[Sema] Make deprecation fix-it replace all multi-parameter ObjC method slots.
Deprecation replacement can be any text but if it looks like a name of
ObjC method and has the same number of arguments as original method,
replace all slot names so after applying a fix-it you have valid code.
rdar://problem/36660853
Reviewers: aaron.ballman, erik.pilkington, rsmith
Reviewed By: erik.pilkington
Subscribers: cfe-commits, jkorous-apple
Differential Revision: https://reviews.llvm.org/D44589
llvm-svn: 328807
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/DelayedDiagnostic.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 101 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 26 |
4 files changed, 109 insertions, 36 deletions
diff --git a/clang/lib/Sema/DelayedDiagnostic.cpp b/clang/lib/Sema/DelayedDiagnostic.cpp index 25552063400..122b477d552 100644 --- a/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/clang/lib/Sema/DelayedDiagnostic.cpp @@ -23,17 +23,18 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeAvailability(AvailabilityResult AR, - SourceLocation Loc, + ArrayRef<SourceLocation> Locs, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, bool ObjCPropertyAccess) { + assert(!Locs.empty()); DelayedDiagnostic DD; DD.Kind = Availability; DD.Triggered = false; - DD.Loc = Loc; + DD.Loc = Locs.front(); DD.AvailabilityData.ReferringDecl = ReferringDecl; DD.AvailabilityData.OffendingDecl = OffendingDecl; DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; @@ -43,9 +44,14 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR, MessageData = new char [Msg.size()]; memcpy(MessageData, Msg.data(), Msg.size()); } - DD.AvailabilityData.Message = MessageData; DD.AvailabilityData.MessageLen = Msg.size(); + + DD.AvailabilityData.SelectorLocs = new SourceLocation[Locs.size()]; + memcpy(DD.AvailabilityData.SelectorLocs, Locs.data(), + sizeof(SourceLocation) * Locs.size()); + DD.AvailabilityData.NumSelectorLocs = Locs.size(); + DD.AvailabilityData.AR = AR; DD.AvailabilityData.ObjCPropertyAccess = ObjCPropertyAccess; return DD; @@ -59,6 +65,7 @@ void DelayedDiagnostic::Destroy() { case Availability: delete[] AvailabilityData.Message; + delete[] AvailabilityData.SelectorLocs; break; case ForbiddenType: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 512a3df0744..1d2c3b55342 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6931,6 +6931,45 @@ struct AttributeInsertion { } // end anonymous namespace +/// Tries to parse a string as ObjC method name. +/// +/// \param Name The string to parse. Expected to originate from availability +/// attribute argument. +/// \param SlotNames The vector that will be populated with slot names. In case +/// of unsuccessful parsing can contain invalid data. +/// \returns A number of method parameters if parsing was successful, None +/// otherwise. +static Optional<unsigned> +tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, + const LangOptions &LangOpts) { + // Accept replacements starting with - or + as valid ObjC method names. + if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) + Name = Name.drop_front(1); + if (Name.empty()) + return None; + Name.split(SlotNames, ':'); + unsigned NumParams; + if (Name.back() == ':') { + // Remove an empty string at the end that doesn't represent any slot. + SlotNames.pop_back(); + NumParams = SlotNames.size(); + } else { + if (SlotNames.size() != 1) + // Not a valid method name, just a colon-separated string. + return None; + NumParams = 0; + } + // Verify all slot names are valid. + bool AllowDollar = LangOpts.DollarIdents; + for (StringRef S : SlotNames) { + if (S.empty()) + continue; + if (!isValidIdentifier(S, AllowDollar)) + return None; + } + return NumParams; +} + /// Returns a source location in which it's appropriate to insert a new /// attribute for the given declaration \D. static Optional<AttributeInsertion> @@ -6967,7 +7006,8 @@ createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -6989,6 +7029,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + SourceLocation Loc = Locs.front(); + // The declaration can have multiple availability attributes, we are looking // at one of them. const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); @@ -7134,37 +7176,55 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, llvm_unreachable("Warning for availability of available declaration?"); } - CharSourceRange UseRange; - StringRef Replacement; + SmallVector<FixItHint, 12> FixIts; if (K == AR_Deprecated) { + StringRef Replacement; if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) Replacement = AL->getReplacement(); if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) Replacement = AL->getReplacement(); + CharSourceRange UseRange; if (!Replacement.empty()) UseRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + if (UseRange.isValid()) { + if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { + Selector Sel = MethodDecl->getSelector(); + SmallVector<StringRef, 12> SelectorSlotNames; + Optional<unsigned> NumParams = tryParseObjCMethodName( + Replacement, SelectorSlotNames, S.getLangOpts()); + if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { + assert(SelectorSlotNames.size() == Locs.size()); + for (unsigned I = 0; I < Locs.size(); ++I) { + if (!Sel.getNameForSlot(I).empty()) { + CharSourceRange NameRange = CharSourceRange::getCharRange( + Locs[I], S.getLocForEndOfToken(Locs[I])); + FixIts.push_back(FixItHint::CreateReplacement( + NameRange, SelectorSlotNames[I])); + } else + FixIts.push_back( + FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); + } + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } } if (!Message.empty()) { - S.Diag(Loc, diag_message) << ReferringDecl << Message - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag) << ReferringDecl << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } @@ -7180,8 +7240,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), - DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), + DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7242,7 +7303,8 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7250,14 +7312,14 @@ static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( DelayedDiagnostic::makeAvailability( - AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Loc, UnknownObjCClass, ObjCProperty, + Message, Locs, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } @@ -7595,7 +7657,8 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); } -void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, +void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { @@ -7632,6 +7695,6 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } } - EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc, + EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d87c21c0b17..c5f581f4232 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -202,10 +202,11 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { /// \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, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { + SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -289,7 +290,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } - DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess, + DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, AvoidPartialAvailabilityChecks); DiagnoseUnusedOfDecl(*this, D, Loc); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 8d017af9912..14db4145ed9 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2408,11 +2408,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } - SourceLocation SelLoc; + ArrayRef<SourceLocation> SelectorSlotLocs; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelLoc = SelectorLocs.front(); + SelectorSlotLocs = SelectorLocs; else - SelLoc = Loc; + SelectorSlotLocs = Loc; + SourceLocation SelLoc = SelectorSlotLocs.front(); if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything @@ -2437,7 +2438,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(Class && "We don't know which class we're messaging?"); // objc++ diagnoses during typename annotation. if (!getLangOpts().CPlusPlus) - (void)DiagnoseUseOfDecl(Class, SelLoc); + (void)DiagnoseUseOfDecl(Class, SelectorSlotLocs); // Find the method we are messaging. if (!Method) { SourceRange TypeRange @@ -2462,7 +2463,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!Method) Method = Class->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } @@ -2632,11 +2633,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); SourceRange RecRange = SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange(); - SourceLocation SelLoc; + ArrayRef<SourceLocation> SelectorSlotLocs; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelLoc = SelectorLocs.front(); + SelectorSlotLocs = SelectorLocs; else - SelLoc = Loc; + SelectorSlotLocs = Loc; + SourceLocation SelLoc = SelectorSlotLocs.front(); if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) @@ -2748,7 +2750,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), receiverIsIdLike, Methods)) - DiagnoseUseOfDecl(Method, SelLoc); + DiagnoseUseOfDecl(Method, SelectorSlotLocs); } } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2780,7 +2782,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); } - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } if (!Method) { @@ -2827,7 +2829,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { @@ -2902,7 +2904,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } } - if (Method && DiagnoseUseOfDecl(Method, SelLoc, forwardClass)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, forwardClass)) return ExprError(); } else { // Reject other random receiver types (e.g. structs). |

