[cfe-commits] r96442 - in /cfe/trunk: include/clang/AST/ASTImporter.h include/clang/Basic/DiagnosticASTKinds.td lib/AST/ASTImporter.cpp test/ASTMerge/Inputs/interface1.m test/ASTMerge/Inputs/interface2.m test/ASTMerge/interface.m

Douglas Gregor dgregor at apple.com
Tue Feb 16 18:12:47 PST 2010


Author: dgregor
Date: Tue Feb 16 20:12:47 2010
New Revision: 96442

URL: http://llvm.org/viewvc/llvm-project?rev=96442&view=rev
Log:
Implement AST importing and checking for Objective-C method declarations.

Modified:
    cfe/trunk/include/clang/AST/ASTImporter.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/test/ASTMerge/Inputs/interface1.m
    cfe/trunk/test/ASTMerge/Inputs/interface2.m
    cfe/trunk/test/ASTMerge/interface.m

Modified: cfe/trunk/include/clang/AST/ASTImporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTImporter.h?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTImporter.h (original)
+++ cfe/trunk/include/clang/AST/ASTImporter.h Tue Feb 16 20:12:47 2010
@@ -156,6 +156,12 @@
     /// \returns the equivalent identifier in the "to" context.
     IdentifierInfo *Import(IdentifierInfo *FromId);
 
+    /// \brief Import the given Objective-C selector from the "from"
+    /// context into the "to" context.
+    ///
+    /// \returns the equivalent selector in the "to" context.
+    Selector Import(Selector FromSel);
+
     /// \brief Import the given file ID from the "from" context into the 
     /// "to" context.
     ///

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Tue Feb 16 20:12:47 2010
@@ -60,6 +60,19 @@
   "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_odr_objc_method_result_type_inconsistent : Error<
+  "%select{class|instance}0 method %1 has incompatible result types in "
+  "different translation units (%2 vs. %3)">;
+def err_odr_objc_method_num_params_inconsistent : Error<
+  "%select{class|instance}0 method %1 has a different number of parameters in "
+  "different translation units (%2 vs. %3)">;
+def err_odr_objc_method_param_type_inconsistent : Error<
+  "%select{class|instance}0 method %1 has a parameter with a different types "
+  "in different translation units (%2 vs. %3)">;
+def err_odr_objc_method_variadic_inconsistent : Error<
+  "%select{class|instance}0 method %1 is variadic in one translation unit "
+  "and not variadic in another">;
+def note_odr_objc_method_here : Note<
+  "%select{class|instance}0 method %1 also declared here">;
 def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
 }

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Feb 16 20:12:47 2010
@@ -93,6 +93,7 @@
     Decl *VisitObjCIvarDecl(ObjCIvarDecl *D);
     Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitParmVarDecl(ParmVarDecl *D);
+    Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
     Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
                             
     // Importing statements
@@ -1774,25 +1775,25 @@
   
   // Create the imported function.
   TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
-  FunctionDecl *ToEnumerator
+  FunctionDecl *ToFunction
     = FunctionDecl::Create(Importer.getToContext(), DC, Loc, 
                            Name, T, TInfo, D->getStorageClass(), 
                            D->isInlineSpecified(),
                            D->hasWrittenPrototype());
-  ToEnumerator->setLexicalDeclContext(LexicalDC);
-  Importer.Imported(D, ToEnumerator);
-  LexicalDC->addDecl(ToEnumerator);
+  ToFunction->setLexicalDeclContext(LexicalDC);
+  Importer.Imported(D, ToFunction);
+  LexicalDC->addDecl(ToFunction);
 
   // Set the parameters.
   for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
-    Parameters[I]->setOwningFunction(ToEnumerator);
-    ToEnumerator->addDecl(Parameters[I]);
+    Parameters[I]->setOwningFunction(ToFunction);
+    ToFunction->addDecl(Parameters[I]);
   }
-  ToEnumerator->setParams(Parameters.data(), Parameters.size());
+  ToFunction->setParams(Parameters.data(), Parameters.size());
 
   // FIXME: Other bits to merge?
   
-  return ToEnumerator;
+  return ToFunction;
 }
 
 Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
@@ -2013,6 +2014,122 @@
   return Importer.Imported(D, ToParm);
 }
 
+Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+  // Import the major distinguishing characteristics of a method.
+  DeclContext *DC, *LexicalDC;
+  DeclarationName Name;
+  SourceLocation Loc;
+  if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+    return 0;
+  
+  for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+       Lookup.first != Lookup.second; 
+       ++Lookup.first) {
+    if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(*Lookup.first)) {
+      if (FoundMethod->isInstanceMethod() != D->isInstanceMethod())
+        continue;
+
+      // Check return types.
+      if (!Importer.IsStructurallyEquivalent(D->getResultType(),
+                                             FoundMethod->getResultType())) {
+        Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent)
+          << D->isInstanceMethod() << Name
+          << D->getResultType() << FoundMethod->getResultType();
+        Importer.ToDiag(FoundMethod->getLocation(), 
+                        diag::note_odr_objc_method_here)
+          << D->isInstanceMethod() << Name;
+        return 0;
+      }
+
+      // Check the number of parameters.
+      if (D->param_size() != FoundMethod->param_size()) {
+        Importer.ToDiag(Loc, diag::err_odr_objc_method_num_params_inconsistent)
+          << D->isInstanceMethod() << Name
+          << D->param_size() << FoundMethod->param_size();
+        Importer.ToDiag(FoundMethod->getLocation(), 
+                        diag::note_odr_objc_method_here)
+          << D->isInstanceMethod() << Name;
+        return 0;
+      }
+
+      // Check parameter types.
+      for (ObjCMethodDecl::param_iterator P = D->param_begin(), 
+             PEnd = D->param_end(), FoundP = FoundMethod->param_begin();
+           P != PEnd; ++P, ++FoundP) {
+        if (!Importer.IsStructurallyEquivalent((*P)->getType(), 
+                                               (*FoundP)->getType())) {
+          Importer.FromDiag((*P)->getLocation(), 
+                            diag::err_odr_objc_method_param_type_inconsistent)
+            << D->isInstanceMethod() << Name
+            << (*P)->getType() << (*FoundP)->getType();
+          Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here)
+            << (*FoundP)->getType();
+          return 0;
+        }
+      }
+
+      // Check variadic/non-variadic.
+      // Check the number of parameters.
+      if (D->isVariadic() != FoundMethod->isVariadic()) {
+        Importer.ToDiag(Loc, diag::err_odr_objc_method_variadic_inconsistent)
+          << D->isInstanceMethod() << Name;
+        Importer.ToDiag(FoundMethod->getLocation(), 
+                        diag::note_odr_objc_method_here)
+          << D->isInstanceMethod() << Name;
+        return 0;
+      }
+
+      // FIXME: Any other bits we need to merge?
+      return Importer.Imported(D, FoundMethod);
+    }
+  }
+
+  // Import the result type.
+  QualType ResultTy = Importer.Import(D->getResultType());
+  if (ResultTy.isNull())
+    return 0;
+
+  ObjCMethodDecl *ToMethod
+    = ObjCMethodDecl::Create(Importer.getToContext(),
+                             Loc,
+                             Importer.Import(D->getLocEnd()),
+                             Name.getObjCSelector(),
+                             ResultTy, DC,
+                             D->isInstanceMethod(),
+                             D->isVariadic(),
+                             D->isSynthesized(),
+                             D->getImplementationControl());
+
+  // FIXME: When we decide to merge method definitions, we'll need to
+  // deal with implicit parameters.
+
+  // Import the parameters
+  llvm::SmallVector<ParmVarDecl *, 5> ToParams;
+  for (ObjCMethodDecl::param_iterator FromP = D->param_begin(),
+                                   FromPEnd = D->param_end();
+       FromP != FromPEnd; 
+       ++FromP) {
+    ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*FromP));
+    if (!ToP)
+      return 0;
+    
+    ToParams.push_back(ToP);
+  }
+  
+  // Set the parameters.
+  for (unsigned I = 0, N = ToParams.size(); I != N; ++I) {
+    ToParams[I]->setOwningFunction(ToMethod);
+    ToMethod->addDecl(ToParams[I]);
+  }
+  ToMethod->setMethodParams(Importer.getToContext(), 
+                            ToParams.data(), ToParams.size());
+
+  ToMethod->setLexicalDeclContext(LexicalDC);
+  Importer.Imported(D, ToMethod);
+  LexicalDC->addDecl(ToMethod);
+  return ToMethod;
+}
+
 Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   // Import the major distinguishing characteristics of an @interface.
   DeclContext *DC, *LexicalDC;
@@ -2432,6 +2549,17 @@
   return &ToContext.Idents.get(FromId->getName());
 }
 
+Selector ASTImporter::Import(Selector FromSel) {
+  if (FromSel.isNull())
+    return Selector();
+
+  llvm::SmallVector<IdentifierInfo *, 4> Idents;
+  Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0)));
+  for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I)
+    Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I)));
+  return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data());
+}
+
 DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
                                                 DeclContext *DC,
                                                 unsigned IDNS,

Modified: cfe/trunk/test/ASTMerge/Inputs/interface1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/interface1.m?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/interface1.m (original)
+++ cfe/trunk/test/ASTMerge/Inputs/interface1.m Tue Feb 16 20:12:47 2010
@@ -21,3 +21,27 @@
 @interface I4 : I2 {
 }
 @end
+
+// Methods match
+ at interface I5
+- (int)foo;
++ (float)bar;
+ at end
+
+// Method mismatch
+ at interface I6
+- (int)foo;
++ (int)foo;
+ at end
+
+// Method mismatch
+ at interface I7
+- (int)foo;
++ (int)bar:(int)x;
+ at end
+
+// Method mismatch
+ at interface I8
+- (int)foo;
++ (int)bar:(float)x;
+ at end

Modified: cfe/trunk/test/ASTMerge/Inputs/interface2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/interface2.m?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/interface2.m (original)
+++ cfe/trunk/test/ASTMerge/Inputs/interface2.m Tue Feb 16 20:12:47 2010
@@ -21,3 +21,26 @@
 @interface I4 : I1 {
 }
 @end
+
+// Methods match
+ at interface I5
++ (float)bar;
+- (int)foo;
+ at end
+
+// Method mismatch
+ at interface I6
++ (float)foo;
+ at end
+
+// Method mismatch
+ at interface I7
+- (int)foo;
++ (int)bar:(float)x;
+ at end
+
+// Method mismatch
+ at interface I8
+- (int)foo;
++ (int)bar:(float)x, ...;
+ at end

Modified: cfe/trunk/test/ASTMerge/interface.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/interface.m?rev=96442&r1=96441&r2=96442&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/interface.m (original)
+++ cfe/trunk/test/ASTMerge/interface.m Tue Feb 16 20:12:47 2010
@@ -7,5 +7,11 @@
 // 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
+// CHECK: interface2.m:33:1: error: class method 'foo' has incompatible result types in different translation units ('float' vs. 'int')
+// CHECK: interface1.m:34:1: note: class method 'foo' also declared here
+// CHECK: interface2.m:39:19: error: class method 'bar:' has a parameter with a different types in different translation units ('float' vs. 'int')
+// 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
 





More information about the cfe-commits mailing list