Extend warnings for missing '@end'.

Fixes PR2709.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145928 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Erik Verbruggen 2011-12-06 09:25:23 +00:00
Родитель 26b45d8608
Коммит d64251fd56
14 изменённых файлов: 128 добавлений и 62 удалений

Просмотреть файл

@ -35,7 +35,7 @@ namespace clang {
DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
DIAG_START_LEX = DIAG_START_FRONTEND + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
DIAG_START_AST = DIAG_START_PARSE + 300,
DIAG_START_AST = DIAG_START_PARSE + 350,
DIAG_START_SEMA = DIAG_START_AST + 100,
DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100

Просмотреть файл

@ -313,7 +313,10 @@ def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
def err_objc_no_attributes_on_category : Error<
"attributes may not be specified on a category">;
def err_objc_missing_end : Error<"missing @end">;
def err_objc_missing_end : Error<"missing '@end'">;
def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
"|category implementation}0 started here">;
def warn_objc_protocol_qualifier_missing_id : Warning<
"protocol qualifiers without 'id' is archaic">;
def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
@ -352,8 +355,8 @@ def err_missing_id_definition : Error<"cannot find definition of 'id'">;
def err_missing_proto_definition : Error<
"cannot find definition of 'Protocol'">;
def err_missing_class_definition : Error<"cannot find definition of 'Class'">;
def err_expected_implementation : Error<
"@end must appear in an @implementation context">;
def err_expected_objc_container : Error<
"'@end' must appear in an Objective-C context">;
def error_property_ivar_decl : Error<
"property synthesize requires specification of an ivar">;
def err_synthesized_property_name : Error<

Просмотреть файл

@ -488,7 +488,6 @@ def note_declared_at : Note<"declared here">;
def note_method_declared_at : Note<"method declared here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
def err_missing_atend : Error<"'@end' is missing in implementation context">;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def error_missing_method_context : Error<

Просмотреть файл

@ -716,6 +716,7 @@ public:
private:
void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
void CheckNestedObjCContexts(SourceLocation AtLoc);
/// SkipUntil - Read tokens until we get to the specified token, then consume
/// it (unless DontConsume is true). Because we cannot guarantee that the
@ -1204,7 +1205,7 @@ private:
// Objective-C External Declarations
Parser::DeclGroupPtrTy ParseObjCAtDirectives();
Parser::DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &prefixAttrs);
void ParseObjCClassInstanceVariables(Decl *interfaceDecl,
tok::ObjCKeywordKind visibility,
@ -1225,7 +1226,7 @@ private:
typedef SmallVector<LexedMethod*, 2> LateParsedObjCMethodContainer;
LateParsedObjCMethodContainer LateParsedObjCMethods;
Decl *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
Decl *ParseObjCAtImplementationDeclaration(SourceLocation AtLoc);
DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
Decl *ParseObjCPropertySynthesize(SourceLocation atLoc);

Просмотреть файл

@ -5173,6 +5173,17 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs);
// Objective-C declarations.
enum ObjCContainerKind {
OCK_None = -1,
OCK_Interface = 0,
OCK_Protocol,
OCK_Category,
OCK_ClassExtension,
OCK_Implementation,
OCK_CategoryImplementation
};
ObjCContainerKind getObjCContainerKind() const;
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLoc,
@ -5275,10 +5286,10 @@ public:
void MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
void ActOnAtEnd(Scope *S, SourceRange AtEnd,
Decl **allMethods = 0, unsigned allNum = 0,
Decl **allProperties = 0, unsigned pNum = 0,
DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd,
Decl **allMethods = 0, unsigned allNum = 0,
Decl **allProperties = 0, unsigned pNum = 0,
DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
Decl *ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,

Просмотреть файл

@ -113,6 +113,23 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ClassNames.size());
}
void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
{
Sema::ObjCContainerKind ock = Actions.getObjCContainerKind();
if (ock == Sema::OCK_None)
return;
Decl *Decl = Actions.ActOnAtEnd(getCurScope(), AtLoc);
Diag(AtLoc, diag::err_objc_missing_end)
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
if (Decl)
Diag(Decl->getLocStart(), diag::note_objc_container_start)
<< (int) ock;
if (!PendingObjCImpDecl.empty())
PendingObjCImpDecl.pop_back();
ObjCImpDecl = 0;
}
///
/// objc-interface:
/// objc-class-interface-attributes[opt] objc-class-interface
@ -141,10 +158,11 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
/// __attribute__((unavailable))
/// __attribute__((objc_exception)) - used by NSException on 64-bit
///
Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &attrs) {
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
CheckNestedObjCContexts(AtLoc);
ConsumeToken(); // the "interface" identifier
// Code completion after '@interface'.
@ -205,7 +223,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
return 0;
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(atLoc,
Actions.ActOnStartCategoryInterface(AtLoc,
nameId, nameLoc,
categoryId, categoryLoc,
ProtocolRefs.data(),
@ -214,7 +232,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
EndProtoLoc);
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc);
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
return CategoryType;
@ -250,14 +268,14 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
return 0;
Decl *ClsType =
Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
superClassId, superClassLoc,
ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
return ClsType;
@ -425,7 +443,10 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
case tok::objc_implementation:
case tok::objc_interface:
Diag(Tok, diag::err_objc_missing_end);
Diag(AtLoc, diag::err_objc_missing_end)
<< FixItHint::CreateInsertion(AtLoc, "@end\n");
Diag(CDecl->getLocStart(), diag::note_objc_container_start)
<< (int) Actions.getObjCContainerKind();
ConsumeToken();
break;
@ -465,10 +486,16 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtDirective(getCurScope());
return cutOffParsing();
} else if (Tok.isObjCAtKeyword(tok::objc_end))
} else if (Tok.isObjCAtKeyword(tok::objc_end)) {
ConsumeToken(); // the "end" identifier
else
Diag(Tok, diag::err_objc_missing_end);
} else {
Diag(Tok, diag::err_objc_missing_end)
<< FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
Diag(CDecl->getLocStart(), diag::note_objc_container_start)
<< (int) Actions.getObjCContainerKind();
AtEnd.setBegin(Tok.getLocation());
AtEnd.setEnd(Tok.getLocation());
}
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
@ -1316,6 +1343,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
ParsedAttributes &attrs) {
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
CheckNestedObjCContexts(AtLoc);
ConsumeToken(); // the "protocol" identifier
if (Tok.is(tok::code_completion)) {
@ -1399,10 +1427,10 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
///
/// objc-category-implementation-prologue:
/// @implementation identifier ( identifier )
Decl *Parser::ParseObjCAtImplementationDeclaration(
SourceLocation atLoc) {
Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
CheckNestedObjCContexts(AtLoc);
ConsumeToken(); // the "implementation" identifier
// Code completion after '@implementation'.
@ -1446,7 +1474,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
}
rparenLoc = ConsumeParen();
Decl *ImplCatType = Actions.ActOnStartCategoryImplementation(
atLoc, nameId, nameLoc, categoryId,
AtLoc, nameId, nameLoc, categoryId,
categoryLoc);
ObjCImpDecl = ImplCatType;
@ -1467,11 +1495,11 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
superClassLoc = ConsumeToken(); // Consume super class name
}
Decl *ImplClsType = Actions.ActOnStartClassImplementation(
atLoc, nameId, nameLoc,
AtLoc, nameId, nameLoc,
superClassId, superClassLoc);
if (Tok.is(tok::l_brace)) // we have ivars
ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc);
ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, AtLoc);
ObjCImpDecl = ImplClsType;
PendingObjCImpDecl.push_back(ObjCImpDecl);
@ -1498,7 +1526,7 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
}
else
// missing @implementation
Diag(atEnd.getBegin(), diag::err_expected_implementation);
Diag(atEnd.getBegin(), diag::err_expected_objc_container);
clearLateParsedObjCMethods();
ObjCImpDecl = 0;
@ -1510,8 +1538,15 @@ Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
Actions.DiagnoseUseOfUnimplementedSelectors();
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(0);
Decl *ImpDecl = PendingObjCImpDecl.pop_back_val();
Actions.ActOnAtEnd(getCurScope(), SourceRange());
Actions.ActOnAtEnd(getCurScope(), SourceRange(Tok.getLocation()));
Diag(Tok, diag::err_objc_missing_end)
<< FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
if (ImpDecl)
Diag(ImpDecl->getLocStart(), diag::note_objc_container_start)
<< Sema::OCK_Implementation;
return Actions.ConvertDeclToDeclGroup(ImpDecl);
}

