AST import for Objective-C protocols

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96478 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index a6e565d..7b3fb00 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -94,6 +94,7 @@
     Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitParmVarDecl(ParmVarDecl *D);
     Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
+    Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
     Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
                             
     // Importing statements
@@ -2130,6 +2131,70 @@
   return ToMethod;
 }
 
+Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+  // Import the major distinguishing characteristics of an @protocol.
+  DeclContext *DC, *LexicalDC;
+  DeclarationName Name;
+  SourceLocation Loc;
+  if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+    return 0;
+
+  ObjCProtocolDecl *MergeWithProtocol = 0;
+  for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+       Lookup.first != Lookup.second; 
+       ++Lookup.first) {
+    if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
+      continue;
+    
+    if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(*Lookup.first)))
+      break;
+  }
+  
+  ObjCProtocolDecl *ToProto = MergeWithProtocol;
+  if (!ToProto || ToProto->isForwardDecl()) {
+    if (!ToProto) {
+      ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, Loc,
+                                         Name.getAsIdentifierInfo());
+      ToProto->setForwardDecl(D->isForwardDecl());
+      ToProto->setLexicalDeclContext(LexicalDC);
+      LexicalDC->addDecl(ToProto);
+    }
+    Importer.Imported(D, ToProto);
+
+    // Import protocols
+    llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols;
+    llvm::SmallVector<SourceLocation, 4> ProtocolLocs;
+    ObjCProtocolDecl::protocol_loc_iterator 
+      FromProtoLoc = D->protocol_loc_begin();
+    for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(),
+                                          FromProtoEnd = D->protocol_end();
+       FromProto != FromProtoEnd;
+       ++FromProto, ++FromProtoLoc) {
+      ObjCProtocolDecl *ToProto
+        = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
+      if (!ToProto)
+        return 0;
+      Protocols.push_back(ToProto);
+      ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
+    }
+    
+    // FIXME: If we're merging, make sure that the protocol list is the same.
+    ToProto->setProtocolList(Protocols.data(), Protocols.size(),
+                             ProtocolLocs.data(), Importer.getToContext());
+  } else {
+    Importer.Imported(D, ToProto);
+  }
+
+  // Import all of the members of this class.
+  for (DeclContext::decl_iterator FromMem = D->decls_begin(), 
+                               FromMemEnd = D->decls_end();
+       FromMem != FromMemEnd;
+       ++FromMem)
+    Importer.Import(*FromMem);
+
+  return ToProto;
+}
+
 Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   // Import the major distinguishing characteristics of an @interface.
   DeclContext *DC, *LexicalDC;
@@ -2158,6 +2223,7 @@
                                           Importer.Import(D->getClassLoc()),
                                           D->isForwardDecl(),
                                           D->isImplicitInterfaceDecl());
+      ToIface->setForwardDecl(D->isForwardDecl());
       ToIface->setLexicalDeclContext(LexicalDC);
       LexicalDC->addDecl(ToIface);
     }
@@ -2246,7 +2312,7 @@
     ToIface->setImplementation(Impl);
   }
   
-  return 0;
+  return ToIface;
 }
 
 //----------------------------------------------------------------------------
diff --git a/test/ASTMerge/Inputs/interface1.m b/test/ASTMerge/Inputs/interface1.m
index bde6674..a508bc1 100644
--- a/test/ASTMerge/Inputs/interface1.m
+++ b/test/ASTMerge/Inputs/interface1.m
@@ -45,3 +45,26 @@
 - (int)foo;
 + (int)bar:(float)x;
 @end
+
+// Matching protocol
+@protocol P0
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with mismatching method
+@protocol P1
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Interface with protocol
+@interface I9 <P0>
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with protocol
+@protocol P2 <P0>
+- (float)wibble:(int)a1 second:(int)a2;
+@end
diff --git a/test/ASTMerge/Inputs/interface2.m b/test/ASTMerge/Inputs/interface2.m
index 1d5bebd..d79f77d 100644
--- a/test/ASTMerge/Inputs/interface2.m
+++ b/test/ASTMerge/Inputs/interface2.m
@@ -44,3 +44,26 @@
 - (int)foo;
 + (int)bar:(float)x, ...;
 @end
+
+// Matching protocol
+@protocol P0
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with mismatching method
+@protocol P1
++ (int)foo;
+- (int)bar:(double)x;
+@end
+
+// Interface with protocol
+@interface I9 <P0>
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with protocol
+@protocol P2 <P0>
+- (float)wibble:(int)a1 second:(int)a2;
+@end
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
index 465077b..47e4e05 100644
--- a/test/ASTMerge/interface.m
+++ b/test/ASTMerge/interface.m
@@ -13,5 +13,7 @@
 // CHECK: interface1.m:40:17: note: declared here with type 'int'
 // CHECK: interface2.m:45:1: error: class method 'bar:' is variadic in one translation unit and not variadic in another
 // CHECK: interface1.m:46:1: note: class method 'bar:' also declared here
-// CHECK: 11 diagnostics generated
+// CHECK: interface2.m:57:20: error: instance method 'bar:' has a parameter with a different types in different translation units ('double' vs. 'float')
+// CHECK: interface1.m:58:19: note: declared here with type 'float'
+// CHECK: 13 diagnostics generated