From e35abe1fd3f867ae51d5c68d98578d537eb6beca Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 6 Apr 2012 22:29:36 +0000 Subject: [PATCH] modern objective-c translation: support for dictionary literals. This concludes // rdar://10803676 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154218 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Rewrite/RewriteModernObjC.cpp | 197 +++++++++++++++++- .../rewrite-modern-container-literal.mm | 37 ++++ 2 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 test/Rewriter/rewrite-modern-container-literal.mm diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp index 0c57ae0812..a9fe8cecd1 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/RewriteModernObjC.cpp @@ -320,6 +320,7 @@ namespace { Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp); Stmt *RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp); Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp); + Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp); Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); @@ -464,8 +465,11 @@ namespace { bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); void convertToUnqualifiedObjCType(QualType &T) { - if (T->isObjCQualifiedIdType()) - T = Context->getObjCIdType(); + if (T->isObjCQualifiedIdType()) { + bool isConst = T.isConstQualified(); + T = isConst ? Context->getObjCIdType().withConst() + : Context->getObjCIdType(); + } else if (T->isObjCQualifiedClassType()) T = Context->getObjCClassType(); else if (T->isObjCObjectPointerType() && @@ -2608,11 +2612,11 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { SourceLocation StartLoc = Exp->getLocStart(); SourceLocation EndLoc = Exp->getLocEnd(); - // Build the expression: __NSArray_literal(int, ...).arr + // Build the expression: __NSContainer_literal(int, ...).arr QualType IntQT = Context->IntTy; QualType NSArrayFType = getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); - std::string NSArrayFName("__NSArray_literal"); + std::string NSArrayFName("__NSContainer_literal"); FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName); DeclRefExpr *NSArrayDRE = new (Context) DeclRefExpr(NSArrayFD, false, NSArrayFType, VK_RValue, @@ -2733,6 +2737,181 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { return CE; } +Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp) { + // synthesize declaration of helper functions needed in this routine. + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + // use objc_msgSend() for all. + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + SourceLocation StartLoc = Exp->getLocStart(); + SourceLocation EndLoc = Exp->getLocEnd(); + + // Build the expression: __NSContainer_literal(int, ...).arr + QualType IntQT = Context->IntTy; + QualType NSDictFType = + getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true); + std::string NSDictFName("__NSContainer_literal"); + FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName); + DeclRefExpr *NSDictDRE = + new (Context) DeclRefExpr(NSDictFD, false, NSDictFType, VK_RValue, + SourceLocation()); + + SmallVector KeyExprs; + SmallVector ValueExprs; + + unsigned NumElements = Exp->getNumElements(); + unsigned UnsignedIntSize = + static_cast(Context->getTypeSize(Context->UnsignedIntTy)); + Expr *count = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + KeyExprs.push_back(count); + ValueExprs.push_back(count); + for (unsigned i = 0; i < NumElements; i++) { + ObjCDictionaryElement Element = Exp->getKeyValueElement(i); + KeyExprs.push_back(Element.Key); + ValueExprs.push_back(Element.Value); + } + + // (const id [])objects + Expr *NSValueCallExpr = + new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(), + NSDictFType, VK_LValue, SourceLocation()); + + FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), + &Context->Idents.get("arr"), + Context->getPointerType(Context->VoidPtrTy), 0, + /*BitWidth=*/0, /*Mutable=*/true, + /*HasInit=*/false); + MemberExpr *DictLiteralValueME = + new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, + SourceLocation(), + ARRFD->getType(), VK_LValue, + OK_Ordinary); + QualType ConstIdT = Context->getObjCIdType().withConst(); + CStyleCastExpr * DictValueObjects = + NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(ConstIdT), + CK_BitCast, + DictLiteralValueME); + // (const id [])keys + Expr *NSKeyCallExpr = + new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(), + NSDictFType, VK_LValue, SourceLocation()); + + MemberExpr *DictLiteralKeyME = + new (Context) MemberExpr(NSKeyCallExpr, false, ARRFD, + SourceLocation(), + ARRFD->getType(), VK_LValue, + OK_Ordinary); + + CStyleCastExpr * DictKeyObjects = + NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(ConstIdT), + CK_BitCast, + DictLiteralKeyME); + + + + // Synthesize a call to objc_msgSend(). + SmallVector MsgExprs; + SmallVector ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + QualType expType = Exp->getType(); + + // Create a call to objc_getClass("NSArray"). It will be th 1st argument. + ObjCInterfaceDecl *Class = + expType->getPointeeType()->getAs()->getInterface(); + + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getName(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + + // Create a call to sel_registerName("arrayWithObjects:count:"). + // it will be the 2nd argument. + SmallVector SelExprs; + ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod(); + SelExprs.push_back(StringLiteral::Create(*Context, + DictMethod->getSelector().getAsString(), + StringLiteral::Ascii, false, + argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(SelExp); + + // (const id [])objects + MsgExprs.push_back(DictValueObjects); + + // (const id [])keys + MsgExprs.push_back(DictKeyObjects); + + // (NSUInteger)cnt + Expr *cnt = IntegerLiteral::Create(*Context, + llvm::APInt(UnsignedIntSize, NumElements), + Context->UnsignedIntTy, SourceLocation()); + MsgExprs.push_back(cnt); + + + SmallVector ArgTypes; + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + for (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(), + E = DictMethod->param_end(); PI != E; ++PI) { + QualType T = (*PI)->getType(); + if (const PointerType* PT = T->getAs()) { + QualType PointeeTy = PT->getPointeeType(); + convertToUnqualifiedObjCType(PointeeTy); + T = Context->getPointerType(PointeeTy); + } + ArgTypes.push_back(T); + } + + QualType returnType = Exp->getType(); + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, false, msgSendType, + VK_LValue, SourceLocation()); + + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CK_BitCast, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = + getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), + DictMethod->isVariadic()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs(); + CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], + MsgExprs.size(), + FT->getResultType(), VK_RValue, + EndLoc); + ReplaceStmt(Exp, CE); + return CE; +} + // struct objc_super { struct objc_object *receiver; struct objc_class *super; }; QualType RewriteModernObjC::getSuperStructType() { if (!SuperStructDecl) { @@ -5031,6 +5210,10 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast(S)) return RewriteObjCArrayLiteralExpr(ArrayLitExpr); + + if (ObjCDictionaryLiteral *DictionaryLitExpr = + dyn_cast(S)) + return RewriteObjCDictionaryLiteralExpr(DictionaryLitExpr); if (ObjCMessageExpr *MessExpr = dyn_cast(S)) { #if 0 @@ -5514,9 +5697,9 @@ void RewriteModernObjC::Initialize(ASTContext &context) { // Declarations required for modern objective-c array and dictionary literals. Preamble += "\n#include \n"; - Preamble += "struct __NSArray_literal {\n"; + Preamble += "struct __NSContainer_literal {\n"; Preamble += " void * *arr;\n"; - Preamble += " __NSArray_literal (unsigned int count, ...) {\n"; + Preamble += " __NSContainer_literal (unsigned int count, ...) {\n"; Preamble += "\tva_list marker;\n"; Preamble += "\tva_start(marker, count);\n"; Preamble += "\tarr = new void *[count];\n"; @@ -5524,7 +5707,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "\t arr[i] = va_arg(marker, void *);\n"; Preamble += "\tva_end( marker );\n"; Preamble += " };\n"; - Preamble += " ~__NSArray_literal() {\n"; + Preamble += " __NSContainer_literal() {\n"; Preamble += "\tdelete[] arr;\n"; Preamble += " }\n"; Preamble += "};\n"; diff --git a/test/Rewriter/rewrite-modern-container-literal.mm b/test/Rewriter/rewrite-modern-container-literal.mm new file mode 100644 index 0000000000..7d0f0c02cf --- /dev/null +++ b/test/Rewriter/rewrite-modern-container-literal.mm @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -x objective-c++ -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// rdar://10803676 + +void *sel_registerName(const char *); + +@interface NSNumber ++ (NSNumber *)numberWithChar:(char)value; ++ (NSNumber *)numberWithInt:(int)value; +@end + +@protocol NSCopying @end +typedef unsigned long NSUInteger; + +@interface NSDictionary ++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt; +@end + +@interface NSArray ++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; +@end + +@interface NSString +@end + +id NSUserName(); + +@interface NSDate ++ (id)date; +@end + +int main() { +NSArray *array = @[ @"Hello", NSUserName(), [NSDate date], [NSNumber numberWithInt:42]]; + +NSDictionary *dictionary = @{ @"name" : NSUserName(), @"date" : [NSDate date], @"process" : @"processInfo"}; +} + -- 2.40.0