[objcmt] Check for classes that accept 'objectForKey:' (or the other selectors
that the migrator handles) but return their instances as 'id', resulting in the compiler resolving 'objectForKey:' as the method from NSDictionary. When checking if we can convert to subscripting syntax, check whether the receiver is a result of a class method from a hardcoded list of such classes. In such a case return the specific class as the interface of the receiver. llvm-svn: 159788
This commit is contained in:
parent
b2af512cef
commit
89b928eb6a
|
@ -94,8 +94,73 @@ bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
|
||||||
// rewriteToObjCSubscriptSyntax.
|
// rewriteToObjCSubscriptSyntax.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *IFace,
|
/// \brief Check for classes that accept 'objectForKey:' (or the other selectors
|
||||||
|
/// that the migrator handles) but return their instances as 'id', resulting
|
||||||
|
/// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
|
||||||
|
///
|
||||||
|
/// When checking if we can convert to subscripting syntax, check whether
|
||||||
|
/// the receiver is a result of a class method from a hardcoded list of
|
||||||
|
/// such classes. In such a case return the specific class as the interface
|
||||||
|
/// of the receiver.
|
||||||
|
///
|
||||||
|
/// FIXME: Remove this when these classes start using 'instancetype'.
|
||||||
|
static const ObjCInterfaceDecl *
|
||||||
|
maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
|
||||||
|
const Expr *Receiver,
|
||||||
|
ASTContext &Ctx) {
|
||||||
|
assert(IFace && Receiver);
|
||||||
|
|
||||||
|
// If the receiver has type 'id'...
|
||||||
|
if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
|
||||||
|
return IFace;
|
||||||
|
|
||||||
|
const ObjCMessageExpr *
|
||||||
|
InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
|
||||||
|
if (!InnerMsg)
|
||||||
|
return IFace;
|
||||||
|
|
||||||
|
QualType ClassRec;
|
||||||
|
switch (InnerMsg->getReceiverKind()) {
|
||||||
|
case ObjCMessageExpr::Instance:
|
||||||
|
case ObjCMessageExpr::SuperInstance:
|
||||||
|
return IFace;
|
||||||
|
|
||||||
|
case ObjCMessageExpr::Class:
|
||||||
|
ClassRec = InnerMsg->getClassReceiver();
|
||||||
|
break;
|
||||||
|
case ObjCMessageExpr::SuperClass:
|
||||||
|
ClassRec = InnerMsg->getSuperType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClassRec.isNull())
|
||||||
|
return IFace;
|
||||||
|
|
||||||
|
// ...and it is the result of a class message...
|
||||||
|
|
||||||
|
const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
|
||||||
|
if (!ObjTy)
|
||||||
|
return IFace;
|
||||||
|
const ObjCInterfaceDecl *OID = ObjTy->getInterface();
|
||||||
|
|
||||||
|
// ...and the receiving class is NSMapTable or NSLocale, return that
|
||||||
|
// class as the receiving interface.
|
||||||
|
if (OID->getName() == "NSMapTable" ||
|
||||||
|
OID->getName() == "NSLocale")
|
||||||
|
return OID;
|
||||||
|
|
||||||
|
return IFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
|
||||||
|
const ObjCMessageExpr *Msg,
|
||||||
|
ASTContext &Ctx,
|
||||||
Selector subscriptSel) {
|
Selector subscriptSel) {
|
||||||
|
const Expr *Rec = Msg->getInstanceReceiver();
|
||||||
|
if (!Rec)
|
||||||
|
return false;
|
||||||
|
IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
|
||||||
|
|
||||||
if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
|
if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
|
||||||
if (!MD->isUnavailable())
|
if (!MD->isUnavailable())
|
||||||
return true;
|
return true;
|
||||||
|
@ -138,7 +203,7 @@ static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
|
||||||
const ObjCMessageExpr *Msg,
|
const ObjCMessageExpr *Msg,
|
||||||
const NSAPI &NS,
|
const NSAPI &NS,
|
||||||
Commit &commit) {
|
Commit &commit) {
|
||||||
if (!canRewriteToSubscriptSyntax(IFace,
|
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||||
NS.getObjectAtIndexedSubscriptSelector()))
|
NS.getObjectAtIndexedSubscriptSelector()))
|
||||||
return false;
|
return false;
|
||||||
return rewriteToSubscriptGetCommon(Msg, commit);
|
return rewriteToSubscriptGetCommon(Msg, commit);
|
||||||
|
@ -148,7 +213,7 @@ static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
|
||||||
const ObjCMessageExpr *Msg,
|
const ObjCMessageExpr *Msg,
|
||||||
const NSAPI &NS,
|
const NSAPI &NS,
|
||||||
Commit &commit) {
|
Commit &commit) {
|
||||||
if (!canRewriteToSubscriptSyntax(IFace,
|
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||||
NS.getObjectForKeyedSubscriptSelector()))
|
NS.getObjectForKeyedSubscriptSelector()))
|
||||||
return false;
|
return false;
|
||||||
return rewriteToSubscriptGetCommon(Msg, commit);
|
return rewriteToSubscriptGetCommon(Msg, commit);
|
||||||
|
@ -158,7 +223,7 @@ static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
|
||||||
const ObjCMessageExpr *Msg,
|
const ObjCMessageExpr *Msg,
|
||||||
const NSAPI &NS,
|
const NSAPI &NS,
|
||||||
Commit &commit) {
|
Commit &commit) {
|
||||||
if (!canRewriteToSubscriptSyntax(IFace,
|
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||||
NS.getSetObjectAtIndexedSubscriptSelector()))
|
NS.getSetObjectAtIndexedSubscriptSelector()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -192,7 +257,7 @@ static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
|
||||||
const ObjCMessageExpr *Msg,
|
const ObjCMessageExpr *Msg,
|
||||||
const NSAPI &NS,
|
const NSAPI &NS,
|
||||||
Commit &commit) {
|
Commit &commit) {
|
||||||
if (!canRewriteToSubscriptSyntax(IFace,
|
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||||
NS.getSetObjectForKeyedSubscriptSelector()))
|
NS.getSetObjectForKeyedSubscriptSelector()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -211,3 +211,13 @@ void test2() {
|
||||||
o = [mutcunaval objectAtIndex:4];
|
o = [mutcunaval objectAtIndex:4];
|
||||||
[mutcunaval replaceObjectAtIndex:2 withObject:@"val"];
|
[mutcunaval replaceObjectAtIndex:2 withObject:@"val"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@interface NSLocale : NSObject
|
||||||
|
+ (id)systemLocale;
|
||||||
|
+ (id)currentLocale;
|
||||||
|
- (id)objectForKey:(id)key;
|
||||||
|
@end
|
||||||
|
|
||||||
|
void test3(id key) {
|
||||||
|
id o = [[NSLocale currentLocale] objectForKey:key];
|
||||||
|
}
|
||||||
|
|
|
@ -211,3 +211,13 @@ void test2() {
|
||||||
o = [mutcunaval objectAtIndex:4];
|
o = [mutcunaval objectAtIndex:4];
|
||||||
[mutcunaval replaceObjectAtIndex:2 withObject:@"val"];
|
[mutcunaval replaceObjectAtIndex:2 withObject:@"val"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@interface NSLocale : NSObject
|
||||||
|
+ (id)systemLocale;
|
||||||
|
+ (id)currentLocale;
|
||||||
|
- (id)objectForKey:(id)key;
|
||||||
|
@end
|
||||||
|
|
||||||
|
void test3(id key) {
|
||||||
|
id o = [[NSLocale currentLocale] objectForKey:key];
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue