1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

Bug 314593: Handling of missing semicolon after statement.

This commit is contained in:
Markus Schorn 2010-06-23 09:24:39 +00:00
parent 7938f9e2c4
commit 2ec6a92a98
6 changed files with 98 additions and 54 deletions

View file

@ -101,15 +101,6 @@ public class AST2SelectionParseTest extends AST2SelectionParseBaseTest {
assertEquals(((IFunction)name.resolveBinding()).getName(), "x"); //$NON-NLS-1$
}
public void testBaseCase_Error() throws Exception
{
String code = "int x() { y( ) }"; //$NON-NLS-1$
int offset1 = code.indexOf( "y( " ); //$NON-NLS-1$
int length = "y".length(); //$NON-NLS-1$
assertNull( parse( code, ParserLanguage.C, offset1, length, false ));
assertNull( parse( code, ParserLanguage.CPP, offset1, length, false ));
}
public void testBaseCase_FunctionDeclaration() throws Exception
{
String code = "int x(); x( );"; //$NON-NLS-1$

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2009 Wind River Systems, Inc. and others.
* Copyright (c) 2008, 2010 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -21,6 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
@ -102,7 +103,25 @@ public class FaultToleranceTests extends AST2BaseTest {
sdecl= getDeclaration(tu, 3);
}
}
// void f() {
// int a= 1
// f()
// }
public void testExpressionWithoutSemi_314593() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTFunctionDefinition fdef= getDeclaration(tu, 0);
IASTStatement stmt= getStatement(fdef, 0);
assertEquals("int a= 1", stmt.getRawSignature());
IASTProblemStatement pstmt= getStatement(fdef, 1);
stmt= getStatement(fdef, 2);
assertEquals("f()", stmt.getRawSignature());
pstmt= getStatement(fdef, 3);
}
}
// struct X {
// int a;
public void testIncompleteCompositeType() throws Exception {

View file

@ -852,9 +852,17 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
} catch (BacktrackException bt) {
IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
final IASTNode beforeProblem = bt.getNodeBeforeProblem();
final IASTProblem problem = bt.getProblem();
if (problem != null && beforeProblem instanceof IASTStatement) {
result.addStatement((IASTStatement) beforeProblem);
result.addStatement(buildProblemStatement(problem));
endOffset= calculateEndOffset(beforeProblem);
} else {
IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
}
} catch (EndOfFileException e) {
IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt);
@ -1809,21 +1817,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
* This method will attempt to parse a statement as both an expression and a declaration,
* if both parses succeed then an ambiguity node is returned.
*/
protected IASTStatement parseDeclarationOrExpressionStatement(DeclarationOptions option) throws EndOfFileException, BacktrackException {
protected IASTStatement parseDeclarationOrExpressionStatement() throws EndOfFileException, BacktrackException {
// First attempt to parse an expressionStatement
// Note: the function style cast ambiguity is handled in expression
// Since it only happens when we are in a statement
IToken mark = mark();
IASTExpressionStatement expressionStatement = null;
IToken lastTokenOfExpression = null;
IToken afterExpression = null;
boolean foundSemicolon= false;
try {
IASTExpression expression = expression();
if (LT(1) == IToken.tEOC)
lastTokenOfExpression = consume();
else
lastTokenOfExpression = consume(IToken.tSEMI);
expressionStatement = nodeFactory.newExpressionStatement(expression);
((ASTNode) expressionStatement).setOffsetAndLength(mark.getOffset(), lastTokenOfExpression.getEndOffset() - mark.getOffset());
setRange(expressionStatement, expression);
afterExpression= LA();
IToken semi= consumeOrEOC(IToken.tSEMI);
foundSemicolon= true;
adjustEndOffset(expressionStatement, semi.getEndOffset());
afterExpression= LA();
} catch (BacktrackException b) {
}
@ -1832,22 +1843,31 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
// Now attempt to parse a declarationStatement
IASTDeclarationStatement ds = null;
try {
IASTDeclaration d = declaration(option);
IASTDeclaration d = declaration(DeclarationOptions.LOCAL);
ds = nodeFactory.newDeclarationStatement(d);
((ASTNode) ds).setOffsetAndLength(((ASTNode) d).getOffset(), ((ASTNode) d).getLength());
setRange(ds, d);
} catch (BacktrackException b) {
if (expressionStatement == null) {
backup(mark);
IASTNode node = b.getNodeBeforeProblem();
if (node instanceof IASTDeclaration) {
ds= nodeFactory.newDeclarationStatement((IASTDeclaration) node);
b.initialize(b.getProblem(), setRange(ds, node));
}
throw b;
}
}
if (expressionStatement == null) {
return ds;
}
if (ds == null) {
backup(lastTokenOfExpression); consume();
return expressionStatement;
backup(afterExpression);
if (foundSemicolon)
return expressionStatement;
throwBacktrack(createProblem(IProblem.SYNTAX_ERROR, calculateEndOffset(expressionStatement), 0), expressionStatement);
return null; // Hint for java-compiler
}
if (expressionStatement == null || !foundSemicolon) {
return ds;
}
// At this point we know we have an ambiguity.
@ -1879,7 +1899,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
// x;
// can be parsed as a named declaration specifier without a declarator
if (declarators.length == 0) {
backup(lastTokenOfExpression); consume();
backup(afterExpression);
return expressionStatement;
}
}
@ -1889,8 +1909,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IASTAmbiguousStatement statement = createAmbiguousStatement();
statement.addStatement(expressionStatement);
statement.addStatement(ds);
((ASTNode) statement).setOffsetAndLength((ASTNode) ds);
return statement;
return setRange(statement, ds);
}
@ -2259,10 +2278,19 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr);
protected abstract IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall);
protected IASTStatement forInitStatement(DeclarationOptions option) throws BacktrackException, EndOfFileException {
protected IASTStatement forInitStatement() throws BacktrackException, EndOfFileException {
if( LT(1) == IToken.tSEMI )
return parseNullStatement();
return parseDeclarationOrExpressionStatement(option);
try {
return parseDeclarationOrExpressionStatement();
} catch (BacktrackException e) {
// Missing semicolon within for loop does not make a complete for-statement
IASTNode before = e.getNodeBeforeProblem();
if (before != null) {
e.initialize(e.getProblem());
}
throw e;
}
}
/**

View file

@ -357,8 +357,13 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
return functionDefinition(firstOffset, declSpec, declarators);
default:
if (declOption != DeclarationOptions.LOCAL) {
insertSemi= true;
insertSemi= true;
if (declOption == DeclarationOptions.LOCAL) {
endOffset= figureEndOffset(declSpec, declarators);
if (firstOffset != endOffset) {
break;
}
} else {
if (markBeforDtor != null) {
endOffset= calculateEndOffset(declSpec);
if (firstOffset != endOffset && !isOnSameLine(endOffset, markBeforDtor.getOffset())) {
@ -1830,7 +1835,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
return parseLabelStatement();
}
return parseDeclarationOrExpressionStatement(DeclarationOptions.LOCAL);
return parseDeclarationOrExpressionStatement();
}
}
@ -2075,7 +2080,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
int startOffset;
startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTStatement init = forInitStatement(DeclarationOptions.LOCAL);
IASTStatement init = forInitStatement();
IASTExpression for_condition = null;
switch (LT(1)) {
case IToken.tSEMI:

View file

@ -1972,8 +1972,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return functionDefinition(firstOffset, declSpec, dtor);
default:
if (declOption != DeclarationOptions.LOCAL) {
insertSemi= true;
insertSemi= true;
if (declOption == DeclarationOptions.LOCAL) {
endOffset= figureEndOffset(declSpec, declarators);
break;
} else {
if (isLegalWithoutDtor(declSpec) && markBeforDtor != null && !isOnSameLine(calculateEndOffset(declSpec), markBeforDtor.getOffset())) {
backup(markBeforDtor);
declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
@ -3851,7 +3854,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return parseLabelStatement();
}
return parseDeclarationOrExpressionStatement(DeclarationOptions.LOCAL);
return parseDeclarationOrExpressionStatement();
}
}
@ -4104,7 +4107,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
int startOffset;
startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTStatement init = forInitStatement(DeclarationOptions.LOCAL);
IASTStatement init = forInitStatement();
IASTNode for_condition = null;
switch (LT(1)) {
case IToken.tSEMI:

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2005, 2008 IBM Corporation and others.
* Copyright (c) 2005, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -15,6 +15,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
@ -29,11 +30,10 @@ import org.eclipse.cdt.core.dom.ast.IASTProblemHolder;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
@ -87,7 +87,7 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
if (node == null) return new DOMASTNodeLeafContinue(null);
// only do length check for ASTNode (getNodeLocations on PreprocessorStatements is very expensive)
if (node instanceof ASTNode && ((ASTNode)node).getLength() <= 0)
if (node instanceof ASTNode && ((ASTNode)node).getLength() <= 0 && !(node instanceof IASTProblemHolder))
return new DOMASTNodeLeafContinue(null);
DOMASTNodeParent parent = null;
@ -153,8 +153,8 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
DOMASTNodeLeaf temp = addRoot(declarator);
IASTPointerOperator[] ops = declarator.getPointerOperators();
for(int i=0; i<ops.length; i++)
addRoot(ops[i]);
for (IASTPointerOperator op : ops)
addRoot(op);
if (temp == null)
return PROCESS_ABORT;
@ -347,11 +347,11 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
}
public void mergePreprocessorProblems(IASTProblem[] problems) {
for(int i=0; i<problems.length; i++) {
for (IASTProblem problem : problems) {
if (monitor != null && monitor.isCanceled()) return;
if (problems[i] instanceof ASTNode)
mergeNode((ASTNode)problems[i]);
if (problem instanceof ASTNode)
mergeNode((ASTNode)problem);
}
}
@ -368,9 +368,7 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
final String path= ((IASTPreprocessorIncludeStatement) nodeLeaf.getNode()).getPath();
final DOMASTNodeLeaf[] children = root.getChildren(false);
for(int j=0; j < children.length; j++) {
// if (monitor != null && monitor.isCanceled()) return; // this causes a deadlock when checked here
final DOMASTNodeLeaf child = children[j];
for (final DOMASTNodeLeaf child : children) {
if (child != null && child != nodeLeaf &&
child.getNode().getContainingFilename().equals(path)) {
root.removeChild(child);