Implement AST import for Objective-C property implementations
(@synthesize and @dynamic).


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121159 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index eda7356..7d45bc5 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -56,6 +56,8 @@
   "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">;
+
+// Importing Objective-C ASTs
 def err_odr_ivar_type_inconsistent : Error<
   "instance variable %0 declared with incompatible types in different "
   "translation units (%1 vs. %2)">;
@@ -80,6 +82,18 @@
 def err_odr_objc_property_type_inconsistent : Error<
   "property %0 declared with incompatible types in different "
   "translation units (%1 vs. %2)">;
+def err_odr_objc_property_impl_kind_inconsistent : Error<
+  "property %0 is implemented with %select{@synthesize|@dynamic}1 in one "
+  "translation but %select{@dynamic|@synthesize}1 in another translation unit">;
+def note_odr_objc_property_impl_kind : Note<
+  "property %0 is implemented with %select{@synthesize|@dynamic}1 here">;
+def err_odr_objc_synthesize_ivar_inconsistent : Error<
+  "property %0 is synthesized to different ivars in different translation "
+  "units (%1 vs. %2)">;
+def note_odr_objc_synthesize_ivar_here : Note<
+  "property is synthesized to ivar %0 here">;
+
+// Importing C++ ASTs
 def err_odr_different_num_template_parameters : Error<
   "template parameter lists have a different number of parameters (%0 vs %1)">;
 def note_odr_template_parameter_list : Note<
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index c531405..7a6afbd 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -118,6 +118,7 @@
     Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
     Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
     Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+    Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
     Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
     Decl *VisitObjCClassDecl(ObjCClassDecl *D);
     Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
@@ -3195,6 +3196,87 @@
   return ToProperty;
 }
 
+Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+  ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>(
+                                        Importer.Import(D->getPropertyDecl()));
+  if (!Property)
+    return 0;
+
+  DeclContext *DC = Importer.ImportContext(D->getDeclContext());
+  if (!DC)
+    return 0;
+  
+  // Import the lexical declaration context.
+  DeclContext *LexicalDC = DC;
+  if (D->getDeclContext() != D->getLexicalDeclContext()) {
+    LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+    if (!LexicalDC)
+      return 0;
+  }
+
+  ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC);
+  if (!InImpl)
+    return 0;
+
+  // Import the ivar (for an @synthesize).
+  ObjCIvarDecl *Ivar = 0;
+  if (D->getPropertyIvarDecl()) {
+    Ivar = cast_or_null<ObjCIvarDecl>(
+                                    Importer.Import(D->getPropertyIvarDecl()));
+    if (!Ivar)
+      return 0;
+  }
+
+  ObjCPropertyImplDecl *ToImpl
+    = InImpl->FindPropertyImplDecl(Property->getIdentifier());
+  if (!ToImpl) {    
+    ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC,
+                                          Importer.Import(D->getLocStart()),
+                                          Importer.Import(D->getLocation()),
+                                          Property,
+                                          D->getPropertyImplementation(),
+                                          Ivar, 
+                                  Importer.Import(D->getPropertyIvarDeclLoc()));
+    ToImpl->setLexicalDeclContext(LexicalDC);
+    Importer.Imported(D, ToImpl);
+    LexicalDC->addDecl(ToImpl);
+  } else {
+    // Check that we have the same kind of property implementation (@synthesize
+    // vs. @dynamic).
+    if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) {
+      Importer.ToDiag(ToImpl->getLocation(), 
+                      diag::err_odr_objc_property_impl_kind_inconsistent)
+        << Property->getDeclName() 
+        << (ToImpl->getPropertyImplementation() 
+                                              == ObjCPropertyImplDecl::Dynamic);
+      Importer.FromDiag(D->getLocation(),
+                        diag::note_odr_objc_property_impl_kind)
+        << D->getPropertyDecl()->getDeclName()
+        << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic);
+      return 0;
+    }
+    
+    // For @synthesize, check that we have the same 
+    if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize &&
+        Ivar != ToImpl->getPropertyIvarDecl()) {
+      Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), 
+                      diag::err_odr_objc_synthesize_ivar_inconsistent)
+        << Property->getDeclName()
+        << ToImpl->getPropertyIvarDecl()->getDeclName()
+        << Ivar->getDeclName();
+      Importer.FromDiag(D->getPropertyIvarDeclLoc(), 
+                        diag::note_odr_objc_synthesize_ivar_here)
+        << D->getPropertyIvarDecl()->getDeclName();
+      return 0;
+    }
+    
+    // Merge the existing implementation with the new implementation.
+    Importer.Imported(D, ToImpl);
+  }
+  
+  return ToImpl;
+}
+
 Decl *
 ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
   // Import the context of this declaration.
diff --git a/test/ASTMerge/Inputs/property1.m b/test/ASTMerge/Inputs/property1.m
index 37887a3..22fe0a0 100644
--- a/test/ASTMerge/Inputs/property1.m
+++ b/test/ASTMerge/Inputs/property1.m
@@ -10,3 +10,22 @@
 @property (readonly) float Prop1;
 @end
 
+// Properties with implementations
+@interface I3 {
+  int ivar1;
+  int ivar2;
+  int ivar3;
+  int Prop4;
+}
+@property int Prop1;
+@property int Prop2;
+@property int Prop3;
+@property int Prop4;
+@end
+
+@implementation I3
+@synthesize Prop1 = ivar1;
+@synthesize Prop2 = ivar3;
+@dynamic Prop3;
+@synthesize Prop4;
+@end
diff --git a/test/ASTMerge/Inputs/property2.m b/test/ASTMerge/Inputs/property2.m
index 6039f10..64a03fb 100644
--- a/test/ASTMerge/Inputs/property2.m
+++ b/test/ASTMerge/Inputs/property2.m
@@ -11,3 +11,23 @@
 @interface I2
 @property (readonly) int Prop1;
 @end
+
+// Properties with implementations
+@interface I3 {
+  int ivar1;
+  int ivar2;
+  int ivar3;
+  int Prop4;
+}
+@property int Prop1;
+@property int Prop2;
+@property int Prop3;
+@property int Prop4;
+@end
+
+@implementation I3
+@synthesize Prop2 = ivar2;
+@synthesize Prop1 = ivar1;
+@synthesize Prop3 = ivar3;
+@synthesize Prop4 = Prop4;
+@end
diff --git a/test/ASTMerge/property.m b/test/ASTMerge/property.m
index 5f7a730..a8dd7c4 100644
--- a/test/ASTMerge/property.m
+++ b/test/ASTMerge/property.m
@@ -6,4 +6,8 @@
 // CHECK: property1.m:10:28: note: declared here with type 'float'
 // CHECK: property2.m:12:26: error: instance method 'Prop1' has incompatible result types in different translation units ('int' vs. 'float')
 // CHECK: property1.m:10:28: note: instance method 'Prop1' also declared here
-// CHECK: 2 errors generated.
+// CHECK: property1.m:28:21: error: property 'Prop2' is synthesized to different ivars in different translation units ('ivar3' vs. 'ivar2')
+// CHECK: property2.m:29:21: note: property is synthesized to ivar 'ivar2' here
+// CHECK: property1.m:29:10: error: property 'Prop3' is implemented with @dynamic in one translation but @synthesize in another translation unit
+// CHECK: property2.m:31:13: note: property 'Prop3' is implemented with @synthesize here
+// CHECK: 4 errors generated.