From d95322ff161b3869de3cc42474783e3a80424e71 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Mon, 14 Jul 2008 10:45:58 +0000 Subject: [PATCH] Error recovery within enumeration, bug 72685. --- .../tests/ast2/FaultToleranceTests.java | 29 +++ .../parser/AbstractGNUSourceCodeParser.java | 177 +++++++++--------- .../core/dom/parser/c/GNUCSourceParser.java | 24 ++- .../dom/parser/cpp/GNUCPPSourceParser.java | 21 ++- 4 files changed, 163 insertions(+), 88 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java index 232ae4993e7..2359ec1742e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java @@ -213,4 +213,33 @@ public class FaultToleranceTests extends AST2BaseTest { } } } + + // enum _T { I J, K }; // missing comma + // int i; + public void testEnumProblem() throws Exception { + final String comment= getAboveComment(); + for (ParserLanguage lang : ParserLanguage.values()) { + IASTTranslationUnit tu= parse(comment, lang, false, false); + IASTSimpleDeclaration e= getDeclaration(tu, 0); + IASTProblemDeclaration p= getDeclaration(tu, 1); + assertEquals("J, K };", p.getRawSignature()); + IASTSimpleDeclaration s= getDeclaration(tu, 2); + assertEquals("int i;", s.getRawSignature()); + } + } + + // class A { + // enum _T { I J, K }; // missing comma + // int i; + // }; + public void testEnumError_Bug72685() throws Exception { + final String comment= getAboveComment(); + IASTTranslationUnit tu= parse(comment, ParserLanguage.CPP, false, false); + IASTCompositeTypeSpecifier ct= getCompositeType(tu, 0); + IASTSimpleDeclaration e= getDeclaration(ct, 0); + IASTProblemDeclaration p= getDeclaration(ct, 1); + assertEquals("J, K };", p.getRawSignature()); + IASTSimpleDeclaration s= getDeclaration(ct, 2); + assertEquals("int i;", s.getRawSignature()); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 0c109eecc83..b5347efa5aa 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -237,6 +237,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { ASTNode node = (ASTNode) n; return node.getOffset() + node.getLength(); } + + protected void setRange(IASTNode n, IASTNode from) { + ((ASTNode) n).setOffsetAndLength((ASTNode) from); + } + + protected void setRange(IASTNode n, int offset, int endOffset) { + ((ASTNode) n).setOffsetAndLength(offset, endOffset-offset); + } protected void adjustLength(IASTNode n, IASTNode endNode) { final int endOffset= calculateEndOffset(endNode); @@ -505,7 +513,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { protected IASTProblemDeclaration skipProblemDeclaration(int offset) { failParse(); declarationMark= null; - int endOffset = skipToSemiOrClosingBrace(offset); + int endOffset = skipToSemiOrClosingBrace(offset, false); IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset); return createProblemDeclaration(problem); } @@ -513,12 +521,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { protected IASTProblemStatement skipProblemStatement(int offset) { failParse(); declarationMark= null; - int endOffset = skipToSemiOrClosingBrace(offset); + int endOffset = skipToSemiOrClosingBrace(offset, false); IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset); return createProblemStatement(problem); } - private int skipToSemiOrClosingBrace(int offset) { + private IASTProblem skipProblemEnumerator(int offset) { + failParse(); + final int endOffset= skipToSemiOrClosingBrace(offset, true); + return createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset); + } + + private int skipToSemiOrClosingBrace(int offset, boolean eatBrace) { failParse(); declarationMark= null; int depth= 0; @@ -541,9 +555,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { break; case IToken.tRBRACE: if (--depth <= 0) { - if (depth == 0 || offset == endOffset) { + if (depth == 0 || offset == endOffset || eatBrace) { endOffset= consume().getEndOffset(); // consume closing brace } + if (LTcatchEOF(1) == IToken.tSEMI) { + endOffset= consume().getEndOffset(); + } break loop; } break; @@ -1240,88 +1257,80 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { * @throws BacktrackException request a backtrack */ protected IASTEnumerationSpecifier enumSpecifier() throws BacktrackException, EndOfFileException { - IToken mark = mark(); - IASTName name = null; - int startOffset = consume().getOffset(); // t_enum + final IToken mark= mark(); + final int offset= consume().getOffset(); + + IASTName name; if (LT(1) == IToken.tIDENTIFIER) { - name = createName(identifier()); - } else - name = createName(); - if (LT(1) == IToken.tLBRACE) { - - IASTEnumerationSpecifier result = createEnumerationSpecifier(); - ((ASTNode) result).setOffset(startOffset); - result.setName(name); - - consume(); // IToken.tLBRACE - enumLoop: while (true) { - - switch (LT(1)) { - case IToken.tRBRACE: - case IToken.tEOC: - break enumLoop; - } - - IASTName enumeratorName = null; - - int lastOffset = 0; - if (LT(1) == IToken.tIDENTIFIER) { - enumeratorName = createName(identifier()); - lastOffset = calculateEndOffset(enumeratorName); - } else { - IToken la = LA(1); - throwBacktrack(la.getOffset(), la.getLength()); - return null; // line is never reached, hint for the parser - } - IASTExpression initialValue = null; - if (LT(1) == IToken.tASSIGN) { - consume(); - initialValue = constantExpression(); - lastOffset = calculateEndOffset(initialValue); - } - IASTEnumerationSpecifier.IASTEnumerator enumerator = null; - if (LT(1) == IToken.tRBRACE) { - enumerator = createEnumerator(); - enumerator.setName(enumeratorName); - ((ASTNode) enumerator).setOffsetAndLength( - ((ASTNode) enumeratorName).getOffset(), lastOffset - - ((ASTNode) enumeratorName).getOffset()); - if (initialValue != null) { - enumerator.setValue(initialValue); - } - result.addEnumerator(enumerator); - - break; - } - - switch (LT(1)) { - case IToken.tCOMMA: - case IToken.tEOC: - consume(); - break; - default: - throwBacktrack(mark.getOffset(), mark.getLength()); - } - - enumerator = createEnumerator(); - enumerator.setName(enumeratorName); - ((ASTNode) enumerator).setOffsetAndLength( - ((ASTNode) enumeratorName).getOffset(), lastOffset - - ((ASTNode) enumeratorName).getOffset()); - if (initialValue != null) { - enumerator.setValue(initialValue); - } - result.addEnumerator(enumerator); - } - - int lastOffset = consume().getEndOffset(); - ((ASTNode) result).setLength(lastOffset - startOffset); - return result; + name= createName(identifier()); + } else { + name= createName(); } - // enumSpecifierAbort - backup(mark); - throwBacktrack(mark.getOffset(), mark.getLength()); - return null; + + if (LT(1) != IToken.tLBRACE) { + backup(mark); + throwBacktrack(mark); + } + + final IASTEnumerationSpecifier result= createEnumerationSpecifier(); + result.setName(name); + + boolean needComma= false; + int endOffset= consume().getEndOffset(); // IToken.tLBRACE + int problemOffset= endOffset; + try { + loop: while (true) { + switch (LTcatchEOF(1)) { + case 0: // eof + endOffset= eofOffset; + break loop; + case IToken.tRBRACE: + endOffset= consume().getEndOffset(); + break loop; + case IToken.tEOC: + break loop; + case IToken.tCOMMA: + if (!needComma) { + problemOffset= LA(1).getOffset(); + throw backtrack; + } + endOffset= consume().getEndOffset(); + needComma= false; + continue loop; + case IToken.tIDENTIFIER: + case IToken.tCOMPLETION: + problemOffset= LA(1).getOffset(); + if (needComma) + throw backtrack; + + final IASTEnumerator enumerator= createEnumerator(); + final IASTName etorName= createName(identifier()); + enumerator.setName(etorName); + endOffset= calculateEndOffset(etorName); + setRange(enumerator, problemOffset, endOffset); + result.addEnumerator(enumerator); + if (LTcatchEOF(1) == IToken.tASSIGN) { + problemOffset= consume().getOffset(); + final IASTExpression value= constantExpression(); + enumerator.setValue(value); + adjustLength(enumerator, value); + endOffset= calculateEndOffset(value); + } + needComma= true; + continue loop; + default: + problemOffset= LA(1).getOffset(); + throw backtrack; + } + } + } catch (EndOfFileException eof) { + throwBacktrack(createProblem(IProblem.SYNTAX_ERROR, problemOffset, eofOffset-problemOffset), result); + } catch (BacktrackException bt) { + IASTProblem problem= skipProblemEnumerator(problemOffset); + throwBacktrack(problem, result); + } + setRange(result, offset, endOffset); + return result; } protected abstract IASTStatement statement() throws EndOfFileException, BacktrackException; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index f8659bd6e24..bfbe066a803 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -417,8 +417,17 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { dtor= e.declarator; } backup( e.currToken ); + } catch (BacktrackException e) { + IASTNode node= e.getNodeBeforeProblem(); + if (node instanceof IASTDeclSpecifier) { + IASTSimpleDeclaration d= createSimpleDeclaration(); + d.setDeclSpecifier((IASTDeclSpecifier) node); + setRange(d, node); + throwBacktrack(e.getProblem(), d); + } + throw e; } - + IASTDeclarator[] declarators= {dtor}; while (LTcatchEOF(1) == IToken.tCOMMA) { consume(); @@ -989,6 +998,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { IToken identifier= null; IASTDeclSpecifier result= null; IASTExpression typeofExpression= null; + IASTProblem problem= null; boolean encounteredRawType= false; boolean encounteredTypename= false; @@ -1174,8 +1184,13 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { try { result= enumSpecifier(); } catch (BacktrackException bt) { - // this is an elaborated class specifier - result= elaboratedTypeSpecifier(); + if (bt.getNodeBeforeProblem() instanceof IASTDeclSpecifier) { + result= (IASTDeclSpecifier) bt.getNodeBeforeProblem(); + problem = bt.getProblem(); + break declSpecifiers; + } else { + result= elaboratedTypeSpecifier(); + } } endOffset= calculateEndOffset(result); encounteredTypename= true; @@ -1240,6 +1255,9 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { } } ((ASTNode) result).setOffsetAndLength(offset, endOffset - offset); + if (problem != null) + throwBacktrack(problem, result); + return result; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 59c188468f8..0d5d78103fc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -2284,6 +2284,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { declSpec= (ICPPASTDeclSpecifier) e.declSpec; dtor= e.declarator; backup(e.currToken); + } catch (BacktrackException e) { + IASTNode node= e.getNodeBeforeProblem(); + if (node instanceof ICPPASTDeclSpecifier && validWithoutDtor(declOption, (ICPPASTDeclSpecifier) node)) { + IASTSimpleDeclaration d= createSimpleDeclaration(); + d.setDeclSpecifier((IASTDeclSpecifier) node); + setRange(d, node); + throwBacktrack(e.getProblem(), d); + } + throw e; } IASTDeclarator[] declarators= {dtor}; @@ -2570,6 +2579,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { ITokenDuple identifier= null; ICPPASTDeclSpecifier result= null; IASTExpression typeofExpression= null; + IASTProblem problem= null; boolean isTypename = false; boolean encounteredRawType= false; @@ -2779,7 +2789,13 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { try { result= (ICPPASTDeclSpecifier) enumSpecifier(); } catch (BacktrackException bt) { - result= elaboratedTypeSpecifier(); + if (bt.getNodeBeforeProblem() instanceof ICPPASTDeclSpecifier) { + result= (ICPPASTDeclSpecifier) bt.getNodeBeforeProblem(); + problem= bt.getProblem(); + break declSpecifiers; + } else { + result= elaboratedTypeSpecifier(); + } } endOffset= calculateEndOffset(result); encounteredTypename= true; @@ -2843,6 +2859,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } } ((ASTNode) result).setOffsetAndLength(offset, endOffset - offset); + if (problem != null) { + throwBacktrack(problem, result); + } return result; }