diff options
author | Richard Trieu <rtrieu@google.com> | 2011-05-26 20:11:09 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2011-05-26 20:11:09 +0000 |
commit | f858bd817e8d6eac58ae496fa96a2f508fbb286f (patch) | |
tree | 0acecc50ca66e34450d8a67f3d41da82a6c256d3 /lib/Parse/ParseDeclCXX.cpp | |
parent | f13654600b6c567b2f05902cfa2e86b23ddcbd4b (diff) |
Add a fix-it and better error recovery for improperly nested namespaces. This will give a better error message for cases such as "namespace foo::bar::baz {}" and a suggested fix-it of "namespace foo { namespace bar { namespace baz {} } }"
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132138 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 93 |
1 files changed, 86 insertions, 7 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 5087b92d0b..d007a17d13 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context, SourceLocation IdentLoc; IdentifierInfo *Ident = 0; + std::vector<SourceLocation> ExtraIdentLoc; + std::vector<IdentifierInfo*> ExtraIdent; + std::vector<SourceLocation> ExtraNamespaceLoc; Token attrTok; if (Tok.is(tok::identifier)) { Ident = Tok.getIdentifierInfo(); IdentLoc = ConsumeToken(); // eat the identifier. + while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) { + ExtraNamespaceLoc.push_back(ConsumeToken()); + ExtraIdent.push_back(Tok.getIdentifierInfo()); + ExtraIdentLoc.push_back(ConsumeToken()); + } } // Read label attributes, if present. @@ -85,7 +93,12 @@ Decl *Parser::ParseNamespace(unsigned Context, return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } + if (Tok.isNot(tok::l_brace)) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } Diag(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); return 0; @@ -96,11 +109,44 @@ Decl *Parser::ParseNamespace(unsigned Context, if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() || getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() || getCurScope()->getFnParent()) { + if (!ExtraIdent.empty()) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } Diag(LBrace, diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); return 0; } + if (!ExtraIdent.empty()) { + TentativeParsingAction TPA(*this); + SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true); + Token rBraceToken = Tok; + TPA.Revert(); + + if (!rBraceToken.is(tok::r_brace)) { + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back()); + } else { + + std::string NamespaceFix = ""; + for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(), + E = ExtraIdent.end(); I != E; ++I) { + NamespaceFix += " { namespace "; + NamespaceFix += (*I)->getName(); + } + std::string RBraces; + for (int i = 0; i < ExtraIdent.size(); ++i) { + RBraces += "} "; + } + Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon) + << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(), + ExtraIdentLoc.back()), + NamespaceFix) + << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces); + } + } + // If we're still good, complain about inline namespaces in non-C++0x now. if (!getLang().CPlusPlus0x && InlineLoc.isValid()) Diag(InlineLoc, diag::ext_inline_namespace); @@ -115,23 +161,56 @@ Decl *Parser::ParseNamespace(unsigned Context, PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs); - MaybeParseMicrosoftAttributes(attrs); - ParseExternalDeclaration(attrs); - } + SourceLocation RBraceLoc; + // Parse the contents of the namespace. This includes parsing recovery on + // any improperly nested namespaces. + ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0, + InlineLoc, LBrace, attrs, RBraceLoc); // Leave the namespace scope. NamespaceScope.Exit(); - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); DeclEnd = RBraceLoc; return NamespcDecl; } +/// ParseInnerNamespace - Parse the contents of a namespace. +void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, + std::vector<IdentifierInfo*>& Ident, + std::vector<SourceLocation>& NamespaceLoc, + unsigned int index, SourceLocation& InlineLoc, + SourceLocation& LBrace, + ParsedAttributes& attrs, + SourceLocation& RBraceLoc) { + if (index == Ident.size()) { + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX0XAttributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + ParseExternalDeclaration(attrs); + } + RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace); + + return; + } + + // Parse improperly nested namespaces. + ParseScope NamespaceScope(this, Scope::DeclScope); + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(), + NamespaceLoc[index], IdentLoc[index], + Ident[index], LBrace, attrs.getList()); + + ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc, + LBrace, attrs, RBraceLoc); + + NamespaceScope.Exit(); + + Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc); +} + /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// |