forked from OSchip/llvm-project
[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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
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) {
|
||||
const Expr *Rec = Msg->getInstanceReceiver();
|
||||
if (!Rec)
|
||||
return false;
|
||||
IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
|
||||
|
||||
if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
|
||||
if (!MD->isUnavailable())
|
||||
return true;
|
||||
|
@ -138,7 +203,7 @@ static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
|
|||
const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS,
|
||||
Commit &commit) {
|
||||
if (!canRewriteToSubscriptSyntax(IFace,
|
||||
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||
NS.getObjectAtIndexedSubscriptSelector()))
|
||||
return false;
|
||||
return rewriteToSubscriptGetCommon(Msg, commit);
|
||||
|
@ -148,7 +213,7 @@ static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
|
|||
const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS,
|
||||
Commit &commit) {
|
||||
if (!canRewriteToSubscriptSyntax(IFace,
|
||||
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||
NS.getObjectForKeyedSubscriptSelector()))
|
||||
return false;
|
||||
return rewriteToSubscriptGetCommon(Msg, commit);
|
||||
|
@ -158,7 +223,7 @@ static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
|
|||
const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS,
|
||||
Commit &commit) {
|
||||
if (!canRewriteToSubscriptSyntax(IFace,
|
||||
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||
NS.getSetObjectAtIndexedSubscriptSelector()))
|
||||
return false;
|
||||
|
||||
|
@ -192,7 +257,7 @@ static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
|
|||
const ObjCMessageExpr *Msg,
|
||||
const NSAPI &NS,
|
||||
Commit &commit) {
|
||||
if (!canRewriteToSubscriptSyntax(IFace,
|
||||
if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
|
||||
NS.getSetObjectForKeyedSubscriptSelector()))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -211,3 +211,13 @@ void test2() {
|
|||
o = [mutcunaval objectAtIndex:4];
|
||||
[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];
|
||||
[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