Implement AST importing of Objective-C instance variables. 
Check superclasses when merging two Objective-C @interfaces.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96420 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index b6c2b13..a435e35 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -53,6 +53,13 @@
   "class has %0 base %plural{1:class|:classes}0">;
 def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
 def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
-  
+def err_odr_ivar_type_inconsistent : Error<
+  "instance variable %0 declared with incompatible types in different "
+  "translation units (%1 vs. %2)">;
+def err_odr_objc_superclass_inconsistent : Error<
+  "class %0 has incompatible superclasses">;
+def note_odr_objc_superclass : Note<"inherits from superclass %0 here">;
+def note_odr_objc_missing_superclass : Note<"no corresponding superclass here">;
+
 def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
 }
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index dee0d2b..ff04782 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -90,6 +90,7 @@
     Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
     Decl *VisitFunctionDecl(FunctionDecl *D);
     Decl *VisitFieldDecl(FieldDecl *D);
+    Decl *VisitObjCIvarDecl(ObjCIvarDecl *D);
     Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
@@ -1821,6 +1822,54 @@
   return ToField;
 }
 
+Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
+  // Import the major distinguishing characteristics of an ivar.
+  DeclContext *DC, *LexicalDC;
+  DeclarationName Name;
+  SourceLocation Loc;
+  if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+    return 0;
+  
+  // Determine whether we've already imported this ivar 
+  for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+       Lookup.first != Lookup.second; 
+       ++Lookup.first) {
+    if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(*Lookup.first)) {
+      if (Importer.IsStructurallyEquivalent(D->getType(), 
+                                            FoundIvar->getType())) {
+        Importer.Imported(D, FoundIvar);
+        return FoundIvar;
+      }
+
+      Importer.ToDiag(Loc, diag::err_odr_ivar_type_inconsistent)
+        << Name << D->getType() << FoundIvar->getType();
+      Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here)
+        << FoundIvar->getType();
+      return 0;
+    }
+  }
+
+  // Import the type.
+  QualType T = Importer.Import(D->getType());
+  if (T.isNull())
+    return 0;
+  
+  TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+  Expr *BitWidth = Importer.Import(D->getBitWidth());
+  if (!BitWidth && D->getBitWidth())
+    return 0;
+  
+  ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(), DC, 
+                                              Loc, Name.getAsIdentifierInfo(),
+                                              T, TInfo, D->getAccessControl(),
+                                              BitWidth);
+  ToIvar->setLexicalDeclContext(LexicalDC);
+  Importer.Imported(D, ToIvar);
+  LexicalDC->addDecl(ToIvar);
+  return ToIvar;
+  
+}
+
 Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
   // Import the major distinguishing characteristics of a variable.
   DeclContext *DC, *LexicalDC;
@@ -1997,9 +2046,6 @@
     }
     Importer.Imported(D, ToIface);
 
-    // Import superclass
-    // FIXME: If we're merging, make sure that both decls have the same 
-    // superclass.
     if (D->getSuperClass()) {
       ObjCInterfaceDecl *Super
         = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
@@ -2037,6 +2083,33 @@
     ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
   } else {
     Importer.Imported(D, ToIface);
+
+    // Check for consistency of superclasses.
+    DeclarationName FromSuperName, ToSuperName;
+    if (D->getSuperClass())
+      FromSuperName = Importer.Import(D->getSuperClass()->getDeclName());
+    if (ToIface->getSuperClass())
+      ToSuperName = ToIface->getSuperClass()->getDeclName();
+    if (FromSuperName != ToSuperName) {
+      Importer.ToDiag(ToIface->getLocation(), 
+                      diag::err_odr_objc_superclass_inconsistent)
+        << ToIface->getDeclName();
+      if (ToIface->getSuperClass())
+        Importer.ToDiag(ToIface->getSuperClassLoc(), 
+                        diag::note_odr_objc_superclass)
+          << ToIface->getSuperClass()->getDeclName();
+      else
+        Importer.ToDiag(ToIface->getLocation(), 
+                        diag::note_odr_objc_missing_superclass);
+      if (D->getSuperClass())
+        Importer.FromDiag(D->getSuperClassLoc(), 
+                          diag::note_odr_objc_superclass)
+          << D->getSuperClass()->getDeclName();
+      else
+        Importer.FromDiag(D->getLocation(), 
+                          diag::note_odr_objc_missing_superclass);
+      return 0;
+    }
   }
   
   // Import all of the members of this class.
diff --git a/test/ASTMerge/Inputs/interface1.m b/test/ASTMerge/Inputs/interface1.m
index 1aa1c3b..ebcd2bb 100644
--- a/test/ASTMerge/Inputs/interface1.m
+++ b/test/ASTMerge/Inputs/interface1.m
@@ -1,7 +1,23 @@
 // Matches
-@interface I1
+@interface I1 {
+  int ivar1;
+}
 @end
 
 // Matches
-@interface I2 : I1
+@interface I2 : I1 {
+  float ivar2;
+}
+@end
+
+// Ivar mismatch
+@interface I3 {
+  int ivar1;
+  int ivar2;
+}
+@end
+
+// Superclass mismatch
+@interface I4 : I2 {
+}
 @end
diff --git a/test/ASTMerge/Inputs/interface2.m b/test/ASTMerge/Inputs/interface2.m
index 1aa1c3b..2e6b0bf 100644
--- a/test/ASTMerge/Inputs/interface2.m
+++ b/test/ASTMerge/Inputs/interface2.m
@@ -1,7 +1,23 @@
 // Matches
-@interface I1
+@interface I1 {
+  int ivar1;
+}
 @end
 
 // Matches
-@interface I2 : I1
+@interface I2 : I1 {
+  float ivar2;
+}
+@end
+
+// Ivar mismatch
+@interface I3 {
+  int ivar1;
+  float ivar2;
+}
+@end
+
+// Superclass mismatch
+@interface I4 : I1 {
+}
 @end
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
index d6af2f4..ced3fc8 100644
--- a/test/ASTMerge/interface.m
+++ b/test/ASTMerge/interface.m
@@ -1,6 +1,11 @@
 // RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/interface1.m
 // RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/interface2.m
-// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
 
-// FIXME: FileCheck!
+// CHECK: interface2.m:16:9: error: instance variable 'ivar2' declared with incompatible types in different translation units ('float' vs. 'int')
+// CHECK: interface1.m:16:7: note: declared here with type 'int'
+// CHECK: interface1.m:21:1: error: class 'I4' has incompatible superclasses
+// CHECK: interface1.m:21:17: note: inherits from superclass 'I2' here
+// CHECK: interface2.m:21:17: note: inherits from superclass 'I1' here
+// CHECK: 5 diagnostics generated