Index: include/clang/AST/NSAPI.h =================================================================== --- include/clang/AST/NSAPI.h +++ include/clang/AST/NSAPI.h @@ -207,6 +207,35 @@ Optional getNSNumberFactoryMethodKind(QualType T) const; + /// \brief Enumerates the NSValue methods used to generate literals + /// and to apply automatic migration + enum NSValueMethodKind { + NSValueWithBytesObjCType, + + NSValueWithCGPoint, + NSValueWithCGVector, + NSValueWithCGSize, + NSValueWithCGRect, + NSValueWithCGAffineTransform, + + NSValueWithUIEdgeInsets, + NSValueWithUIOffset, + + NSValueWithCATransform3D, + + NSValueWithRange, + NSValueWithPoint, + NSValueWithSize, + NSValueWithRect, + NSValueWithEdgeInsets + }; + + static const unsigned NumNSValueMethods = 14; + + /// \brief The Objective-C NSValue selectors used to create NSValue literals + /// and to apply automatic migration + Selector getNSValueSelector(NSValueMethodKind MK) const; + /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. bool isObjCBOOLType(QualType T) const; /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. @@ -249,6 +278,10 @@ mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods]; mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods]; + /// \brief The Objective-C NSValue selectors used to create NSValue literals + /// and to apply automatic migration + mutable Selector NSValueSelectors[NumNSValueMethods]; + mutable Selector objectForKeyedSubscriptSel, objectAtIndexedSubscriptSel, setObjectForKeyedSubscriptSel,setObjectAtIndexedSubscriptSel, isEqualSel; Index: lib/AST/NSAPI.cpp =================================================================== --- lib/AST/NSAPI.cpp +++ lib/AST/NSAPI.cpp @@ -469,6 +469,72 @@ return None; } +Selector NSAPI::getNSValueSelector(NSValueMethodKind MK) const { + if (NSValueSelectors[MK].isNull()) { + Selector Sel; + switch (MK) { + case NSValueWithBytesObjCType: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("valueWithBytes"), + &Ctx.Idents.get("objCType") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + } break; + case NSValueWithCGPoint: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCGPoint")); + break; + case NSValueWithCGVector: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCGVector")); + break; + case NSValueWithCGSize: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCGSize")); + break; + case NSValueWithCGRect: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCGRect")); + break; + case NSValueWithCGAffineTransform: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCGAffineTransform")); + break; + case NSValueWithUIEdgeInsets: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithUIEdgeInsets")); + break; + case NSValueWithUIOffset: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithUIOffset")); + break; + case NSValueWithCATransform3D: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithCATransform3D")); + break; + case NSValueWithRange: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("valueWithRange")); + break; + case NSValueWithPoint: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("valueWithPoint")); + break; + case NSValueWithSize: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("valueWithSize")); + break; + case NSValueWithRect: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("valueWithRect")); + break; + case NSValueWithEdgeInsets: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("valueWithEdgeInsets")); + break; + } + NSValueSelectors[MK] = Sel; + } + + return NSValueSelectors[MK]; +} + /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. bool NSAPI::isObjCBOOLType(QualType T) const { return isObjCTypedef(T, "BOOL", BOOLId); Index: lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- lib/Edit/RewriteObjCFoundationAPI.cpp +++ lib/Edit/RewriteObjCFoundationAPI.cpp @@ -335,6 +335,8 @@ const NSAPI &NS, Commit &commit); static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit); +static bool rewriteToObjCBoxableExpression(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, const NSAPI &NS, Commit &commit, @@ -351,6 +353,8 @@ return rewriteToNumberLiteral(Msg, NS, commit); if (II == NS.getNSClassId(NSAPI::ClassId_NSString)) return rewriteToStringBoxedExpression(Msg, NS, commit); + if (II == NS.getNSClassId(NSAPI::ClassId_NSValue)) + return rewriteToObjCBoxableExpression(Msg, NS, commit); return false; } @@ -1171,3 +1175,60 @@ return false; } + +static bool rewriteToObjCBoxableExpression(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit) { + int NumArgs = Msg->getNumArgs(); + if (NumArgs != 2 && NumArgs != 1) { + return false; + } + + Selector Sel = Msg->getSelector(); + + if (Sel == NS.getNSValueSelector(NSAPI::NSValueWithBytesObjCType) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCATransform3D) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCGAffineTransform) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCGPoint) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCGRect) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCGSize) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithCGVector) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithEdgeInsets) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithPoint) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithRange) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithRect) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithSize) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithUIEdgeInsets) || + Sel == NS.getNSValueSelector(NSAPI::NSValueWithUIOffset)) { + + const Expr *Arg = Msg->getArg(0)->IgnoreCasts(); + + // handles 'valueWithBytes' specific case + // [NSValue valueWithBytes:&unaryOperation objCType:@encode(SomeType)] + // ^ + if (const UnaryOperator *UO = dyn_cast(Arg)) { + Arg = UO->getSubExpr(); + } + + QualType ArgType = Arg->getType(); + + // handles 'valueWithBytes' specific case + // [NSValue valueWithBytes:&unaryOperation objCType:@encode(SomeType)] + // ^-------------^ + if (ArgType->isPointerType()) { + ArgType = ArgType->getPointeeType(); + } + + if (!ArgType->isObjCBoxableRecordType()) { + return false; + } + + SourceRange MsgRange(Msg->getLocStart(), Msg->getLocEnd()); + SourceRange ArgRange(Arg->getLocStart(), Arg->getLocEnd()); + commit.replaceWithInner(MsgRange, ArgRange); + commit.insertWrap("@(", ArgRange, ")"); + + return true; + } + + return false; +} Index: test/ARCMT/objcmt-objc-boxable.m =================================================================== --- /dev/null +++ test/ARCMT/objcmt-objc-boxable.m @@ -0,0 +1,176 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -mt-migrate-directory %t %s -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result + +typedef unsigned long NSUInteger; +typedef double CGFloat; + +typedef struct _NSRange { + NSUInteger location; + NSUInteger length; +} NSRange; + +typedef struct CATransform3D +{ + CGFloat m11, m12, m13, m14; + CGFloat m21, m22, m23, m24; + CGFloat m31, m32, m33, m34; + CGFloat m41, m42, m43, m44; +} CATransform3D; + +typedef struct CGPoint { + CGFloat x; + CGFloat y; +} CGPoint; + +typedef struct CGSize { + CGFloat width; + CGFloat height; +} CGSize; + +typedef struct CGVector { + CGFloat dx; + CGFloat dy; +} CGVector; + +typedef struct CGRect { + CGPoint origin; + CGSize size; +} CGRect; + +typedef struct UIEdgeInsets { + CGFloat top, left, bottom, right; +} UIEdgeInsets; + +typedef struct UIOffset { + CGFloat horizontal, vertical; +} UIOffset; + +typedef struct CGAffineTransform { + CGFloat a, b, c, d; + CGFloat tx, ty; +} CGAffineTransform; + +typedef CGPoint NSPoint; +typedef CGSize NSSize; +typedef CGRect NSRect; + +typedef struct NSEdgeInsets { + CGFloat top; + CGFloat left; + CGFloat bottom; + CGFloat right; +} NSEdgeInsets; + +typedef struct CustomStruct { + int dummy; +} CustomStruct; + +typedef struct AnotherCustomStruct { + int dummy; +} AnotherCustomStruct; + +extern CGRect returnRect(); + +@interface NSObject @end + +@interface NSValue : NSObject + ++ (NSValue *)valueWithCGPoint:(CGPoint)point; ++ (NSValue *)valueWithCGVector:(CGVector)vector; ++ (NSValue *)valueWithCGSize:(CGSize)size; ++ (NSValue *)valueWithCGRect:(CGRect)rect; ++ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform; ++ (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets; ++ (NSValue *)valueWithUIOffset:(UIOffset)insets; + ++ (NSValue *)valueWithRange:(NSRange)range; ++ (NSValue *)valueWithCATransform3D:(CATransform3D)t; + ++ (NSValue *)valueWithPoint:(NSPoint)point; ++ (NSValue *)valueWithSize:(NSSize)size; ++ (NSValue *)valueWithRect:(NSRect)rect; ++ (NSValue *)valueWithEdgeInsets:(NSEdgeInsets)insets; + ++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; + +@end + +static CGPoint cg_point; +static CGVector cg_vector; +static CGSize cg_size; +static CGRect cg_rect; +static CGAffineTransform ca_affineTransform; +static UIEdgeInsets ui_edgeInsets; +static UIOffset ui_offset; +static NSRange ns_range; +static CATransform3D ca_transform3D; +static NSPoint ns_point; +static NSSize ns_size; +static NSRect ns_rect; +static NSEdgeInsets ns_edgeInsets; +static CustomStruct customStruct; +static AnotherCustomStruct anotherCustomStruct; + +void noBoxableStructsAvailableYet() { + [NSValue valueWithCGPoint:cg_point]; + [NSValue valueWithCGVector:cg_vector]; + [NSValue valueWithCGSize:cg_size]; + [NSValue valueWithCGRect:cg_rect]; + [NSValue valueWithCGAffineTransform:ca_affineTransform]; + [NSValue valueWithUIEdgeInsets:ui_edgeInsets]; + [NSValue valueWithUIOffset:ui_offset]; + + [NSValue valueWithRange:ns_range]; + [NSValue valueWithCATransform3D:ca_transform3D]; + + [NSValue valueWithPoint:ns_point]; + [NSValue valueWithSize:ns_size]; + [NSValue valueWithRect:ns_rect]; + [NSValue valueWithEdgeInsets:ns_edgeInsets]; + + [NSValue valueWithBytes:&customStruct objCType:@encode(CustomStruct)]; + [NSValue valueWithBytes:&anotherCustomStruct objCType:@encode(AnotherCustomStruct)]; + [NSValue valueWithRect:returnRect()]; +} + +#define BOXABLE __attribute__((objc_boxable)) + +typedef struct BOXABLE _NSRange NSRange; +typedef struct BOXABLE CATransform3D CATransform3D; +typedef struct BOXABLE CGPoint CGPoint; +typedef struct BOXABLE CGSize CGSize; +typedef struct BOXABLE CGVector CGVector; +typedef struct BOXABLE CGRect CGRect; +typedef struct BOXABLE UIEdgeInsets UIEdgeInsets; +typedef struct BOXABLE UIOffset UIOffset; +typedef struct BOXABLE CGAffineTransform CGAffineTransform; +typedef struct BOXABLE CGPoint NSPoint; +typedef struct BOXABLE CGSize NSSize; +typedef struct BOXABLE CGRect NSRect; +typedef struct BOXABLE NSEdgeInsets NSEdgeInsets; +typedef struct BOXABLE CustomStruct CustomStruct; + +void boxableStructsAvailable() { + [NSValue valueWithCGPoint:cg_point]; + [NSValue valueWithCGVector:cg_vector]; + [NSValue valueWithCGSize:cg_size]; + [NSValue valueWithCGRect:cg_rect]; + [NSValue valueWithCGAffineTransform:ca_affineTransform]; + [NSValue valueWithUIEdgeInsets:ui_edgeInsets]; + [NSValue valueWithUIOffset:ui_offset]; + + [NSValue valueWithRange:ns_range]; + [NSValue valueWithCATransform3D:ca_transform3D]; + + [NSValue valueWithPoint:ns_point]; + [NSValue valueWithSize:ns_size]; + [NSValue valueWithRect:ns_rect]; + [NSValue valueWithEdgeInsets:ns_edgeInsets]; + + [NSValue valueWithBytes:&customStruct objCType:@encode(CustomStruct)]; + [NSValue valueWithBytes:&anotherCustomStruct objCType:@encode(AnotherCustomStruct)]; + [NSValue valueWithRect:returnRect()]; +} + Index: test/ARCMT/objcmt-objc-boxable.m.result =================================================================== --- /dev/null +++ test/ARCMT/objcmt-objc-boxable.m.result @@ -0,0 +1,176 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -mt-migrate-directory %t %s -x objective-c +// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result + +typedef unsigned long NSUInteger; +typedef double CGFloat; + +typedef struct _NSRange { + NSUInteger location; + NSUInteger length; +} NSRange; + +typedef struct CATransform3D +{ + CGFloat m11, m12, m13, m14; + CGFloat m21, m22, m23, m24; + CGFloat m31, m32, m33, m34; + CGFloat m41, m42, m43, m44; +} CATransform3D; + +typedef struct CGPoint { + CGFloat x; + CGFloat y; +} CGPoint; + +typedef struct CGSize { + CGFloat width; + CGFloat height; +} CGSize; + +typedef struct CGVector { + CGFloat dx; + CGFloat dy; +} CGVector; + +typedef struct CGRect { + CGPoint origin; + CGSize size; +} CGRect; + +typedef struct UIEdgeInsets { + CGFloat top, left, bottom, right; +} UIEdgeInsets; + +typedef struct UIOffset { + CGFloat horizontal, vertical; +} UIOffset; + +typedef struct CGAffineTransform { + CGFloat a, b, c, d; + CGFloat tx, ty; +} CGAffineTransform; + +typedef CGPoint NSPoint; +typedef CGSize NSSize; +typedef CGRect NSRect; + +typedef struct NSEdgeInsets { + CGFloat top; + CGFloat left; + CGFloat bottom; + CGFloat right; +} NSEdgeInsets; + +typedef struct CustomStruct { + int dummy; +} CustomStruct; + +typedef struct AnotherCustomStruct { + int dummy; +} AnotherCustomStruct; + +extern CGRect returnRect(); + +@interface NSObject @end + +@interface NSValue : NSObject + ++ (NSValue *)valueWithCGPoint:(CGPoint)point; ++ (NSValue *)valueWithCGVector:(CGVector)vector; ++ (NSValue *)valueWithCGSize:(CGSize)size; ++ (NSValue *)valueWithCGRect:(CGRect)rect; ++ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform; ++ (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets; ++ (NSValue *)valueWithUIOffset:(UIOffset)insets; + ++ (NSValue *)valueWithRange:(NSRange)range; ++ (NSValue *)valueWithCATransform3D:(CATransform3D)t; + ++ (NSValue *)valueWithPoint:(NSPoint)point; ++ (NSValue *)valueWithSize:(NSSize)size; ++ (NSValue *)valueWithRect:(NSRect)rect; ++ (NSValue *)valueWithEdgeInsets:(NSEdgeInsets)insets; + ++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; + +@end + +static CGPoint cg_point; +static CGVector cg_vector; +static CGSize cg_size; +static CGRect cg_rect; +static CGAffineTransform ca_affineTransform; +static UIEdgeInsets ui_edgeInsets; +static UIOffset ui_offset; +static NSRange ns_range; +static CATransform3D ca_transform3D; +static NSPoint ns_point; +static NSSize ns_size; +static NSRect ns_rect; +static NSEdgeInsets ns_edgeInsets; +static CustomStruct customStruct; +static AnotherCustomStruct anotherCustomStruct; + +void noBoxableStructsAvailableYet() { + [NSValue valueWithCGPoint:cg_point]; + [NSValue valueWithCGVector:cg_vector]; + [NSValue valueWithCGSize:cg_size]; + [NSValue valueWithCGRect:cg_rect]; + [NSValue valueWithCGAffineTransform:ca_affineTransform]; + [NSValue valueWithUIEdgeInsets:ui_edgeInsets]; + [NSValue valueWithUIOffset:ui_offset]; + + [NSValue valueWithRange:ns_range]; + [NSValue valueWithCATransform3D:ca_transform3D]; + + [NSValue valueWithPoint:ns_point]; + [NSValue valueWithSize:ns_size]; + [NSValue valueWithRect:ns_rect]; + [NSValue valueWithEdgeInsets:ns_edgeInsets]; + + [NSValue valueWithBytes:&customStruct objCType:@encode(CustomStruct)]; + [NSValue valueWithBytes:&anotherCustomStruct objCType:@encode(AnotherCustomStruct)]; + [NSValue valueWithRect:returnRect()]; +} + +#define BOXABLE __attribute__((objc_boxable)) + +typedef struct BOXABLE _NSRange NSRange; +typedef struct BOXABLE CATransform3D CATransform3D; +typedef struct BOXABLE CGPoint CGPoint; +typedef struct BOXABLE CGSize CGSize; +typedef struct BOXABLE CGVector CGVector; +typedef struct BOXABLE CGRect CGRect; +typedef struct BOXABLE UIEdgeInsets UIEdgeInsets; +typedef struct BOXABLE UIOffset UIOffset; +typedef struct BOXABLE CGAffineTransform CGAffineTransform; +typedef struct BOXABLE CGPoint NSPoint; +typedef struct BOXABLE CGSize NSSize; +typedef struct BOXABLE CGRect NSRect; +typedef struct BOXABLE NSEdgeInsets NSEdgeInsets; +typedef struct BOXABLE CustomStruct CustomStruct; + +void boxableStructsAvailable() { + @(cg_point); + @(cg_vector); + @(cg_size); + @(cg_rect); + @(ca_affineTransform); + @(ui_edgeInsets); + @(ui_offset); + + @(ns_range); + @(ca_transform3D); + + @(ns_point); + @(ns_size); + @(ns_rect); + @(ns_edgeInsets); + + @(customStruct); + [NSValue valueWithBytes:&anotherCustomStruct objCType:@encode(AnotherCustomStruct)]; + @(returnRect()); +} +