forked from OSchip/llvm-project
[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
This commit is contained in:
parent
2fa1436206
commit
7d89ce97ec
|
@ -180,14 +180,15 @@ LLVM_READONLY inline char toUppercase(char c) {
|
|||
|
||||
/// Return true if this is a valid ASCII identifier.
|
||||
///
|
||||
/// Note that this is a very simple check; it does not accept '$' or UCNs as
|
||||
/// valid identifier characters.
|
||||
LLVM_READONLY inline bool isValidIdentifier(StringRef S) {
|
||||
if (S.empty() || !isIdentifierHead(S[0]))
|
||||
/// Note that this is a very simple check; it does not accept UCNs as valid
|
||||
/// identifier characters.
|
||||
LLVM_READONLY inline bool isValidIdentifier(StringRef S,
|
||||
bool AllowDollar = false) {
|
||||
if (S.empty() || !isIdentifierHead(S[0], AllowDollar))
|
||||
return false;
|
||||
|
||||
for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I)
|
||||
if (!isIdentifierBody(*I))
|
||||
if (!isIdentifierBody(*I, AllowDollar))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
void Destroy();
|
||||
|
||||
static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
|
||||
SourceLocation Loc,
|
||||
ArrayRef<SourceLocation> Locs,
|
||||
const NamedDecl *ReferringDecl,
|
||||
const NamedDecl *OffendingDecl,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
|
@ -146,7 +147,6 @@ public:
|
|||
StringRef Msg,
|
||||
bool ObjCPropertyAccess);
|
||||
|
||||
|
||||
static DelayedDiagnostic makeAccess(SourceLocation Loc,
|
||||
const AccessedEntity &Entity) {
|
||||
DelayedDiagnostic DD;
|
||||
|
@ -194,6 +194,12 @@ public:
|
|||
return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen);
|
||||
}
|
||||
|
||||
ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const {
|
||||
assert(Kind == Availability && "Not an availability diagnostic.");
|
||||
return llvm::makeArrayRef(AvailabilityData.SelectorLocs,
|
||||
AvailabilityData.NumSelectorLocs);
|
||||
}
|
||||
|
||||
AvailabilityResult getAvailabilityResult() const {
|
||||
assert(Kind == Availability && "Not an availability diagnostic.");
|
||||
return AvailabilityData.AR;
|
||||
|
@ -238,6 +244,8 @@ private:
|
|||
const ObjCPropertyDecl *ObjCProperty;
|
||||
const char *Message;
|
||||
size_t MessageLen;
|
||||
SourceLocation *SelectorLocs;
|
||||
size_t NumSelectorLocs;
|
||||
AvailabilityResult AR;
|
||||
bool ObjCPropertyAccess;
|
||||
};
|
||||
|
|
|
@ -3947,7 +3947,7 @@ public:
|
|||
|
||||
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
|
||||
|
||||
void DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||
bool ObjCPropertyAccess,
|
||||
bool AvoidPartialAvailabilityChecks = false);
|
||||
|
@ -3962,7 +3962,7 @@ public:
|
|||
// Expression Parsing Callbacks: SemaExpr.cpp.
|
||||
|
||||
bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid);
|
||||
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
|
||||
bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||
const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
|
||||
bool ObjCPropertyAccess = false,
|
||||
bool AvoidPartialAvailabilityChecks = false);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -verify -fsyntax-only %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --implicit-check-not fix-it: %s
|
||||
// RUN: cp %s %t
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DIGNORE_UNSUCCESSFUL_RENAMES -fixit -x objective-c %t
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DIGNORE_UNSUCCESSFUL_RENAMES -Werror -x objective-c %t
|
||||
|
||||
#if !__has_feature(attribute_deprecated_with_replacement)
|
||||
#error "Missing __has_feature"
|
||||
#endif
|
||||
|
||||
#if !__has_feature(attribute_availability_with_replacement)
|
||||
#error "Missing __has_feature"
|
||||
#endif
|
||||
|
||||
#define DEPRECATED(replacement) __attribute__((deprecated("message", replacement)))
|
||||
|
||||
@protocol SuccessfulMultiParameterRenames
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)multi:(int)param1 parameter:(int)param2 replacement:(int)param3 DEPRECATED("multi_new:parameter_new:replace_new_ment:");
|
||||
- (void)multi_new:(int)param1 parameter_new:(int)param2 replace_new_ment:(int)param3;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)varArgs:(int)params, ... DEPRECATED("renameVarArgs:");
|
||||
- (void)renameVarArgs:(int)params, ...;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)leadingMinus:(int)param DEPRECATED("-leadingMinusRenamed:");
|
||||
- (void)leadingMinusRenamed:(int)param;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)leadingPlus:(int)param DEPRECATED("+leadingPlusRenamed:");
|
||||
- (void)leadingPlusRenamed:(int)param;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)sourceEmptyName:(int)param1 :(int)param2 DEPRECATED("renameEmptyName:toNonEmpty:");
|
||||
- (void)renameEmptyName:(int)param1 toNonEmpty:(int)param2;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)target:(int)param1 willBecomeEmpty:(int)param2 emptyName:(int)param3 DEPRECATED("target::emptyName:");
|
||||
- (void)target:(int)param1 :(int)param2 emptyName:(int)param3;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)extra:(int)param1 whiteSpace:(int)param2 DEPRECATED("renameExtra:whiteSpace:");
|
||||
- (void)renameExtra:(int)param1 whiteSpace:(int)param2;
|
||||
|
||||
// Test renaming that was producing valid code earlier is still producing valid
|
||||
// code. The difference is that now we detect different number of parameters.
|
||||
//
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)singleArgumentRegression:(int)param DEPRECATED("renameSingleArgument");
|
||||
- (void)renameSingleArgument:(int)param;
|
||||
@end
|
||||
|
||||
void successfulRenames(id<SuccessfulMultiParameterRenames> object) {
|
||||
[object multi:0 parameter:1 replacement:2]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:16}:"multi_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:28}:"parameter_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:42}:"replace_new_ment"
|
||||
|
||||
[object varArgs:1, 2, 3, 0]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:18}:"renameVarArgs"
|
||||
|
||||
[object leadingMinus:0]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:23}:"leadingMinusRenamed"
|
||||
|
||||
[object leadingPlus:0]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:22}:"leadingPlusRenamed"
|
||||
|
||||
[object sourceEmptyName:0 :1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:26}:"renameEmptyName"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:29-[[@LINE-2]]:29}:"toNonEmpty"
|
||||
|
||||
[object target:0 willBecomeEmpty:1 emptyName:2]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:17}:"target"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:20-[[@LINE-2]]:35}:""
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:38-[[@LINE-3]]:47}:"emptyName"
|
||||
|
||||
[object extra: 0 whiteSpace: 1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:16}:"renameExtra"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:33}:"whiteSpace"
|
||||
|
||||
[object singleArgumentRegression:0]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:35}:"renameSingleArgument"
|
||||
}
|
||||
|
||||
#ifndef IGNORE_UNSUCCESSFUL_RENAMES
|
||||
@protocol UnsuccessfulMultiParameterRenames
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)differentNumberOfParameters:(int)param DEPRECATED("rename:hasMoreParameters:");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)differentNumber:(int)param1 ofParameters:(int)param2 DEPRECATED("renameHasLessParameters:");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)methodLike:(int)param1 replacement:(int)param2 DEPRECATED("noColon:atTheEnd");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)freeFormText DEPRECATED("Use something else");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)freeFormTextReplacementStartsAsMethod DEPRECATED("-Use something different");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)replacementHasSingleSkipCharacter DEPRECATED("-");
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)replacementHasInvalid:(int)param1 slotName:(int)param2 DEPRECATED("renameWith:1nonIdentifier:");
|
||||
@end
|
||||
|
||||
void unsuccessfulRenames(id<UnsuccessfulMultiParameterRenames> object) {
|
||||
[object differentNumberOfParameters:0]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:38}:"rename:hasMoreParameters:"
|
||||
|
||||
[object differentNumber:0 ofParameters:1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:26}:"renameHasLessParameters:"
|
||||
|
||||
[object methodLike:0 replacement:1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:21}:"noColon:atTheEnd"
|
||||
|
||||
[object freeFormText]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:23}:"Use something else"
|
||||
|
||||
[object freeFormTextReplacementStartsAsMethod]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:48}:"-Use something different"
|
||||
|
||||
[object replacementHasSingleSkipCharacter]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:44}:"-"
|
||||
|
||||
[object replacementHasInvalid:0 slotName:1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:32}:"renameWith:1nonIdentifier:"
|
||||
}
|
||||
#endif // IGNORE_UNSUCCESSFUL_RENAMES
|
||||
|
||||
// Make sure classes are treated the same way as protocols.
|
||||
__attribute__((objc_root_class))
|
||||
@interface Interface
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
+ (void)classMethod:(int)param1 replacement:(int)param2 DEPRECATED("renameClassMethod:replace_new_ment:");
|
||||
+ (void)renameClassMethod:(int)param1 replace_new_ment:(int)param2;
|
||||
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)multi:(int)param1 parameter:(int)param2 replacement:(int)param3 DEPRECATED("multi_new:parameter_new:replace_new_ment:");
|
||||
- (void)multi_new:(int)param1 parameter_new:(int)param2 replace_new_ment:(int)param3;
|
||||
@end
|
||||
|
||||
@implementation Interface
|
||||
+ (void)classMethod:(int)param1 replacement:(int)param2 {}
|
||||
+ (void)renameClassMethod:(int)param1 replace_new_ment:(int)param2 {}
|
||||
|
||||
- (void)multi:(int)param1 parameter:(int)param2 replacement:(int)param3 {}
|
||||
- (void)multi_new:(int)param1 parameter_new:(int)param2 replace_new_ment:(int)param3 {}
|
||||
|
||||
- (void)usage {
|
||||
[Interface classMethod:0 replacement:1]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:14-[[@LINE-1]]:25}:"renameClassMethod"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:28-[[@LINE-2]]:39}:"replace_new_ment"
|
||||
|
||||
[self multi:0 parameter:1 replacement:2]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:14}:"multi_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:26}:"parameter_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:40}:"replace_new_ment"
|
||||
}
|
||||
@end
|
||||
|
||||
// Make sure availability attribute is handled the same way as deprecation attribute.
|
||||
@protocol AvailabilityAttributeRenames
|
||||
// expected-note@+1 {{has been explicitly marked deprecated here}}
|
||||
- (void)multi:(int)param1 parameter:(int)param2 replacement:(int)param3 __attribute__((availability(macosx,deprecated=9.0,replacement="multi_new:parameter_new:replace_new_ment:")));
|
||||
- (void)multi_new:(int)param1 parameter_new:(int)param2 replace_new_ment:(int)param3;
|
||||
@end
|
||||
|
||||
void availabilityAttributeRenames(id<AvailabilityAttributeRenames> object) {
|
||||
[object multi:0 parameter:1 replacement:2]; // expected-warning {{is deprecated}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:16}:"multi_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:28}:"parameter_new"
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:31-[[@LINE-3]]:42}:"replace_new_ment"
|
||||
}
|
|
@ -432,6 +432,7 @@ TEST(CharInfoTest, isValidIdentifier) {
|
|||
EXPECT_TRUE(isValidIdentifier("z"));
|
||||
EXPECT_TRUE(isValidIdentifier("A"));
|
||||
EXPECT_TRUE(isValidIdentifier("Z"));
|
||||
EXPECT_TRUE(isValidIdentifier("$", /*AllowDollar=*/true));
|
||||
|
||||
// 2 characters, '_' suffix
|
||||
EXPECT_FALSE(isValidIdentifier("._"));
|
||||
|
@ -448,6 +449,7 @@ TEST(CharInfoTest, isValidIdentifier) {
|
|||
EXPECT_TRUE(isValidIdentifier("z_"));
|
||||
EXPECT_TRUE(isValidIdentifier("A_"));
|
||||
EXPECT_TRUE(isValidIdentifier("Z_"));
|
||||
EXPECT_TRUE(isValidIdentifier("$_", /*AllowDollar=*/true));
|
||||
|
||||
// 2 characters, '_' prefix
|
||||
EXPECT_FALSE(isValidIdentifier("_."));
|
||||
|
@ -464,6 +466,7 @@ TEST(CharInfoTest, isValidIdentifier) {
|
|||
EXPECT_TRUE(isValidIdentifier("_z"));
|
||||
EXPECT_TRUE(isValidIdentifier("_A"));
|
||||
EXPECT_TRUE(isValidIdentifier("_Z"));
|
||||
EXPECT_TRUE(isValidIdentifier("_$", /*AllowDollar=*/true));
|
||||
|
||||
// 3 characters, '__' prefix
|
||||
EXPECT_FALSE(isValidIdentifier("__."));
|
||||
|
@ -480,6 +483,7 @@ TEST(CharInfoTest, isValidIdentifier) {
|
|||
EXPECT_TRUE(isValidIdentifier("__z"));
|
||||
EXPECT_TRUE(isValidIdentifier("__A"));
|
||||
EXPECT_TRUE(isValidIdentifier("__Z"));
|
||||
EXPECT_TRUE(isValidIdentifier("__$", /*AllowDollar=*/true));
|
||||
|
||||
// 3 characters, '_' prefix and suffix
|
||||
EXPECT_FALSE(isValidIdentifier("_._"));
|
||||
|
@ -496,4 +500,5 @@ TEST(CharInfoTest, isValidIdentifier) {
|
|||
EXPECT_TRUE(isValidIdentifier("_z_"));
|
||||
EXPECT_TRUE(isValidIdentifier("_A_"));
|
||||
EXPECT_TRUE(isValidIdentifier("_Z_"));
|
||||
EXPECT_TRUE(isValidIdentifier("_$_", /*AllowDollar=*/true));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue