Modern objective-c translator. rewriting ivars of aggregate type.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151662 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/RewriteModernObjC.cpp
index a2dbf9f..db1f5ff 100644
--- a/lib/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Rewrite/RewriteModernObjC.cpp
@@ -108,6 +108,7 @@
     llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs;
     llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols;
     llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCWrittenInterfaces;
+    llvm::SmallPtrSet<TagDecl*, 8> TagsDefinedInIvarDecls;
     SmallVector<ObjCInterfaceDecl*, 32> ObjCInterfacesSeen;
     SmallVector<Stmt *, 32> Stmts;
     SmallVector<int, 8> ObjCBcLabelNo;
@@ -333,6 +334,8 @@
     void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
                                       std::string &Result);
     
+    void RewriteObjCFieldDecl(FieldDecl *fieldDecl, std::string &Result);
+    
     void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
                                   std::string &Result);
     
@@ -3165,6 +3168,78 @@
   return false;
 }
 
+/// RewriteObjCFieldDecl - This routine rewrites a field into the buffer.
+/// It handles elaborated types, as well as enum types in the process.
+void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl, 
+                                             std::string &Result) {
+  QualType Type = fieldDecl->getType();
+  std::string Name = fieldDecl->getNameAsString();
+
+  if (Type->isRecordType()) {
+    RecordDecl *RD = Type->getAs<RecordType>()->getDecl();
+    if (RD->isCompleteDefinition()) {
+      if (RD->isStruct())
+        Result += "\n\tstruct ";
+      else if (RD->isUnion())
+        Result += "\n\tunion ";
+      else
+        assert(false && "class not allowed as an ivar type");
+  
+      Result += RD->getName();
+      if (TagsDefinedInIvarDecls.count(RD)) {
+        // This struct is already defined. Do not write its definition again.
+        Result += " "; Result += Name; Result += ";\n";
+        return;
+      }
+      TagsDefinedInIvarDecls.insert(RD);
+      Result += " {\n";
+      for (RecordDecl::field_iterator i = RD->field_begin(), 
+          e = RD->field_end(); i != e; ++i) {
+        FieldDecl *FD = *i;
+        RewriteObjCFieldDecl(FD, Result);
+      }
+      Result += "\t} "; 
+      Result += Name; Result += ";\n";
+      return;
+    }
+  }
+  else if (Type->isEnumeralType()) {
+    EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+    if (ED->isCompleteDefinition()) {
+      Result += "\n\tenum ";
+      Result += ED->getName();
+      if (TagsDefinedInIvarDecls.count(ED)) {
+        // This enum is already defined. Do not write its definition again.
+        Result += " "; Result += Name; Result += ";\n";
+        return;
+      }
+      TagsDefinedInIvarDecls.insert(ED);
+      
+      Result += " {\n";
+      for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(),
+           ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) {
+        Result += "\t"; Result += EC->getName(); Result += " = ";
+        llvm::APSInt Val = EC->getInitVal();
+        Result += Val.toString(10);
+        Result += ",\n";
+      }
+      Result += "\t} "; 
+      Result += Name; Result += ";\n";
+      return;
+    }
+  }
+  
+  Result += "\t";
+  convertObjCTypeToCStyleType(Type);
+  
+  Type.getAsStringInternal(Name, Context->getPrintingPolicy());
+  Result += Name;
+  if (fieldDecl->isBitField()) {
+    Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context));
+  }
+  Result += ";\n";
+}
+
 /// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
 /// an objective-c class with ivars.
 void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
@@ -3205,22 +3280,10 @@
     Result += "_IMPL "; Result += RCDecl->getNameAsString();
     Result += "_IVARS;\n";
   }
-  
-  for (unsigned i = 0, e = IVars.size(); i < e; i++) {
-    ObjCIvarDecl *IvarDecl = IVars[i];
-    QualType Type = IvarDecl->getType();
-    std::string Name = IvarDecl->getNameAsString();
+  TagsDefinedInIvarDecls.clear();
+  for (unsigned i = 0, e = IVars.size(); i < e; i++)
+    RewriteObjCFieldDecl(IVars[i], Result);
 
-    Result += "\t";
-    convertObjCTypeToCStyleType(Type);
-    
-    Type.getAsStringInternal(Name, Context->getPrintingPolicy());
-    Result += Name;
-    if (IvarDecl->isBitField()) {
-      Result += " : "; Result += utostr(IvarDecl->getBitWidthValue(*Context));
-    }
-    Result += ";\n";
-  }
   Result += "};\n";
   endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
   ReplaceText(LocStart, endBuf-startBuf, Result);
diff --git a/test/Rewriter/rewrite-modern-ivars-1.mm b/test/Rewriter/rewrite-modern-ivars-1.mm
new file mode 100644
index 0000000..376d300
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-ivars-1.mm
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp
+
+@interface NSCheapMutableString {
+@private
+    struct S s0;
+    union {
+        char *fat;
+        unsigned char *thin;
+    } contents;
+
+    struct {
+        unsigned int isFat:1;
+        unsigned int freeWhenDone:1;
+        unsigned int refs:30;
+    } flags;
+
+    struct S {
+        int iS1;
+        double dS1;
+    } others;
+
+    union U {
+      int iU1;
+      double dU1;
+    } u_others;
+
+   enum {
+    One, Two
+   } E1;
+
+   enum e {
+    Yes = 1,
+    No = 0
+   } BoOl;
+
+   struct S s1;
+
+   enum e E2;
+
+    union {
+        char *fat;
+        unsigned char *thin;
+    } Last_contents;
+
+    struct {
+        unsigned int isFat:1;
+        unsigned int freeWhenDone:1;
+        unsigned int refs:30;
+    } Last_flags;
+}
+@end
+
+@interface III {
+@private
+    struct S s0;
+
+    union {
+        char *fat;
+        unsigned char *thin;
+    } contents;
+
+    struct {
+        unsigned int isFat:1;
+        unsigned int freeWhenDone:1;
+        unsigned int refs:30;
+    } flags;
+
+   enum {
+    One1 = 1000, Two1, Three1
+   } E1;
+
+   struct S s1;
+
+   enum e E2;
+
+    union {
+        char *fat;
+        unsigned char *thin;
+    } Last_contents;
+
+    struct {
+        unsigned int isFat:1;
+        unsigned int freeWhenDone:1;
+        unsigned int refs:30;
+    } Last_flags;
+}
+@end
+