[cfe-commits] r172679 - in /cfe/trunk: include/clang/AST/NSAPI.h include/clang/Edit/Rewriters.h lib/ARCMigrate/ObjCMT.cpp lib/AST/NSAPI.cpp lib/Edit/RewriteObjCFoundationAPI.cpp test/ARCMT/objcmt-subscripting-literals-in-arc.m test/ARCMT/objcmt-subscripting-literals-in-arc.m.result test/ARCMT/objcmt-subscripting-literals.m test/ARCMT/objcmt-subscripting-literals.m.result
Argyrios Kyrtzidis
akyrtzi at gmail.com
Wed Jan 16 15:54:48 PST 2013
Author: akirtzidis
Date: Wed Jan 16 17:54:48 2013
New Revision: 172679
URL: http://llvm.org/viewvc/llvm-project?rev=172679&view=rev
Log:
[objcmt] Rewrite a NSDictionary dictionaryWithObjects:forKeys: to a dictionary literal
if we can see the elements of the arrays.
for example:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", @"2", nil] forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
-->
NSDictionary *dict = @{ @"A" : @"1", @"B" : @"2" };
rdar://12428166
Modified:
cfe/trunk/include/clang/AST/NSAPI.h
cfe/trunk/include/clang/Edit/Rewriters.h
cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
cfe/trunk/lib/AST/NSAPI.cpp
cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp
cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m
cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m
cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m.result
Modified: cfe/trunk/include/clang/AST/NSAPI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/NSAPI.h (original)
+++ cfe/trunk/include/clang/AST/NSAPI.h Wed Jan 16 17:54:48 2013
@@ -96,10 +96,11 @@
NSDict_dictionaryWithObjectsAndKeys,
NSDict_initWithDictionary,
NSDict_initWithObjectsAndKeys,
+ NSDict_initWithObjectsForKeys,
NSDict_objectForKey,
NSMutableDict_setObjectForKey
};
- static const unsigned NumNSDictionaryMethods = 10;
+ static const unsigned NumNSDictionaryMethods = 11;
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
Modified: cfe/trunk/include/clang/Edit/Rewriters.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Edit/Rewriters.h?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/include/clang/Edit/Rewriters.h (original)
+++ cfe/trunk/include/clang/Edit/Rewriters.h Wed Jan 16 17:54:48 2013
@@ -13,6 +13,7 @@
namespace clang {
class ObjCMessageExpr;
class NSAPI;
+ class ParentMap;
namespace edit {
class Commit;
@@ -21,7 +22,8 @@
const NSAPI &NS, Commit &commit);
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap);
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
Modified: cfe/trunk/lib/ARCMigrate/ObjCMT.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/ObjCMT.cpp?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/lib/ARCMigrate/ObjCMT.cpp (original)
+++ cfe/trunk/lib/ARCMigrate/ObjCMT.cpp Wed Jan 16 17:54:48 2013
@@ -11,6 +11,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/NSAPI.h"
+#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Edit/Commit.h"
@@ -120,9 +121,11 @@
namespace {
class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
ObjCMigrateASTConsumer &Consumer;
+ ParentMap &PMap;
public:
- ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+ ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
+ : Consumer(consumer), PMap(PMap) { }
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldWalkTypesOfTypeLocs() const { return false; }
@@ -130,7 +133,7 @@
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
if (Consumer.MigrateLiterals) {
edit::Commit commit(*Consumer.Editor);
- edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit);
+ edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Consumer.Editor->commit(commit);
}
@@ -153,6 +156,23 @@
return WalkUpFromObjCMessageExpr(E);
}
};
+
+class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
+ ObjCMigrateASTConsumer &Consumer;
+ OwningPtr<ParentMap> PMap;
+
+public:
+ BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+
+ bool shouldVisitTemplateInstantiations() const { return false; }
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseStmt(Stmt *S) {
+ PMap.reset(new ParentMap(S));
+ ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
+ return true;
+ }
+};
}
void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
@@ -161,7 +181,7 @@
if (isa<ObjCMethodDecl>(D))
return; // Wait for the ObjC container declaration.
- ObjCMigrator(*this).TraverseDecl(D);
+ BodyMigrator(*this).TraverseDecl(D);
}
namespace {
Modified: cfe/trunk/lib/AST/NSAPI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/lib/AST/NSAPI.cpp (original)
+++ cfe/trunk/lib/AST/NSAPI.cpp Wed Jan 16 17:54:48 2013
@@ -186,6 +186,14 @@
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
+ case NSDict_initWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("initWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
Modified: cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp (original)
+++ cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp Wed Jan 16 17:54:48 2013
@@ -16,6 +16,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/NSAPI.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Edit/Commit.h"
#include "clang/Lex/Lexer.h"
@@ -325,7 +326,8 @@
//===----------------------------------------------------------------------===//
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap);
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
@@ -336,13 +338,14 @@
const NSAPI &NS, Commit &commit);
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
IdentifierInfo *II = 0;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
- return rewriteToArrayLiteral(Msg, NS, commit);
+ return rewriteToArrayLiteral(Msg, NS, commit, PMap);
if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
return rewriteToDictionaryLiteral(Msg, NS, commit);
if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
@@ -353,6 +356,19 @@
return false;
}
+/// \brief Returns true if the immediate message arguments of \c Msg should not
+/// be rewritten because it will interfere with the rewrite of the parent
+/// message expression. e.g.
+/// \code
+/// [NSDictionary dictionaryWithObjects:
+/// [NSArray arrayWithObjects:@"1", @"2", nil]
+/// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
+/// \endcode
+/// It will return true for this because we are going to rewrite this directly
+/// to a dictionary literal without any array literals.
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS);
+
//===----------------------------------------------------------------------===//
// rewriteToArrayLiteral.
//===----------------------------------------------------------------------===//
@@ -361,7 +377,15 @@
static void objectifyExpr(const Expr *E, Commit &commit);
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
+ if (PMap) {
+ const ObjCMessageExpr *ParentMsg =
+ dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
+ if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
+ return false;
+ }
+
Selector Sel = Msg->getSelector();
SourceRange MsgRange = Msg->getSourceRange();
@@ -411,6 +435,59 @@
// rewriteToDictionaryLiteral.
//===----------------------------------------------------------------------===//
+/// \brief If \c Msg is an NSArray creation message or literal, this gets the
+/// objects that were used to create it.
+/// \returns true if it is an NSArray and we got objects, or false otherwise.
+static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
+ SmallVectorImpl<const Expr *> &Objs) {
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+ if (!E)
+ return false;
+
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
+ IdentifierInfo *Cls = 0;
+ if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
+ return true; // empty array.
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+ Objs.push_back(Msg->getArg(0));
+ return true;
+ }
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
+ Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
+ if (Msg->getNumArgs() == 0)
+ return false;
+ const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
+ if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+ return false;
+
+ for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
+ Objs.push_back(Msg->getArg(i));
+ return true;
+ }
+
+ } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
+ for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
+ Objs.push_back(ArrLit->getElement(i));
+ return true;
+ }
+
+ return false;
+}
+
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit) {
Selector Sel = Msg->getSelector();
@@ -481,6 +558,83 @@
return true;
}
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ if (Vals.empty()) {
+ commit.replace(MsgRange, "@{}");
+ return true;
+ }
+
+ for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
+ objectifyExpr(Vals[i], commit);
+ objectifyExpr(Keys[i], commit);
+
+ SourceRange ValRange = Vals[i]->getSourceRange();
+ SourceRange KeyRange = Keys[i]->getSourceRange();
+ // Insert value after key.
+ commit.insertAfterToken(KeyRange.getEnd(), ": ");
+ commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
+ }
+ // Range of arguments up until and including the last key.
+ // The first value is cut off, the value will move after the key.
+ SourceRange ArgRange(Keys.front()->getLocStart(),
+ Keys.back()->getLocEnd());
+ commit.insertWrap("@{", ArgRange, "}");
+ commit.replaceWithInner(MsgRange, ArgRange);
+ return true;
+ }
+
+ return false;
+}
+
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS) {
+ if (!Msg)
+ return false;
+
+ IdentifierInfo *II = 0;
+ if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ return true;
+ }
+
return false;
}
Modified: cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m (original)
+++ cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m Wed Jan 16 17:54:48 2013
@@ -101,6 +101,8 @@
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
dict = [[NSDictionary alloc] initWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+ dict = [[NSDictionary alloc] initWithObjects:[[NSArray alloc] initWithObjects:@"1", @"2", nil] forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
+
NSNumber *n = [[NSNumber alloc] initWithInt:2];
}
@end
Modified: cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result (original)
+++ cfe/trunk/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result Wed Jan 16 17:54:48 2013
@@ -101,6 +101,8 @@
dict = @{@"key1": @"value1", @"key2": @"value2"};
dict = @{@"key1": @"value1", @"key2": @"value2"};
+ dict = @{@"A": @"1", @"B": @"2"};
+
NSNumber *n = @2;
}
@end
Modified: cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m (original)
+++ cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m Wed Jan 16 17:54:48 2013
@@ -153,6 +153,10 @@
void *hd;
o = [(NSArray*)hd objectAtIndex:2];
o = [ivarArr objectAtIndex:2];
+
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", [NSArray array], nil] forKeys:[NSArray arrayWithObjects:@"A", [arr objectAtIndex:2], nil]];
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", @"2", nil] forKeys:arr];
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", @"2", nil] forKeys:@[@"A", @"B"]];
}
@end
Modified: cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m.result?rev=172679&r1=172678&r2=172679&view=diff
==============================================================================
--- cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m.result (original)
+++ cfe/trunk/test/ARCMT/objcmt-subscripting-literals.m.result Wed Jan 16 17:54:48 2013
@@ -153,6 +153,10 @@
void *hd;
o = ((NSArray*)hd)[2];
o = ivarArr[2];
+
+ dict = @{@"A": @"1", arr[2]: @[]};
+ dict = [NSDictionary dictionaryWithObjects:@[@"1", @"2"] forKeys:arr];
+ dict = @{@"A": @"1", @"B": @"2"};
}
@end
More information about the cfe-commits
mailing list