diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 62d46abd7426..cc89c7caec3c 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -74,5 +74,8 @@ def err_odr_objc_method_variadic_inconsistent : Error< "and not variadic in another">; def note_odr_objc_method_here : Note< "%select{class|instance}0 method %1 also declared here">; +def err_odr_objc_property_type_inconsistent : Error< + "property %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 7b3fb00543d1..ffeaa23276b9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -96,7 +96,8 @@ namespace { Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); - + Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D); + // Importing statements Stmt *VisitStmt(Stmt *S); @@ -2315,6 +2316,66 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { return ToIface; } +Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + // Import the major distinguishing characteristics of an @property. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Check whether we have already imported this property. + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (ObjCPropertyDecl *FoundProp + = dyn_cast(*Lookup.first)) { + // Check property types. + if (!Importer.IsStructurallyEquivalent(D->getType(), + FoundProp->getType())) { + Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) + << Name << D->getType() << FoundProp->getType(); + Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here) + << FoundProp->getType(); + return 0; + } + + // FIXME: Check property attributes, getters, setters, etc.? + + // Consider these properties to be equivalent. + Importer.Imported(D, FoundProp); + return FoundProp; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the new property. + ObjCPropertyDecl *ToProperty + = ObjCPropertyDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getAtLoc()), + T, + D->getPropertyImplementation()); + Importer.Imported(D, ToProperty); + ToProperty->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToProperty); + + ToProperty->setPropertyAttributes(D->getPropertyAttributes()); + ToProperty->setGetterName(Importer.Import(D->getGetterName())); + ToProperty->setSetterName(Importer.Import(D->getSetterName())); + ToProperty->setGetterMethodDecl( + cast_or_null(Importer.Import(D->getGetterMethodDecl()))); + ToProperty->setSetterMethodDecl( + cast_or_null(Importer.Import(D->getSetterMethodDecl()))); + ToProperty->setPropertyIvarDecl( + cast_or_null(Importer.Import(D->getPropertyIvarDecl()))); + return ToProperty; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- diff --git a/clang/test/ASTMerge/Inputs/property1.m b/clang/test/ASTMerge/Inputs/property1.m new file mode 100644 index 000000000000..37887a34f767 --- /dev/null +++ b/clang/test/ASTMerge/Inputs/property1.m @@ -0,0 +1,12 @@ +// Matching properties +@interface I1 { +} +- (int)getProp2; +- (void)setProp2:(int)value; +@end + +// Mismatched property +@interface I2 +@property (readonly) float Prop1; +@end + diff --git a/clang/test/ASTMerge/Inputs/property2.m b/clang/test/ASTMerge/Inputs/property2.m new file mode 100644 index 000000000000..6039f10ec6e8 --- /dev/null +++ b/clang/test/ASTMerge/Inputs/property2.m @@ -0,0 +1,13 @@ +// Matching properties +@interface I1 { +} +- (int)getProp2; +- (void)setProp2:(int)value; +@property (readonly) int Prop1; +@property (getter = getProp2, setter = setProp2:) int Prop2; +@end + +// Mismatched property +@interface I2 +@property (readonly) int Prop1; +@end diff --git a/clang/test/ASTMerge/property.m b/clang/test/ASTMerge/property.m new file mode 100644 index 000000000000..0fd7e4872d72 --- /dev/null +++ b/clang/test/ASTMerge/property.m @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/property1.m +// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/property2.m +// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s + +// CHECK: property2.m:12:26: error: property 'Prop1' declared with incompatible types in different translation units ('int' vs. 'float') +// 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: 4 diagnostics generated.