diff options
author | Richard Trieu <rtrieu@google.com> | 2011-04-21 21:44:26 +0000 |
---|---|---|
committer | Richard Trieu <rtrieu@google.com> | 2011-04-21 21:44:26 +0000 |
commit | bb9b80c308d7d3f758886243c7145404a50c66cf (patch) | |
tree | a0f409d3a3e384dabdd86880871ca16a2b229b96 /lib/Parse/ParseStmt.cpp | |
parent | 723b1782460bc448d9d865e9b828c09d26a50964 (diff) |
Add a fixit suggest for missing case keywords inside a switch scope. For instance, in the following code, 'case ' will be suggested before the '1:'
switch (x) {
1: return 0;
default: return 1;
}
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129943 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseStmt.cpp')
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index d70a745314..aaf79acf4f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -121,6 +121,9 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { return StmtError(); } + // If a case keyword is missing, this is where it should be inserted. + Token OldToken = Tok; + // FIXME: Use the attributes // expression[opt] ';' ExprResult Expr(ParseExpression()); @@ -133,6 +136,18 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { ConsumeToken(); return StmtError(); } + + if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && + Actions.CheckCaseExpression(Expr.get())) { + // If a constant expression is followed by a colon inside a switch block, + // suggest a missing case keywork. + Diag(OldToken, diag::err_expected_case_before_expression) + << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); + + // Recover parsing as a case statement. + return ParseCaseStatement(attrs, /*MissingCase=*/true, Expr); + } + // Otherwise, eat the semicolon. ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); @@ -251,8 +266,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { - assert(Tok.is(tok::kw_case) && "Not a case stmt!"); +StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, + ExprResult Expr) { + assert(MissingCase || Tok.is(tok::kw_case) && "Not a case stmt!"); // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively @@ -280,7 +296,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { // While we have case statements, eat and stack them. do { - SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. + SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() : + ConsumeToken(); // eat the 'case'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(getCurScope()); @@ -292,7 +309,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { /// expression. ColonProtectionRAIIObject ColonProtection(*this); - ExprResult LHS(ParseConstantExpression()); + ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); + MissingCase = false; if (LHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); @@ -775,7 +793,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // - unsigned ScopeFlags = Scope::BreakScope; + unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope; if (C99orCXX) ScopeFlags |= Scope::DeclScope | Scope::ControlScope; ParseScope SwitchScope(this, ScopeFlags); |