[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
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 40e9759..7e61c96 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -126,10 +126,19 @@
 
   /// \brief Determine the appropriate NSNumber factory method kind for a
   /// literal of the given type.
-  static llvm::Optional<NSNumberLiteralMethodKind>
-      getNSNumberFactoryMethodKind(QualType T);
+  llvm::Optional<NSNumberLiteralMethodKind>
+      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 @@
   /// \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 3c958b2..9f3fbdb 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1750,9 +1750,9 @@
   friend class ASTWriter;
 };
 
-template <> inline const TypedefType *Type::getAs() const {
-  return dyn_cast<TypedefType>(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 f5ea2c5..c56e6c1 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 @@
 }
 
 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
-NSAPI::getNSNumberFactoryMethodKind(QualType T) {
+NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
   const BuiltinType *BT = T->getAs<BuiltinType>();
   if (!BT)
     return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
-  
+
+  const TypedefType *TDT = T->getAs<TypedefType>();
+  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 @@
   
   return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
 }
+
+/// \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<TypedefType>()) {
+    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 42673e8..4fef11f 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -288,6 +288,28 @@
   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<TypedefType>(Cur))
+      return TDT;
+    switch (Cur->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+    case Class: { \
+      const Class##Type *Ty = cast<Class##Type>(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 0000000..16b66bb
--- /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 3374f30..8f8ed75 100644
--- a/test/Rewriter/objc-modern-boxing.mm
+++ b/test/Rewriter/objc-modern-boxing.mm
@@ -54,6 +54,9 @@
   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 @@
 // 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")));