]> granicus.if.org Git - clang/commitdiff
Handle case of missing '@end' in implementation context
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 16 Nov 2009 18:57:01 +0000 (18:57 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 16 Nov 2009 18:57:01 +0000 (18:57 +0000)
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

13 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Parser.h
lib/Parse/ParseObjc.cpp
lib/Sema/ParseAST.cpp
lib/Sema/SemaDeclObjC.cpp
test/Analysis/NSString.m
test/Analysis/PR3991.m
test/Analysis/misc-ps.m
test/Analysis/pr4209.m
test/Analysis/region-1.m
test/CodeGenObjC/missing-atend-metadata.m [new file with mode: 0644]
test/SemaObjC/compare-qualified-id.m
test/SemaObjC/method-arg-decay.m

index e3f23837986cef4cfb56c4df7953fb7551f7cd0f..bd0dec6a8dfcf351860fd8b289e5398a5b59fdbf 100644 (file)
@@ -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<
index 3e75189aea2c3927041a78a3579f87ca6034aa1f..f436a75e290b8573a373b629e3e33e54fe8beec5 100644 (file)
@@ -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);
index 29f3fc0a57661fb0c71c01e3fdcc10ec7bfed338..2ae0c690cad15ed71dbd2dc28d9ec2705db6937e 100644 (file)
@@ -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 ';'
 ///
index 9afc8100c7eb6cb048203d1e6baf67c4126d97d3..18ab092102cb4b039883419f66f2da422a1d9cc3 100644 (file)
@@ -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
index e4482804dd2778f55c5b192871b3f64608e314c4..d1b40bed0fd8ae71f2ef1f97d4dbb6b204c00060 100644 (file)
@@ -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.
index 1cf8ae8b1ef5c5abf24d1f9c3b84aae9a89a9258..481a94055ffd3dee66e7e0a8e94fdfdfb825e08c 100644 (file)
@@ -371,5 +371,4 @@ void test_synchronized(id x) {
     NSString *string = [[NSString stringWithFormat:@"%ld", (long) 100] retain]; // expected-warning {{leak}}
   }
 }
-
-
+@end
index 765cc7e486a86b3ead844b033c27cba5ff7ac8d5..53a6b5257a770187d3b5b1d06a1df79b99779093 100644 (file)
@@ -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
index 3004afc9b98167181d7efe3c63b94151d43e9392..d2eef0d7fdbdba585557f75a0b84dfa07fa515cc 100644 (file)
@@ -749,3 +749,4 @@ void test_undefined_array_subscript() {
   int i, a[10];
   int *p = &a[i]; // expected-warning{{Array subscript is undefined}}
 }
+@end
index 5d77414921e69821619fa099ad024939852fd1fb..60161b1b08a8f9cb6bebc97021da577b3e11916e 100644 (file)
@@ -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
index 2ac1a9b78d2e5d3b66f8d6d88275aa9d5103a1c6..6a8ae49bba4b774b78559f23b40cde8d69a100c6 100644 (file)
@@ -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 (file)
index 0000000..664b6f0
--- /dev/null
@@ -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
index 86845c0358d2f42c42fa54f060c2b0de66bf3ffa..22bec504a558e0664786b6d8421366fac944d7b6 100644 (file)
@@ -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
index 7fd07d2ede3369046cb10d6e5a01e3f2762f48b7..e81bcdf7b75fec5b4feadf55322205b29850f15a 100644 (file)
@@ -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