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();
|
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) {
|
protected void adjustLength(IASTNode n, IASTNode endNode) {
|
||||||
final int endOffset= calculateEndOffset(endNode);
|
final int endOffset= calculateEndOffset(endNode);
|
||||||
final ASTNode node = (ASTNode) n;
|
final ASTNode node = (ASTNode) n;
|
||||||
|
@ -505,7 +513,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
protected IASTProblemDeclaration skipProblemDeclaration(int offset) {
|
protected IASTProblemDeclaration skipProblemDeclaration(int offset) {
|
||||||
failParse();
|
failParse();
|
||||||
declarationMark= null;
|
declarationMark= null;
|
||||||
int endOffset = skipToSemiOrClosingBrace(offset);
|
int endOffset = skipToSemiOrClosingBrace(offset, false);
|
||||||
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
|
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
|
||||||
return createProblemDeclaration(problem);
|
return createProblemDeclaration(problem);
|
||||||
}
|
}
|
||||||
|
@ -513,12 +521,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
protected IASTProblemStatement skipProblemStatement(int offset) {
|
protected IASTProblemStatement skipProblemStatement(int offset) {
|
||||||
failParse();
|
failParse();
|
||||||
declarationMark= null;
|
declarationMark= null;
|
||||||
int endOffset = skipToSemiOrClosingBrace(offset);
|
int endOffset = skipToSemiOrClosingBrace(offset, false);
|
||||||
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
|
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
|
||||||
return createProblemStatement(problem);
|
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();
|
failParse();
|
||||||
declarationMark= null;
|
declarationMark= null;
|
||||||
int depth= 0;
|
int depth= 0;
|
||||||
|
@ -541,9 +555,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
break;
|
break;
|
||||||
case IToken.tRBRACE:
|
case IToken.tRBRACE:
|
||||||
if (--depth <= 0) {
|
if (--depth <= 0) {
|
||||||
if (depth == 0 || offset == endOffset) {
|
if (depth == 0 || offset == endOffset || eatBrace) {
|
||||||
endOffset= consume().getEndOffset(); // consume closing brace
|
endOffset= consume().getEndOffset(); // consume closing brace
|
||||||
}
|
}
|
||||||
|
if (LTcatchEOF(1) == IToken.tSEMI) {
|
||||||
|
endOffset= consume().getEndOffset();
|
||||||
|
}
|
||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1240,89 +1257,81 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
* @throws BacktrackException request a backtrack
|
* @throws BacktrackException request a backtrack
|
||||||
*/
|
*/
|
||||||
protected IASTEnumerationSpecifier enumSpecifier() throws BacktrackException, EndOfFileException {
|
protected IASTEnumerationSpecifier enumSpecifier() throws BacktrackException, EndOfFileException {
|
||||||
IToken mark = mark();
|
final IToken mark= mark();
|
||||||
IASTName name = null;
|
final int offset= consume().getOffset();
|
||||||
int startOffset = consume().getOffset(); // t_enum
|
|
||||||
if (LT(1) == IToken.tIDENTIFIER) {
|
|
||||||
name = createName(identifier());
|
|
||||||
} else
|
|
||||||
name = createName();
|
|
||||||
if (LT(1) == IToken.tLBRACE) {
|
|
||||||
|
|
||||||
IASTEnumerationSpecifier result = createEnumerationSpecifier();
|
IASTName name;
|
||||||
((ASTNode) result).setOffset(startOffset);
|
if (LT(1) == IToken.tIDENTIFIER) {
|
||||||
|
name= createName(identifier());
|
||||||
|
} else {
|
||||||
|
name= createName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LT(1) != IToken.tLBRACE) {
|
||||||
|
backup(mark);
|
||||||
|
throwBacktrack(mark);
|
||||||
|
}
|
||||||
|
|
||||||
|
final IASTEnumerationSpecifier result= createEnumerationSpecifier();
|
||||||
result.setName(name);
|
result.setName(name);
|
||||||
|
|
||||||
consume(); // IToken.tLBRACE
|
boolean needComma= false;
|
||||||
enumLoop: while (true) {
|
int endOffset= consume().getEndOffset(); // IToken.tLBRACE
|
||||||
|
int problemOffset= endOffset;
|
||||||
switch (LT(1)) {
|
try {
|
||||||
|
loop: while (true) {
|
||||||
|
switch (LTcatchEOF(1)) {
|
||||||
|
case 0: // eof
|
||||||
|
endOffset= eofOffset;
|
||||||
|
break loop;
|
||||||
case IToken.tRBRACE:
|
case IToken.tRBRACE:
|
||||||
|
endOffset= consume().getEndOffset();
|
||||||
|
break loop;
|
||||||
case IToken.tEOC:
|
case IToken.tEOC:
|
||||||
break enumLoop;
|
break loop;
|
||||||
}
|
|
||||||
|
|
||||||
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.tCOMMA:
|
||||||
case IToken.tEOC:
|
if (!needComma) {
|
||||||
consume();
|
problemOffset= LA(1).getOffset();
|
||||||
break;
|
throw backtrack;
|
||||||
default:
|
|
||||||
throwBacktrack(mark.getOffset(), mark.getLength());
|
|
||||||
}
|
}
|
||||||
|
endOffset= consume().getEndOffset();
|
||||||
|
needComma= false;
|
||||||
|
continue loop;
|
||||||
|
case IToken.tIDENTIFIER:
|
||||||
|
case IToken.tCOMPLETION:
|
||||||
|
problemOffset= LA(1).getOffset();
|
||||||
|
if (needComma)
|
||||||
|
throw backtrack;
|
||||||
|
|
||||||
enumerator = createEnumerator();
|
final IASTEnumerator enumerator= createEnumerator();
|
||||||
enumerator.setName(enumeratorName);
|
final IASTName etorName= createName(identifier());
|
||||||
((ASTNode) enumerator).setOffsetAndLength(
|
enumerator.setName(etorName);
|
||||||
((ASTNode) enumeratorName).getOffset(), lastOffset
|
endOffset= calculateEndOffset(etorName);
|
||||||
- ((ASTNode) enumeratorName).getOffset());
|
setRange(enumerator, problemOffset, endOffset);
|
||||||
if (initialValue != null) {
|
|
||||||
enumerator.setValue(initialValue);
|
|
||||||
}
|
|
||||||
result.addEnumerator(enumerator);
|
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;
|
||||||
int lastOffset = consume().getEndOffset();
|
continue loop;
|
||||||
((ASTNode) result).setLength(lastOffset - startOffset);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
// enumSpecifierAbort
|
|
||||||
backup(mark);
|
|
||||||
throwBacktrack(mark.getOffset(), mark.getLength());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract IASTStatement statement() throws EndOfFileException, BacktrackException;
|
protected abstract IASTStatement statement() throws EndOfFileException, BacktrackException;
|
||||||
|
|
||||||
|
|
|
@ -417,6 +417,15 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
dtor= e.declarator;
|
dtor= e.declarator;
|
||||||
}
|
}
|
||||||
backup( e.currToken );
|
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};
|
IASTDeclarator[] declarators= {dtor};
|
||||||
|
@ -989,6 +998,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
IToken identifier= null;
|
IToken identifier= null;
|
||||||
IASTDeclSpecifier result= null;
|
IASTDeclSpecifier result= null;
|
||||||
IASTExpression typeofExpression= null;
|
IASTExpression typeofExpression= null;
|
||||||
|
IASTProblem problem= null;
|
||||||
|
|
||||||
boolean encounteredRawType= false;
|
boolean encounteredRawType= false;
|
||||||
boolean encounteredTypename= false;
|
boolean encounteredTypename= false;
|
||||||
|
@ -1174,9 +1184,14 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
try {
|
try {
|
||||||
result= enumSpecifier();
|
result= enumSpecifier();
|
||||||
} catch (BacktrackException bt) {
|
} catch (BacktrackException bt) {
|
||||||
// this is an elaborated class specifier
|
if (bt.getNodeBeforeProblem() instanceof IASTDeclSpecifier) {
|
||||||
|
result= (IASTDeclSpecifier) bt.getNodeBeforeProblem();
|
||||||
|
problem = bt.getProblem();
|
||||||
|
break declSpecifiers;
|
||||||
|
} else {
|
||||||
result= elaboratedTypeSpecifier();
|
result= elaboratedTypeSpecifier();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
endOffset= calculateEndOffset(result);
|
endOffset= calculateEndOffset(result);
|
||||||
encounteredTypename= true;
|
encounteredTypename= true;
|
||||||
break;
|
break;
|
||||||
|
@ -1240,6 +1255,9 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
|
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
|
||||||
|
if (problem != null)
|
||||||
|
throwBacktrack(problem, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2284,6 +2284,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
declSpec= (ICPPASTDeclSpecifier) e.declSpec;
|
declSpec= (ICPPASTDeclSpecifier) e.declSpec;
|
||||||
dtor= e.declarator;
|
dtor= e.declarator;
|
||||||
backup(e.currToken);
|
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};
|
IASTDeclarator[] declarators= {dtor};
|
||||||
|
@ -2570,6 +2579,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
ITokenDuple identifier= null;
|
ITokenDuple identifier= null;
|
||||||
ICPPASTDeclSpecifier result= null;
|
ICPPASTDeclSpecifier result= null;
|
||||||
IASTExpression typeofExpression= null;
|
IASTExpression typeofExpression= null;
|
||||||
|
IASTProblem problem= null;
|
||||||
|
|
||||||
boolean isTypename = false;
|
boolean isTypename = false;
|
||||||
boolean encounteredRawType= false;
|
boolean encounteredRawType= false;
|
||||||
|
@ -2779,8 +2789,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
try {
|
try {
|
||||||
result= (ICPPASTDeclSpecifier) enumSpecifier();
|
result= (ICPPASTDeclSpecifier) enumSpecifier();
|
||||||
} catch (BacktrackException bt) {
|
} catch (BacktrackException bt) {
|
||||||
|
if (bt.getNodeBeforeProblem() instanceof ICPPASTDeclSpecifier) {
|
||||||
|
result= (ICPPASTDeclSpecifier) bt.getNodeBeforeProblem();
|
||||||
|
problem= bt.getProblem();
|
||||||
|
break declSpecifiers;
|
||||||
|
} else {
|
||||||
result= elaboratedTypeSpecifier();
|
result= elaboratedTypeSpecifier();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
endOffset= calculateEndOffset(result);
|
endOffset= calculateEndOffset(result);
|
||||||
encounteredTypename= true;
|
encounteredTypename= true;
|
||||||
break;
|
break;
|
||||||
|
@ -2843,6 +2859,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
|
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
|
||||||
|
if (problem != null) {
|
||||||
|
throwBacktrack(problem, result);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue