diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-02-07 16:50:53 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-02-07 16:50:53 +0000 |
commit | 849639d8b548519cc5a00c0c9253f0c0d525060d (patch) | |
tree | a812a80ebb5de2431d3c647299a43dd9efec26cf /lib/Parse/ParseObjc.cpp | |
parent | b534a9ed04b343534e5f277b81d1170de3204164 (diff) |
Make parsing of objc @implementations more robust.
Parsing of @implementations was based on modifying global state from
the parser; the logic for late parsing of methods was spread in multiple places
making it difficult to have a robust error recovery.
-it was difficult to ensure that we don't neglect parsing the lexed methods.
-it was difficult to setup the original objc container context for parsing the lexed methods
after completing ParseObjCAtImplementationDeclaration and returning to top level context.
Enhance parsing of @implementations by centralizing it in Parser::ParseObjCAtImplementationDeclaration().
ParseObjCAtImplementationDeclaration now returns only after an @implementation is fully parsed;
all the data and logic for late parsing of methods is now in one place.
This allows us to provide code-completion for late parsed methods with mis-matched braces.
rdar://10775381
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149987 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseObjc.cpp')
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 187 |
1 files changed, 105 insertions, 82 deletions
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 3f4f4611fd..41dfeddaab 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -52,8 +52,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() { return ParseObjCAtProtocolDeclaration(AtLoc, attrs); } case tok::objc_implementation: - SingleDecl = ParseObjCAtImplementationDeclaration(AtLoc); - break; + return ParseObjCAtImplementationDeclaration(AtLoc); case tok::objc_end: return ParseObjCAtEndDeclaration(AtLoc); case tok::objc_compatibility_alias: @@ -122,15 +121,17 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) if (ock == Sema::OCK_None) return; - Decl *Decl = Actions.ActOnAtEnd(getCurScope(), AtLoc); + Decl *Decl = Actions.getObjCDeclContext(); + if (CurParsedObjCImpl) { + CurParsedObjCImpl->finish(AtLoc); + } else { + 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; } /// @@ -403,7 +404,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, // Code completion within an Objective-C interface. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), - ObjCImpDecl? Sema::PCC_ObjCImplementation + CurParsedObjCImpl? Sema::PCC_ObjCImplementation : Sema::PCC_ObjCInterface); return cutOffParsing(); } @@ -1441,7 +1442,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, /// /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) -Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { +Parser::DeclGroupPtrTy +Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); CheckNestedObjCContexts(AtLoc); @@ -1451,16 +1453,17 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationDecl(getCurScope()); cutOffParsing(); - return 0; + return DeclGroupPtrTy(); } if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. - return 0; + return DeclGroupPtrTy(); } // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); // consume class or category name + Decl *ObjCImpDecl = 0; if (Tok.is(tok::l_paren)) { // we have a category implementation. @@ -1471,7 +1474,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc); cutOffParsing(); - return 0; + return DeclGroupPtrTy(); } if (Tok.is(tok::identifier)) { @@ -1479,45 +1482,59 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { categoryLoc = ConsumeToken(); } else { Diag(Tok, diag::err_expected_ident); // missing category name. - return 0; + return DeclGroupPtrTy(); } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren, false); // don't stop at ';' - return 0; + return DeclGroupPtrTy(); } rparenLoc = ConsumeParen(); - Decl *ImplCatType = Actions.ActOnStartCategoryImplementation( + ObjCImpDecl = Actions.ActOnStartCategoryImplementation( AtLoc, nameId, nameLoc, categoryId, categoryLoc); - ObjCImpDecl = ImplCatType; - PendingObjCImpDecl.push_back(ObjCImpDecl); - return 0; - } - // We have a class implementation - SourceLocation superClassLoc; - IdentifierInfo *superClassId = 0; - if (Tok.is(tok::colon)) { - // We have a super class - ConsumeToken(); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing super class name. - return 0; + } else { + // We have a class implementation + SourceLocation superClassLoc; + IdentifierInfo *superClassId = 0; + if (Tok.is(tok::colon)) { + // We have a super class + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return DeclGroupPtrTy(); + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); // Consume super class name } - superClassId = Tok.getIdentifierInfo(); - superClassLoc = ConsumeToken(); // Consume super class name + ObjCImpDecl = Actions.ActOnStartClassImplementation( + AtLoc, nameId, nameLoc, + superClassId, superClassLoc); + + if (Tok.is(tok::l_brace)) // we have ivars + ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); } - Decl *ImplClsType = Actions.ActOnStartClassImplementation( - AtLoc, nameId, nameLoc, - superClassId, superClassLoc); + assert(ObjCImpDecl); + + SmallVector<Decl *, 8> DeclsInGroup; - if (Tok.is(tok::l_brace)) // we have ivars - ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, AtLoc); + { + ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl); + while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) { + DeclGroupRef DG = DGP.get(); + DeclsInGroup.append(DG.begin(), DG.end()); + } + } + } - ObjCImpDecl = ImplClsType; - PendingObjCImpDecl.push_back(ObjCImpDecl); - return 0; + DeclsInGroup.push_back(ObjCImpDecl); + return Actions.BuildDeclaratorGroup( + DeclsInGroup.data(), DeclsInGroup.size(), false); } Parser::DeclGroupPtrTy @@ -1525,51 +1542,44 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { assert(Tok.isObjCAtKeyword(tok::objc_end) && "ParseObjCAtEndDeclaration(): Expected @end"); ConsumeToken(); // the "end" identifier - SmallVector<Decl *, 8> DeclsInGroup; - Actions.DefaultSynthesizeProperties(getCurScope(), ObjCImpDecl); - for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) { - Decl *D = ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); - if (D) - DeclsInGroup.push_back(D); - } - DeclsInGroup.push_back(ObjCImpDecl); - - if (ObjCImpDecl) { - Actions.ActOnAtEnd(getCurScope(), atEnd); - PendingObjCImpDecl.pop_back(); - } + if (CurParsedObjCImpl) + CurParsedObjCImpl->finish(atEnd); else // missing @implementation Diag(atEnd.getBegin(), diag::err_expected_objc_container); - - clearLateParsedObjCMethods(); - ObjCImpDecl = 0; - return Actions.BuildDeclaratorGroup( - DeclsInGroup.data(), DeclsInGroup.size(), false); + return DeclGroupPtrTy(); } -Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() { - Actions.DiagnoseUseOfUnimplementedSelectors(); - if (PendingObjCImpDecl.empty()) - return Actions.ConvertDeclToDeclGroup(0); +Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { + if (!Finished) { + finish(P.Tok.getLocation()); + if (P.Tok.is(tok::eof)) { + P.Diag(P.Tok, diag::err_objc_missing_end) + << FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n"); + P.Diag(Dcl->getLocStart(), diag::note_objc_container_start) + << Sema::OCK_Implementation; + } + } + P.CurParsedObjCImpl = 0; + assert(LateParsedObjCMethods.empty()); +} - Decl *ImpDecl = PendingObjCImpDecl.pop_back_val(); - 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; +void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { + assert(!Finished); + P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); + for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) + P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]); - return Actions.ConvertDeclToDeclGroup(ImpDecl); -} + P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd); -void Parser::clearLateParsedObjCMethods() { + /// \brief Clear and free the cached objc methods. for (LateParsedObjCMethodContainer::iterator I = LateParsedObjCMethods.begin(), E = LateParsedObjCMethods.end(); I != E; ++I) delete *I; LateParsedObjCMethods.clear(); + + Finished = true; } /// compatibility-alias-decl: @@ -1908,7 +1918,7 @@ Decl *Parser::ParseObjCMethodDefinition() { // parse optional ';' if (Tok.is(tok::semi)) { - if (ObjCImpDecl) { + if (CurParsedObjCImpl) { Diag(Tok, diag::warn_semicolon_before_method_body) << FixItHint::CreateRemoval(Tok.getLocation()); } @@ -1926,19 +1936,32 @@ Decl *Parser::ParseObjCMethodDefinition() { if (Tok.isNot(tok::l_brace)) return 0; } + + if (!MDecl) { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + return 0; + } + // 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); + Actions.AddAnyMethodToGlobalPool(MDecl); + + if (CurParsedObjCImpl) { + // Consume the tokens and store them for later parsing. + LexedMethod* LM = new LexedMethod(this, MDecl); + CurParsedObjCImpl->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); + + } else { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false); + } + return MDecl; } |