diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2009-11-16 18:57:01 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2009-11-16 18:57:01 +0000 |
commit | 63e963cdffca9530f920dbab58b9b4eecb2a582c (patch) | |
tree | 807e73d8edf9a9d5ee0933cb78ecce26fbf98878 | |
parent | 2a70e94c543338059432fc38b801a56c60f0e0d7 (diff) |
Handle case of missing '@end' in implementation context
gracefully, on par with gcc, by: Issuing a warning,
doing final sematinc check of its definitions and generating
its meta-data.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@88934 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 1 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/ParseAST.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 7 | ||||
-rw-r--r-- | test/Analysis/NSString.m | 3 | ||||
-rw-r--r-- | test/Analysis/PR3991.m | 11 | ||||
-rw-r--r-- | test/Analysis/misc-ps.m | 1 | ||||
-rw-r--r-- | test/Analysis/pr4209.m | 10 | ||||
-rw-r--r-- | test/Analysis/region-1.m | 1 | ||||
-rw-r--r-- | test/CodeGenObjC/missing-atend-metadata.m | 24 | ||||
-rw-r--r-- | test/SemaObjC/compare-qualified-id.m | 5 | ||||
-rw-r--r-- | test/SemaObjC/method-arg-decay.m | 5 |
13 files changed, 77 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e3f2383798..bd0dec6a8d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -251,6 +251,7 @@ def warn_accessor_property_type_mismatch : Warning< def note_declared_at : Note<"declared at">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; +def warn_missing_atend : Warning<"'@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< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3e75189aea..f436a75e29 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -179,6 +179,8 @@ public: /// the EOF was encountered. bool ParseTopLevelDecl(DeclGroupPtrTy &Result); + DeclGroupPtrTy RetreivePendingObjCImpDecl(); + private: //===--------------------------------------------------------------------===// // Low-Level token peeking and consumption methods. @@ -783,6 +785,7 @@ private: AttributeList *prefixAttrs = 0); DeclPtrTy ObjCImpDecl; + llvm::SmallVector<DeclPtrTy, 4> PendingObjCImpDecl; DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc); DeclPtrTy ParseObjCAtEndDeclaration(SourceLocation atLoc); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 29f3fc0a57..2ae0c690ca 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -123,6 +123,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); } + // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); @@ -1093,6 +1094,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( atLoc, nameId, nameLoc, categoryId, categoryLoc); ObjCImpDecl = ImplCatType; + PendingObjCImpDecl.push_back(ObjCImpDecl); return DeclPtrTy(); } // We have a class implementation @@ -1115,7 +1117,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); ObjCImpDecl = ImplClsType; - + PendingObjCImpDecl.push_back(ObjCImpDecl); + return DeclPtrTy(); } @@ -1127,12 +1130,21 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { if (ObjCImpDecl) { Actions.ActOnAtEnd(atLoc, ObjCImpDecl); ObjCImpDecl = DeclPtrTy(); + PendingObjCImpDecl.pop_back(); } else Diag(atLoc, diag::warn_expected_implementation); // missing @implementation return Result; } +Parser::DeclGroupPtrTy Parser::RetreivePendingObjCImpDecl() { + if (PendingObjCImpDecl.empty()) + return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); + DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); + Actions.ActOnAtEnd(SourceLocation(), ImpDecl); + return Actions.ConvertDeclToDeclGroup(ImpDecl); +} + /// compatibility-alias-decl: /// @compatibility_alias alias-name class-name ';' /// diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 9afc8100c7..18ab092102 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -71,6 +71,9 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, if (ADecl) Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); }; + // Check for any pending objective-c implementation decl. + while (ADecl = P.RetreivePendingObjCImpDecl()) + Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); // process any TopLevelDecls generated by #pragma weak for (llvm::SmallVector<Decl*,2>::iterator diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index e4482804dd..d1b40bed0f 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1559,12 +1559,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, // should be true. if (!ClassDecl) return; - + bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); + if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) { + AtEndLoc = ClassDecl->getLocation(); + Diag(AtEndLoc, diag::warn_missing_atend); + } + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m index 1cf8ae8b1e..481a94055f 100644 --- a/test/Analysis/NSString.m +++ b/test/Analysis/NSString.m @@ -371,5 +371,4 @@ void test_synchronized(id x) { NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}} } } - - +@end diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m index 765cc7e486..53a6b5257a 100644 --- a/test/Analysis/PR3991.m +++ b/test/Analysis/PR3991.m @@ -42,7 +42,15 @@ typedef struct _NSZone NSZone; - (unsigned int)currentPathComponentIndex; - (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex; - (NSURL *)folderFeedURL; -@end @implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { +@end + +@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { // expected-warning {{incomplete implementation}} \ +// expected-warning {{method definition for 'entries' not found}} \ +// expected-warning {{method definition for 'feedDocList' not found}} \ +// expected-warning {{method definition for 'directoryPathComponents' not found}} \ +// expected-warning {{method definition for 'currentPathComponentIndex' not found}} \ +// expected-warning {{method definition for 'setCurrentPathComponentIndex:' not found}} \ +// expected-warning {{method definition for 'folderFeedURL' not found}} return 0; } @@ -66,3 +74,4 @@ typedef struct _NSZone NSZone; } } } +@end diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 3004afc9b9..d2eef0d7fd 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -749,3 +749,4 @@ void test_undefined_array_subscript() { int i, a[10]; int *p = &a[i]; // expected-warning{{Array subscript is undefined}} } +@end diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m index 5d77414921..60161b1b08 100644 --- a/test/Analysis/pr4209.m +++ b/test/Analysis/pr4209.m @@ -49,17 +49,20 @@ CMProfileLocation; GSEbayCategory *rootCategory; } - (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; --(NSString*) categoryID; +-(NSString*) categoryID; @end @interface GSEbayCategory : NSObject <NSCoding> { } - (int) categoryID; - (GSEbayCategory *) parent; - (GSEbayCategory*) subcategoryWithID:(int) inID; -@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { +@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}} \ +// expected-warning {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}} \ +// expected-warning {{method definition for 'categoryID' not found}} return 0; } - (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories { - GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; + GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; + if (rootCategory != category) { GSEbayCategory *parent = category; while ((((void*)0) != (parent = [parent parent])) && ([parent categoryID] != 0)) { @@ -69,3 +72,4 @@ CMProfileLocation; } } } +@end diff --git a/test/Analysis/region-1.m b/test/Analysis/region-1.m index 2ac1a9b78d..6a8ae49bba 100644 --- a/test/Analysis/region-1.m +++ b/test/Analysis/region-1.m @@ -89,3 +89,4 @@ Dos_CharacterRangeType = 0, Dos_LineRangeType = 1 } symbol = [HancodeFett symbolFromClass:(JabaSCClass *) selectedClassifier]; } } +@end diff --git a/test/CodeGenObjC/missing-atend-metadata.m b/test/CodeGenObjC/missing-atend-metadata.m new file mode 100644 index 0000000000..664b6f0b16 --- /dev/null +++ b/test/CodeGenObjC/missing-atend-metadata.m @@ -0,0 +1,24 @@ +// RUN: clang-cc -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck %s + +@interface I0 +@end + +@implementation I0 // expected-warning {{'@end' is missing in implementation context}} +- meth { return 0; } + +@interface I1 : I0 +@end + +@implementation I1 // expected-warning {{'@end' is missing in implementation context}} +-(void) im0 { self = [super init]; } + +@interface I2 : I0 +- I2meth; +@end + +@implementation I2 // expected-warning {{'@end' is missing in implementation context}} +- I2meth { return 0; } + +@implementation I2(CAT) // expected-warning {{'@end' is missing in implementation context}} + +// CHECK: @"\01L_OBJC_CLASS_I1" = internal global diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m index 86845c0358..22bec504a5 100644 --- a/test/SemaObjC/compare-qualified-id.m +++ b/test/SemaObjC/compare-qualified-id.m @@ -23,11 +23,12 @@ extern NSString * const NSTaskDidTerminateNotification; - (NSString *)evaluateAsStringInContext:(XCPropertyExpansionContext *)context withNestingState:(const void *)state; @end -@implementation XCPropertyExpansionContext +@implementation XCPropertyExpansionContext // expected-warning {{method definition for 'copyWithZone:' not found}} \ + // expected-warning {{incomplete implementation}} - (NSString *)expandedValueForProperty:(NSString *)property { id <XCPropertyValues> cachedValueNode = [_propNamesToPropValuesCache objectForKey:property]; // expected-warning {{method '-objectForKey:' not found (return type defaults to 'id')}} if (cachedValueNode == ((void *)0)) { } NSString * expandedValue = [cachedValueNode evaluateAsStringInContext:self withNestingState:((void *)0)]; return expandedValue; } - +@end diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m index 7fd07d2ede..e81bcdf7b7 100644 --- a/test/SemaObjC/method-arg-decay.m +++ b/test/SemaObjC/method-arg-decay.m @@ -72,7 +72,9 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos } - (PBXModule *) moduleForTab:(NSTabViewItem *)item; @end -@implementation XCPerspectiveModule +@implementation XCPerspectiveModule // expected-warning {{method definition for 'moduleForTab:' not found}} \ + // expected-warning {{method definition for 'performAction:withSelection:' not found}} \ + // expected-warning {{incomplete implementation}} + (void) openForProjectDocument:(PBXProjectDocument *)projectDocument { } - (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data { @@ -94,3 +96,4 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos prompts++; return (BOOL)0; } +@end |