Просмотреть файл

@ -2148,15 +2148,39 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
}
}
Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
switch (CurContext->getDeclKind()) {
case Decl::ObjCInterface:
return Sema::OCK_Interface;
case Decl::ObjCProtocol:
return Sema::OCK_Protocol;
case Decl::ObjCCategory:
if (dyn_cast<ObjCCategoryDecl>(CurContext)->IsClassExtension())
return Sema::OCK_ClassExtension;
else
return Sema::OCK_Category;
case Decl::ObjCImplementation:
return Sema::OCK_Implementation;
case Decl::ObjCCategoryImpl:
return Sema::OCK_CategoryImplementation;
default:
return Sema::OCK_None;
}
}
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Decl **allMethods, unsigned allNum,
Decl **allProperties, unsigned pNum,
DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
Decl **allMethods, unsigned allNum,
Decl **allProperties, unsigned pNum,
DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
if (getObjCContainerKind() == Sema::OCK_None)
return 0;
assert(AtEnd.isValid() && "Invalid location for '@end'");
if (!CurContext->isObjCContainer())
return;
ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
Decl *ClassDecl = cast<Decl>(OCD);
@ -2165,15 +2189,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
if (!isInterfaceDeclKind && AtEnd.isInvalid()) {
// FIXME: This is wrong. We shouldn't be pretending that there is
// an '@end' in the declaration.
SourceLocation L = OCD->getAtStartLoc();
AtEnd.setBegin(L);
AtEnd.setEnd(L);
Diag(L, diag::err_missing_atend);
}
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@ -2335,6 +2350,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
(*I)->setTopLevelDeclInObjCContainer();
Consumer.HandleTopLevelDeclInObjCContainer(DG);
}
return ClassDecl;
}

