From 2df1a5819fd98708ff3b4772f3477f6c1a8da59a Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Thu, 10 May 2012 23:12:03 +0000 Subject: [PATCH] [objc] When boxing a BOOL/NSInteger/NSUInteger type, use the corresponding numberWithBool:/numberWithInteger:/numberWithUnsignedInteger: NSNumber selectors. rdar://11428703 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156583 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/NSAPI.h | 15 ++++- include/clang/AST/Type.h | 6 +- lib/AST/NSAPI.cpp | 49 +++++++++++++++- lib/AST/Type.cpp | 22 ++++++++ test/CodeGenObjC/boxing.m | 86 +++++++++++++++++++++++++++++ test/Rewriter/objc-modern-boxing.mm | 4 ++ 6 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 test/CodeGenObjC/boxing.m diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h index 40e9759067..7e61c960dd 100644 --- a/include/clang/AST/NSAPI.h +++ b/include/clang/AST/NSAPI.h @@ -126,10 +126,19 @@ public: /// \brief Determine the appropriate NSNumber factory method kind for a /// literal of the given type. - static llvm::Optional - getNSNumberFactoryMethodKind(QualType T); + llvm::Optional + getNSNumberFactoryMethodKind(QualType T) 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. + bool isObjCNSIntegerType(QualType T) const; + /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. + bool isObjCNSUIntegerType(QualType T) const; private: + bool isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const; + ASTContext &Ctx; mutable IdentifierInfo *ClassIds[NumClassIds]; @@ -145,6 +154,8 @@ private: /// \brief The Objective-C NSNumber selectors used to create NSNumber literals. mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods]; mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods]; + + mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId; }; } // end namespace clang diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 3c958b21af..9f3fbdb5fc 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1750,9 +1750,9 @@ public: friend class ASTWriter; }; -template <> inline const TypedefType *Type::getAs() const { - return dyn_cast(this); -} +/// \brief This will check for a TypedefType by removing any existing sugar +/// until it reaches a TypedefType or a non-sugared type. +template <> const TypedefType *Type::getAs() const; // We can do canonical leaf types faster, because we don't have to // worry about preserving child type decoration. diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index f5ea2c54ee..c56e6c1688 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -13,7 +13,7 @@ using namespace clang; NSAPI::NSAPI(ASTContext &ctx) - : Ctx(ctx), ClassIds() { + : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0) { } IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { @@ -251,11 +251,22 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const { } llvm::Optional -NSAPI::getNSNumberFactoryMethodKind(QualType T) { +NSAPI::getNSNumberFactoryMethodKind(QualType T) const { const BuiltinType *BT = T->getAs(); if (!BT) return llvm::Optional(); - + + const TypedefType *TDT = T->getAs(); + if (TDT) { + QualType TDTTy = QualType(TDT, 0); + if (isObjCBOOLType(TDTTy)) + return NSAPI::NSNumberWithBool; + if (isObjCNSIntegerType(TDTTy)) + return NSAPI::NSNumberWithInteger; + if (isObjCNSUIntegerType(TDTTy)) + return NSAPI::NSNumberWithUnsignedInteger; + } + switch (BT->getKind()) { case BuiltinType::Char_S: case BuiltinType::SChar: @@ -310,3 +321,35 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) { return llvm::Optional(); } + +/// \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); +} +/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. +bool NSAPI::isObjCNSIntegerType(QualType T) const { + return isObjCTypedef(T, "NSInteger", NSIntegerId); +} +/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. +bool NSAPI::isObjCNSUIntegerType(QualType T) const { + return isObjCTypedef(T, "NSUInteger", NSUIntegerId); +} + +bool NSAPI::isObjCTypedef(QualType T, + StringRef name, IdentifierInfo *&II) const { + if (!Ctx.getLangOpts().ObjC1) + return false; + if (T.isNull()) + return false; + + if (!II) + II = &Ctx.Idents.get(name); + + while (const TypedefType *TDT = T->getAs()) { + if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) + return true; + T = TDT->desugar(); + } + + return false; +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 42673e8e7d..4fef11f2a8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -288,6 +288,28 @@ QualType QualType::IgnoreParens(QualType T) { return T; } +/// \brief This will check for a TypedefType by removing any existing sugar +/// until it reaches a TypedefType or a non-sugared type. +template <> const TypedefType *Type::getAs() const { + const Type *Cur = this; + + while (true) { + if (const TypedefType *TDT = dyn_cast(Cur)) + return TDT; + switch (Cur->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Class: { \ + const Class##Type *Ty = cast(Cur); \ + if (!Ty->isSugared()) return 0; \ + Cur = Ty->desugar().getTypePtr(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } +} + /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. diff --git a/test/CodeGenObjC/boxing.m b/test/CodeGenObjC/boxing.m new file mode 100644 index 0000000000..16b66bbeb4 --- /dev/null +++ b/test/CodeGenObjC/boxing.m @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +typedef long NSInteger; +typedef unsigned long NSUInteger; +typedef signed char BOOL; +#define nil ((void*) 0) + +@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 + +@interface NSString : NSObject +@end + +@interface NSString (NSStringExtensionMethods) ++ (id)stringWithUTF8String:(const char *)nullTerminatedCString; +@end + +// CHECK: [[WithIntMeth:@".*"]] = internal global [15 x i8] c"numberWithInt:\00" +// CHECK: [[WithIntSEL:@".*"]] = internal global i8* getelementptr inbounds ([15 x i8]* [[WithIntMeth]] +// CHECK: [[WithCharMeth:@".*"]] = internal global [16 x i8] c"numberWithChar:\00" +// CHECK: [[WithCharSEL:@".*"]] = internal global i8* getelementptr inbounds ([16 x i8]* [[WithCharMeth]] +// CHECK: [[WithBoolMeth:@".*"]] = internal global [16 x i8] c"numberWithBool:\00" +// CHECK: [[WithBoolSEL:@".*"]] = internal global i8* getelementptr inbounds ([16 x i8]* [[WithBoolMeth]] +// CHECK: [[WithIntegerMeth:@".*"]] = internal global [19 x i8] c"numberWithInteger:\00" +// CHECK: [[WithIntegerSEL:@".*"]] = internal global i8* getelementptr inbounds ([19 x i8]* [[WithIntegerMeth]] +// CHECK: [[WithUnsignedIntegerMeth:@".*"]] = internal global [27 x i8] c"numberWithUnsignedInteger:\00" +// CHECK: [[WithUnsignedIntegerSEL:@".*"]] = internal global i8* getelementptr inbounds ([27 x i8]* [[WithUnsignedIntegerMeth]] +// CHECK: [[stringWithUTF8StringMeth:@".*"]] = internal global [22 x i8] c"stringWithUTF8String:\00" +// CHECK: [[stringWithUTF8StringSEL:@".*"]] = internal global i8* getelementptr inbounds ([22 x i8]* [[stringWithUTF8StringMeth]] + +int main() { + // CHECK: load i8** [[WithIntSEL]] + int i; @(i); + // CHECK: load i8** [[WithCharSEL]] + signed char sc; @(sc); + // CHECK: load i8** [[WithBoolSEL]] + BOOL b; @(b); + // CHECK: load i8** [[WithBoolSEL]] + typeof(b) b2; @(b2); + // CHECK: load i8** [[WithBoolSEL]] + @((BOOL)i); + // CHECK: load i8** [[WithIntegerSEL]] + @((NSInteger)i); + // CHECK: load i8** [[WithUnsignedIntegerSEL]] + @((NSUInteger)i); + // CHECK: load i8** [[stringWithUTF8StringSEL]] + const char *s; @(s); +} diff --git a/test/Rewriter/objc-modern-boxing.mm b/test/Rewriter/objc-modern-boxing.mm index 3374f30476..8f8ed751c5 100644 --- a/test/Rewriter/objc-modern-boxing.mm +++ b/test/Rewriter/objc-modern-boxing.mm @@ -54,6 +54,9 @@ int main(int argc, const char *argv[]) { NSNumber *piFloat = @(3.141592654F); // equivalent to [NSNumber numberWithFloat:(3.141592654F)] NSNumber *piDouble = @(3.1415926535); // equivalent to [NSNumber numberWithDouble:(3.1415926535)] + BOOL b; + NSNumber *nsb = @(b); + // Strings. NSString *duplicateString = @(strdup("Hello")); } @@ -65,4 +68,5 @@ int main(int argc, const char *argv[]) { // CHECK: NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), (42LL)); // CHECK: NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.1415927)); // CHECK: NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535)); +// CHECK: NSNumber *nsb = ((NSNumber *(*)(id, SEL, BOOL))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithBool:"), (BOOL)(b)); // CHECK: NSString *duplicateString = ((NSString *(*)(id, SEL, const char *))(void *)objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), (const char *)(strdup("Hello"))); -- 2.40.0