forked from OSchip/llvm-project
Implement AST importing and checking for Objective-C method declarations.
llvm-svn: 96442
This commit is contained in:
parent
03db9e9cd3
commit
43f54796ab
|
@ -156,6 +156,12 @@ namespace clang {
|
|||
/// \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.
|
||||
///
|
||||
|
|
|
@ -60,6 +60,19 @@ 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_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">;
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ namespace {
|
|||
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 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
|
||||
// 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 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
|
|||
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 @@ IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) {
|
|||
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,
|
||||
|
|
|
@ -21,3 +21,27 @@
|
|||
@interface I4 : I2 {
|
||||
}
|
||||
@end
|
||||
|
||||
// Methods match
|
||||
@interface I5
|
||||
- (int)foo;
|
||||
+ (float)bar;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I6
|
||||
- (int)foo;
|
||||
+ (int)foo;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I7
|
||||
- (int)foo;
|
||||
+ (int)bar:(int)x;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I8
|
||||
- (int)foo;
|
||||
+ (int)bar:(float)x;
|
||||
@end
|
||||
|
|
|
@ -21,3 +21,26 @@
|
|||
@interface I4 : I1 {
|
||||
}
|
||||
@end
|
||||
|
||||
// Methods match
|
||||
@interface I5
|
||||
+ (float)bar;
|
||||
- (int)foo;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I6
|
||||
+ (float)foo;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I7
|
||||
- (int)foo;
|
||||
+ (int)bar:(float)x;
|
||||
@end
|
||||
|
||||
// Method mismatch
|
||||
@interface I8
|
||||
- (int)foo;
|
||||
+ (int)bar:(float)x, ...;
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue