forked from OSchip/llvm-project
objective-c - This patch buffers method implementations
and does the Sema on their body after the entire class/category @implementation is seen. This change allows messaging of forward private methods, as well as, access to synthesized ivars of properties with foward synthesize declarations; among others. In effect, this patch removes several restrictions placed on objective-c due to in-place semantics processing of methods. This is part of // rdar://8843851. llvm-svn: 138865
This commit is contained in:
parent
cdef71f4f3
commit
bd0642fede
|
@ -1022,6 +1022,7 @@ private:
|
|||
void ParseLexedMethodDef(LexedMethod &LM);
|
||||
void ParseLexedMemberInitializers(ParsingClass &Class);
|
||||
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
|
||||
Decl *ParseLexedObjCMethodDefs(LexedMethod &LM);
|
||||
bool ConsumeAndStoreUntil(tok::TokenKind T1,
|
||||
CachedTokens &Toks,
|
||||
bool StopAtSemi = true,
|
||||
|
@ -1080,9 +1081,11 @@ private:
|
|||
|
||||
Decl *ObjCImpDecl;
|
||||
SmallVector<Decl *, 4> PendingObjCImpDecl;
|
||||
typedef SmallVector<LexedMethod*, 2> LateParsedObjCMethodContainer;
|
||||
LateParsedObjCMethodContainer LateParsedObjCMethods;
|
||||
|
||||
Decl *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
|
||||
Decl *ParseObjCAtEndDeclaration(SourceRange atEnd);
|
||||
DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
|
||||
Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
|
||||
Decl *ParseObjCPropertySynthesize(SourceLocation atLoc);
|
||||
Decl *ParseObjCPropertyDynamic(SourceLocation atLoc);
|
||||
|
|
|
@ -1958,6 +1958,10 @@ public:
|
|||
AddMethodToGlobalPool(Method, impl, /*instance*/false);
|
||||
}
|
||||
|
||||
/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
|
||||
/// pool.
|
||||
void AddAnyMethodToGlobalPool(Decl *D);
|
||||
|
||||
/// LookupInstanceMethodInGlobalPool - Returns the method and warns if
|
||||
/// there are multiple signatures.
|
||||
ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R,
|
||||
|
|
|
@ -56,7 +56,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
|
|||
SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc);
|
||||
break;
|
||||
case tok::objc_end:
|
||||
SingleDecl = ParseObjCAtEndDeclaration(AtLoc);
|
||||
return ParseObjCAtEndDeclaration(AtLoc);
|
||||
break;
|
||||
case tok::objc_compatibility_alias:
|
||||
SingleDecl = ParseObjCAtAliasDeclaration(AtLoc);
|
||||
|
@ -1395,11 +1395,19 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
|
|||
return 0;
|
||||
}
|
||||
|
||||
Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
|
||||
Parser::DeclGroupPtrTy
|
||||
Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
|
||||
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
|
||||
"ParseObjCAtEndDeclaration(): Expected @end");
|
||||
Decl *Result = ObjCImpDecl;
|
||||
ConsumeToken(); // the "end" identifier
|
||||
SmallVector<Decl *, 8> DeclsInGroup;
|
||||
|
||||
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) {
|
||||
Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]);
|
||||
DeclsInGroup.push_back(D);
|
||||
}
|
||||
LateParsedObjCMethods.clear();
|
||||
DeclsInGroup.push_back(ObjCImpDecl);
|
||||
if (ObjCImpDecl) {
|
||||
Actions.ActOnAtEnd(getCurScope(), atEnd);
|
||||
ObjCImpDecl = 0;
|
||||
|
@ -1409,7 +1417,8 @@ Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
|
|||
// missing @implementation
|
||||
Diag(atEnd.getBegin(), diag::err_expected_implementation);
|
||||
}
|
||||
return Result;
|
||||
return Actions.BuildDeclaratorGroup(
|
||||
DeclsInGroup.data(), DeclsInGroup.size(), false);
|
||||
}
|
||||
|
||||
Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
|
||||
|
@ -1772,35 +1781,19 @@ Decl *Parser::ParseObjCMethodDefinition() {
|
|||
if (Tok.isNot(tok::l_brace))
|
||||
return 0;
|
||||
}
|
||||
SourceLocation BraceLoc = Tok.getLocation();
|
||||
|
||||
// Enter a scope for the method body.
|
||||
ParseScope BodyScope(this,
|
||||
Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
|
||||
|
||||
// Tell the actions module that we have entered a method definition with the
|
||||
// specified Declarator for the method.
|
||||
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
|
||||
|
||||
if (PP.isCodeCompletionEnabled()) {
|
||||
if (trySkippingFunctionBodyForCodeCompletion()) {
|
||||
BodyScope.Exit();
|
||||
return Actions.ActOnFinishFunctionBody(MDecl, 0);
|
||||
}
|
||||
}
|
||||
|
||||
StmtResult FnBody(ParseCompoundStatementBody());
|
||||
|
||||
// If the function body could not be parsed, make a bogus compoundstmt.
|
||||
if (FnBody.isInvalid())
|
||||
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
|
||||
MultiStmtArg(Actions), false);
|
||||
|
||||
// Leave the function body scope.
|
||||
BodyScope.Exit();
|
||||
|
||||
// TODO: Pass argument information.
|
||||
Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
|
||||
// Allow the rest of sema to find private method decl implementations.
|
||||
if (MDecl)
|
||||
Actions.AddAnyMethodToGlobalPool(MDecl);
|
||||
|
||||
// Consume the tokens and store them for later parsing.
|
||||
LexedMethod* LM = new LexedMethod(this, MDecl);
|
||||
LateParsedObjCMethods.push_back(LM);
|
||||
CachedTokens &Toks = LM->Toks;
|
||||
// Begin by storing the '{' token.
|
||||
Toks.push_back(Tok);
|
||||
ConsumeBrace();
|
||||
// Consume everything up to (and including) the matching right brace.
|
||||
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
||||
return MDecl;
|
||||
}
|
||||
|
||||
|
@ -2432,3 +2425,46 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
|||
return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
|
||||
LParenLoc, RParenLoc));
|
||||
}
|
||||
|
||||
Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
|
||||
|
||||
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
|
||||
// Append the current token at the end of the new token stream so that it
|
||||
// doesn't get lost.
|
||||
LM.Toks.push_back(Tok);
|
||||
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
|
||||
|
||||
// MDecl might be null due to error in method prototype, etc.
|
||||
Decl *MDecl = LM.D;
|
||||
// Consume the previously pushed token.
|
||||
ConsumeAnyToken();
|
||||
|
||||
assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'");
|
||||
SourceLocation BraceLoc = Tok.getLocation();
|
||||
// Enter a scope for the method body.
|
||||
ParseScope BodyScope(this,
|
||||
Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
|
||||
|
||||
// Tell the actions module that we have entered a method definition with the
|
||||
// specified Declarator for the method.
|
||||
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
|
||||
|
||||
if (PP.isCodeCompletionEnabled()) {
|
||||
if (trySkippingFunctionBodyForCodeCompletion()) {
|
||||
BodyScope.Exit();
|
||||
return Actions.ActOnFinishFunctionBody(MDecl, 0);
|
||||
}
|
||||
}
|
||||
|
||||
StmtResult FnBody(ParseCompoundStatementBody());
|
||||
|
||||
// If the function body could not be parsed, make a bogus compoundstmt.
|
||||
if (FnBody.isInvalid())
|
||||
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
|
||||
MultiStmtArg(Actions), false);
|
||||
|
||||
// Leave the function body scope.
|
||||
BodyScope.Exit();
|
||||
|
||||
return Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
|
||||
}
|
||||
|
|
|
@ -214,6 +214,20 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S,
|
|||
}
|
||||
}
|
||||
|
||||
/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
|
||||
/// pool.
|
||||
void Sema::AddAnyMethodToGlobalPool(Decl *D) {
|
||||
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
|
||||
|
||||
// If we don't have a valid method decl, simply return.
|
||||
if (!MDecl)
|
||||
return;
|
||||
if (MDecl->isInstanceMethod())
|
||||
AddInstanceMethodToGlobalPool(MDecl, true);
|
||||
else
|
||||
AddFactoryMethodToGlobalPool(MDecl, true);
|
||||
}
|
||||
|
||||
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
|
||||
/// and user declared, in the method definition's AST.
|
||||
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
|
||||
|
@ -224,12 +238,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
|
|||
if (!MDecl)
|
||||
return;
|
||||
|
||||
// Allow the rest of sema to find private method decl implementations.
|
||||
if (MDecl->isInstanceMethod())
|
||||
AddInstanceMethodToGlobalPool(MDecl, true);
|
||||
else
|
||||
AddFactoryMethodToGlobalPool(MDecl, true);
|
||||
|
||||
// Allow all of Sema to see that we are entering a method definition.
|
||||
PushDeclContext(FnBodyScope, MDecl);
|
||||
PushFunctionScope();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
|
||||
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
|
||||
// RUN: diff %t %s.result
|
||||
// XFAIL: *
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* The run lines are below, because this test is line- and
|
||||
column-number sensitive. */
|
||||
// XFAIL: *
|
||||
@interface MyClass { int ivar; }
|
||||
- (int)myMethod:(int)arg;
|
||||
@end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// This test is line- and column-sensitive, so test commands are at the bottom.
|
||||
// XFAIL: *
|
||||
@protocol P
|
||||
- (int)method:(id)param1;
|
||||
@end
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// XFAIL: *
|
||||
typedef signed char BOOL;
|
||||
#define YES ((BOOL)1)
|
||||
#define NO ((BOOL)0)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Note: the run lines follow their respective tests, since line/column
|
||||
// matter in this test.
|
||||
|
||||
// XFAIL: *
|
||||
@interface A
|
||||
+ (id)alloc;
|
||||
+ (id)init;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Note: the run lines follow their respective tests, since line/column
|
||||
// matter in this test.
|
||||
// XFAIL: *
|
||||
#define nil (void*)0
|
||||
@protocol FooTestProtocol
|
||||
+ protocolClassMethod;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* Run lines are at the end, since line/column matter in this test. */
|
||||
|
||||
// XFAIL: *
|
||||
@interface A
|
||||
- (void)method:(int)x;
|
||||
@end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Note: the run lines follow their respective tests, since line/column
|
||||
// matter in this test.
|
||||
// XFAIL: *
|
||||
|
||||
typedef int Bool;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Note: this test is line- and column-sensitive. Test commands are at
|
||||
// the end.
|
||||
// XFAIL: *
|
||||
|
||||
|
||||
@interface A
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
- (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \
|
||||
// expected-error {{missing context for method declaration}}
|
||||
Exit: [nilArgs release]; // expected-error {{use of undeclared identifier}}
|
||||
- (NSDictionary*) _executeScript:(NSString *)source { // expected-error 2 {{expected a type}} \
|
||||
// expected-error {{missing context for method declaration}}
|
||||
Exit: [nilArgs release];
|
||||
}
|
||||
- (NSDictionary *) _setupKernelStandardMode:(NSString *)source { // expected-error 2 {{expected a type}} \
|
||||
expected-error {{missing context for method declaration}} \
|
||||
expected-note{{to match this '{'}}
|
||||
Exit: if(_ciKernel && !success ) { // expected-error {{use of undeclared identifier}} // expected-error 2 {{expected}} expected-note{{to match this '{'}} expected-error{{use of undeclared identifier 'success'}}
|
||||
// expected-error {{missing context for method declaration}}
|
||||
Exit: if(_ciKernel && !success ) {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
- im0 { // expected-note{{to match this '{'}} expected-error{{missing context for method declaration}}
|
||||
- im0 { // expected-error{{missing context for method declaration}}
|
||||
int a; return 0;
|
||||
// expected-error{{expected '}'}}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
@end
|
||||
|
||||
@implementation I1 // expected-error {{'@end' is missing in implementation context}}
|
||||
-(void) im0 { self = [super init]; } // expected-warning {{nstance method '-init' not found }}
|
||||
-(void) im0 { self = [super init]; }
|
||||
|
||||
@interface I2 : I0
|
||||
- I2meth;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -verify %s
|
||||
// rdar://8843851
|
||||
|
||||
int* global;
|
||||
|
||||
@interface I
|
||||
- (void) Meth;
|
||||
@property int prop;
|
||||
@property int prop1;
|
||||
@end
|
||||
|
||||
@implementation I
|
||||
+ (void) _defaultMinSize { };
|
||||
static void _initCommon() {
|
||||
Class graphicClass;
|
||||
[graphicClass _defaultMinSize];
|
||||
}
|
||||
|
||||
- (void) Meth { [self Forw]; } // No warning now
|
||||
- (void) Forw {}
|
||||
- (int) func { return prop; } // compiles - synthesized ivar will be accessible here.
|
||||
- (int)get_g { return global; } // No warning here - synthesized ivar will be accessible here.
|
||||
@synthesize prop;
|
||||
@synthesize prop1=global;
|
||||
@end
|
|
@ -18,7 +18,7 @@ int bar;
|
|||
@end
|
||||
|
||||
@implementation I
|
||||
- (int) Meth { return PROP; } // expected-note 2{{'PROP' declared here}}
|
||||
- (int) Meth { return PROP; }
|
||||
|
||||
@dynamic PROP1;
|
||||
- (int) Meth1 { return PROP1; } // expected-error {{use of undeclared identifier 'PROP1'}}
|
||||
|
@ -32,7 +32,7 @@ int bar;
|
|||
- (int) Meth4 { return PROP4; }
|
||||
@synthesize PROP4=PROP4;
|
||||
|
||||
- (int) Meth5 { return bar; } // expected-error {{use of undeclared identifier 'bar'}}
|
||||
- (int) Meth5 { return bar; }
|
||||
@synthesize bar = _bar;
|
||||
|
||||
- (int) Meth6 { return bar1; }
|
||||
|
@ -45,6 +45,6 @@ int bar;
|
|||
|
||||
@implementation I(r8251648)
|
||||
- (int) Meth1: (int) bar {
|
||||
return bar; // expected-warning {{local declaration of 'bar' hides instance variable}}
|
||||
return bar;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef struct objc_selector *SEL;
|
|||
+ (void) methodD
|
||||
{
|
||||
SEL d = @selector(methodD); /* Ok */
|
||||
SEL e = @selector(methodE); // expected-warning {{undeclared selector 'methodE'}}
|
||||
SEL e = @selector(methodE);
|
||||
}
|
||||
|
||||
- (void) methodE
|
||||
|
|
Loading…
Reference in New Issue