mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-08 10:16:03 +02:00
Error recovery within enumeration, bug 72685.
This commit is contained in:
parent
bfa93d84d0
commit
d95322ff16
4 changed files with 163 additions and 88 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,6 +238,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
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);
|
||||
final ASTNode node = (ASTNode) n;
|
||||
|
@ -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;
|
||||
|
|
|
@ -417,6 +417,15 @@ 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};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue