aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp154
-rw-r--r--clang/test/ARCMT/objcmt-boxing.m68
-rw-r--r--clang/test/ARCMT/objcmt-boxing.m.result68
-rw-r--r--clang/test/ARCMT/objcmt-numeric-literals.m.result4
4 files changed, 279 insertions, 15 deletions
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 218ef22..1d368d6 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -209,6 +209,8 @@ static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
+static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit);
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit) {
@@ -372,7 +374,7 @@ static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
return true;
}
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
}
static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
@@ -386,7 +388,7 @@ static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
return true;
}
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
}
namespace {
@@ -488,10 +490,10 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
literalE = UOE->getSubExpr();
}
- // Only integer and floating literals; non-literals or imaginary literal
- // cannot be rewritten.
+ // Only integer and floating literals, otherwise try to rewrite to boxed
+ // expression.
if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
@@ -511,7 +513,7 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
case NSAPI::NSNumberWithShort:
case NSAPI::NSNumberWithUnsignedShort:
case NSAPI::NSNumberWithBool:
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
case NSAPI::NSNumberWithUnsignedInt:
case NSAPI::NSNumberWithUnsignedInteger:
@@ -551,15 +553,16 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
}
// We will need to modify the literal suffix to get the same type as the call.
- // Don't even try if it came from a macro.
+ // Try with boxed expression if it came from a macro.
if (ArgRange.getBegin().isMacroID())
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
bool LitIsFloat = ArgTy->isFloatingType();
- // For a float passed to integer call, don't try rewriting. It is difficult
- // and a very uncommon case anyway.
+ // For a float passed to integer call, don't try rewriting to objc literal.
+ // It is difficult and a very uncommon case anyway.
+ // But try with boxed expression.
if (LitIsFloat && !CallIsFloating)
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
// Try to modify the literal make it the same type as the method call.
// -Modify the suffix, and/or
@@ -570,11 +573,11 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
isIntZero = !IntE->getValue().getBoolValue();
if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
// Not easy to do int -> float with hex/octal and uncommon anyway.
if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
- return false;
+ return rewriteToNumericBoxedExpression(Msg, NS, commit);
SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
@@ -672,3 +675,128 @@ static void objectifyExpr(const Expr *E, Commit &commit) {
commit.insertWrap("(", Range, ")");
commit.insertBefore(Range.getBegin(), "(id)");
}
+
+//===----------------------------------------------------------------------===//
+// rewriteToNumericBoxedExpression.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
+ const NSAPI &NS, Commit &commit) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+
+ const Expr *Arg = Msg->getArg(0);
+ if (Arg->isTypeDependent())
+ return false;
+
+ ASTContext &Ctx = NS.getASTContext();
+ Selector Sel = Msg->getSelector();
+ llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
+ if (!MKOpt)
+ return false;
+ NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
+
+ const Expr *OrigArg = Arg->IgnoreImpCasts();
+ QualType FinalTy = Arg->getType();
+ QualType OrigTy = OrigArg->getType();
+ uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
+ uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
+
+ bool isTruncated = FinalTySize < OrigTySize;
+ bool needsCast = false;
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ switch (ICE->getCastKind()) {
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ break;
+
+ case CK_IntegralCast: {
+ if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
+ break;
+ // Be more liberal with Integer/UnsignedInteger which are very commonly
+ // used.
+ if ((MK == NSAPI::NSNumberWithInteger ||
+ MK == NSAPI::NSNumberWithUnsignedInteger) &&
+ !isTruncated) {
+ if (OrigTy->getAs<EnumType>())
+ break;
+ if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
+ OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
+ break;
+ }
+
+ needsCast = true;
+ break;
+ }
+
+ case CK_PointerToBoolean:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ case CK_AtomicToNonAtomic:
+ needsCast = true;
+ break;
+
+ case CK_Dependent:
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToPointer:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_MemberPointerToBoolean:
+ case CK_ReinterpretMemberPointer:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingRealToComplex:
+ case CK_FloatingComplexCast:
+ case CK_FloatingComplexToIntegralComplex:
+ case CK_IntegralRealToComplex:
+ case CK_IntegralComplexCast:
+ case CK_IntegralComplexToFloatingComplex:
+ case CK_ARCProduceObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCExtendBlockObject:
+ case CK_NonAtomicToAtomic:
+ case CK_CopyAndAutoreleaseBlockObject:
+ return false;
+ }
+ }
+
+ if (needsCast)
+ return false;
+
+ SourceRange ArgRange = OrigArg->getSourceRange();
+ commit.replaceWithInner(Msg->getSourceRange(), OrigArg->getSourceRange());
+
+ if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
+ commit.insertBefore(ArgRange.getBegin(), "@");
+ else
+ commit.insertWrap("@(", ArgRange, ")");
+
+ return true;
+}
diff --git a/clang/test/ARCMT/objcmt-boxing.m b/clang/test/ARCMT/objcmt-boxing.m
new file mode 100644
index 0000000..faff5a9
--- /dev/null
+++ b/clang/test/ARCMT/objcmt-boxing.m
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -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
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+#define INT_MIN (-__INT_MAX__ -1)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+enum MyEnm {
+ ME_foo
+};
+
+void foo() {
+ [NSNumber numberWithInt:INT_MIN];
+ bool cppb;
+ [NSNumber numberWithBool:cppb];
+ MyEnm myenum;
+ [NSNumber numberWithInteger:myenum];
+ [NSNumber numberWithInteger:ME_foo];
+}
diff --git a/clang/test/ARCMT/objcmt-boxing.m.result b/clang/test/ARCMT/objcmt-boxing.m.result
new file mode 100644
index 0000000..fa8ab11
--- /dev/null
+++ b/clang/test/ARCMT/objcmt-boxing.m.result
@@ -0,0 +1,68 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -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
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+#define INT_MIN (-__INT_MAX__ -1)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+enum MyEnm {
+ ME_foo
+};
+
+void foo() {
+ @INT_MIN;
+ bool cppb;
+ @(cppb);
+ MyEnm myenum;
+ @(myenum);
+ @(ME_foo);
+}
diff --git a/clang/test/ARCMT/objcmt-numeric-literals.m.result b/clang/test/ARCMT/objcmt-numeric-literals.m.result
index 8e34345..bb7b515 100644
--- a/clang/test/ARCMT/objcmt-numeric-literals.m.result
+++ b/clang/test/ARCMT/objcmt-numeric-literals.m.result
@@ -468,7 +468,7 @@ void foo() {
[NSNumber numberWithInteger:NO];
[NSNumber numberWithInteger:true];
[NSNumber numberWithInteger:false];
- [NSNumber numberWithInteger:VAL_INT];
+ @VAL_INT;
[NSNumber numberWithInteger:VAL_UINT];
[NSNumber numberWithUnsignedInteger:'a'];
@@ -498,5 +498,5 @@ void foo() {
[NSNumber numberWithUnsignedInteger:true];
[NSNumber numberWithUnsignedInteger:false];
[NSNumber numberWithUnsignedInteger:VAL_INT];
- [NSNumber numberWithUnsignedInteger:VAL_UINT];
+ @VAL_UINT;
}