Просмотреть файл

@ -4,4 +4,4 @@
@interface Rdar8452791 () - (void)rdar8452791;
// CHECK: error: cannot find interface declaration for 'Rdar8452791'
// CHECK: missing @end
// CHECK: missing '@end'

Просмотреть файл

@ -1,19 +1,19 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar: //7824372
@interface A
@interface A // expected-note {{class started here}}
-(void) im0;
@implementation A // expected-error {{missing @end}}
@implementation A // expected-error {{missing '@end'}}
@end
@interface B {
@interface B { // expected-note {{class started here}}
}
@implementation B // expected-error {{missing @end}}
@implementation B // expected-error {{missing '@end'}}
@end
@interface C
@interface C // expected-note 2 {{class started here}}
@property int P;
@implementation C // expected-error 2 {{missing @end}}
@implementation C // expected-error 2 {{missing '@end'}}

Просмотреть файл

@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://8283484
@interface blah {
@interface blah { // expected-note {{class started here}}
@private
}
// since I forgot the @end here it should say something
@interface blah // expected-error {{missing @end}}
@interface blah // expected-error {{missing '@end'}}
@end // and Unknown type name 'end' here

Просмотреть файл

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface AAA
@interface AAA // expected-note {{class started here}}
{
}
@ x// expected-error{{expected an Objective-C directive after '@'}}
// expected-error{{missing @end}}
// expected-error{{missing '@end'}}

Просмотреть файл

@ -1,2 +1,2 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@end // expected-error {{@end must appear in an @implementation context}}
@end // expected-error {{'@end' must appear in an Objective-C context}}

Просмотреть файл

@ -5,8 +5,8 @@ int @"s" = 5; // expected-error {{prefix attribute must be}}
// rdar://6480479
@interface A
}; // expected-error {{missing @end}} \
@interface A // expected-note {{class started here}}
}; // expected-error {{missing '@end'}} \
// expected-error {{expected external declaration}} \
// expected-warning{{extra ';' outside of a function}}

Просмотреть файл

@ -3,20 +3,20 @@
@interface I0
@end
@implementation I0 // expected-error {{'@end' is missing in implementation context}}
@implementation I0 // expected-note {{implementation started here}}
- meth { return 0; }
@interface I1 : I0
@interface I1 : I0 // expected-error {{missing '@end'}}
@end
@implementation I1 // expected-error {{'@end' is missing in implementation context}}
@implementation I1 // expected-note {{implementation started here}}
-(void) im0 { self = [super init]; }
@interface I2 : I0
@interface I2 : I0 // expected-error {{missing '@end'}}
- I2meth;
@end
@implementation I2 // expected-error {{'@end' is missing in implementation context}}
@implementation I2 // expected-note {{implementation started here}}
- I2meth { return 0; }
@implementation I2(CAT) // expected-error {{'@end' is missing in implementation context}}
@implementation I2(CAT) // expected-error 2 {{missing '@end'}} expected-note {{implementation started here}}