1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 02:36: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$ 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 public void testBaseCase_FunctionDeclaration() throws Exception
{ {
String code = "int x(); x( );"; //$NON-NLS-1$ 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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; 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.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
@ -103,6 +104,24 @@ public class FaultToleranceTests extends AST2BaseTest {
} }
} }
// 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 { // struct X {
// int a; // int a;
public void testIncompleteCompositeType() throws Exception { public void testIncompleteCompositeType() throws Exception {

View file

@ -852,9 +852,17 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
result.addStatement(stmt); result.addStatement(stmt);
endOffset= calculateEndOffset(stmt); endOffset= calculateEndOffset(stmt);
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
IASTStatement stmt= skipProblemStatement(stmtOffset); final IASTNode beforeProblem = bt.getNodeBeforeProblem();
result.addStatement(stmt); final IASTProblem problem = bt.getProblem();
endOffset= calculateEndOffset(stmt); 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) { } catch (EndOfFileException e) {
IASTStatement stmt= skipProblemStatement(stmtOffset); IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt); 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, * 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. * 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 // First attempt to parse an expressionStatement
// Note: the function style cast ambiguity is handled in expression // Note: the function style cast ambiguity is handled in expression
// Since it only happens when we are in a statement // Since it only happens when we are in a statement
IToken mark = mark(); IToken mark = mark();
IASTExpressionStatement expressionStatement = null; IASTExpressionStatement expressionStatement = null;
IToken lastTokenOfExpression = null; IToken afterExpression = null;
boolean foundSemicolon= false;
try { try {
IASTExpression expression = expression(); IASTExpression expression = expression();
if (LT(1) == IToken.tEOC)
lastTokenOfExpression = consume();
else
lastTokenOfExpression = consume(IToken.tSEMI);
expressionStatement = nodeFactory.newExpressionStatement(expression); 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) { } catch (BacktrackException b) {
} }
@ -1832,22 +1843,31 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
// Now attempt to parse a declarationStatement // Now attempt to parse a declarationStatement
IASTDeclarationStatement ds = null; IASTDeclarationStatement ds = null;
try { try {
IASTDeclaration d = declaration(option); IASTDeclaration d = declaration(DeclarationOptions.LOCAL);
ds = nodeFactory.newDeclarationStatement(d); ds = nodeFactory.newDeclarationStatement(d);
((ASTNode) ds).setOffsetAndLength(((ASTNode) d).getOffset(), ((ASTNode) d).getLength()); setRange(ds, d);
} catch (BacktrackException b) { } catch (BacktrackException b) {
if (expressionStatement == null) { 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; throw b;
} }
} }
if (expressionStatement == null) {
return ds;
}
if (ds == null) { if (ds == null) {
backup(lastTokenOfExpression); consume(); backup(afterExpression);
return expressionStatement; 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. // At this point we know we have an ambiguity.
@ -1879,7 +1899,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
// x; // x;
// can be parsed as a named declaration specifier without a declarator // can be parsed as a named declaration specifier without a declarator
if (declarators.length == 0) { if (declarators.length == 0) {
backup(lastTokenOfExpression); consume(); backup(afterExpression);
return expressionStatement; return expressionStatement;
} }
} }
@ -1889,8 +1909,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
IASTAmbiguousStatement statement = createAmbiguousStatement(); IASTAmbiguousStatement statement = createAmbiguousStatement();
statement.addStatement(expressionStatement); statement.addStatement(expressionStatement);
statement.addStatement(ds); statement.addStatement(ds);
((ASTNode) statement).setOffsetAndLength((ASTNode) ds); return setRange(statement, ds);
return statement;
} }
@ -2259,10 +2278,19 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr); protected abstract IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr);
protected abstract IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall); 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 ) if( LT(1) == IToken.tSEMI )
return parseNullStatement(); 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); return functionDefinition(firstOffset, declSpec, declarators);
default: 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) { if (markBeforDtor != null) {
endOffset= calculateEndOffset(declSpec); endOffset= calculateEndOffset(declSpec);
if (firstOffset != endOffset && !isOnSameLine(endOffset, markBeforDtor.getOffset())) { if (firstOffset != endOffset && !isOnSameLine(endOffset, markBeforDtor.getOffset())) {
@ -1830,7 +1835,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
return parseLabelStatement(); return parseLabelStatement();
} }
return parseDeclarationOrExpressionStatement(DeclarationOptions.LOCAL); return parseDeclarationOrExpressionStatement();
} }
} }
@ -2075,7 +2080,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
int startOffset; int startOffset;
startOffset = consume().getOffset(); startOffset = consume().getOffset();
consume(IToken.tLPAREN); consume(IToken.tLPAREN);
IASTStatement init = forInitStatement(DeclarationOptions.LOCAL); IASTStatement init = forInitStatement();
IASTExpression for_condition = null; IASTExpression for_condition = null;
switch (LT(1)) { switch (LT(1)) {
case IToken.tSEMI: case IToken.tSEMI:

View file

@ -1972,8 +1972,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return functionDefinition(firstOffset, declSpec, dtor); return functionDefinition(firstOffset, declSpec, dtor);
default: 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())) { if (isLegalWithoutDtor(declSpec) && markBeforDtor != null && !isOnSameLine(calculateEndOffset(declSpec), markBeforDtor.getOffset())) {
backup(markBeforDtor); backup(markBeforDtor);
declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY; declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
@ -3851,7 +3854,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return parseLabelStatement(); return parseLabelStatement();
} }
return parseDeclarationOrExpressionStatement(DeclarationOptions.LOCAL); return parseDeclarationOrExpressionStatement();
} }
} }
@ -4104,7 +4107,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
int startOffset; int startOffset;
startOffset = consume().getOffset(); startOffset = consume().getOffset();
consume(IToken.tLPAREN); consume(IToken.tLPAREN);
IASTStatement init = forInitStatement(DeclarationOptions.LOCAL); IASTStatement init = forInitStatement();
IASTNode for_condition = null; IASTNode for_condition = null;
switch (LT(1)) { switch (LT(1)) {
case IToken.tSEMI: 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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator; 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.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName; 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.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; 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.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.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; 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.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode; 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); if (node == null) return new DOMASTNodeLeafContinue(null);
// only do length check for ASTNode (getNodeLocations on PreprocessorStatements is very expensive) // 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); return new DOMASTNodeLeafContinue(null);
DOMASTNodeParent parent = null; DOMASTNodeParent parent = null;
@ -153,8 +153,8 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
DOMASTNodeLeaf temp = addRoot(declarator); DOMASTNodeLeaf temp = addRoot(declarator);
IASTPointerOperator[] ops = declarator.getPointerOperators(); IASTPointerOperator[] ops = declarator.getPointerOperators();
for(int i=0; i<ops.length; i++) for (IASTPointerOperator op : ops)
addRoot(ops[i]); addRoot(op);
if (temp == null) if (temp == null)
return PROCESS_ABORT; return PROCESS_ABORT;
@ -347,11 +347,11 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
} }
public void mergePreprocessorProblems(IASTProblem[] problems) { public void mergePreprocessorProblems(IASTProblem[] problems) {
for(int i=0; i<problems.length; i++) { for (IASTProblem problem : problems) {
if (monitor != null && monitor.isCanceled()) return; if (monitor != null && monitor.isCanceled()) return;
if (problems[i] instanceof ASTNode) if (problem instanceof ASTNode)
mergeNode((ASTNode)problems[i]); mergeNode((ASTNode)problem);
} }
} }
@ -368,9 +368,7 @@ public class CPPPopulateASTViewAction extends CPPASTVisitor implements IPopulate
final String path= ((IASTPreprocessorIncludeStatement) nodeLeaf.getNode()).getPath(); final String path= ((IASTPreprocessorIncludeStatement) nodeLeaf.getNode()).getPath();
final DOMASTNodeLeaf[] children = root.getChildren(false); final DOMASTNodeLeaf[] children = root.getChildren(false);
for(int j=0; j < children.length; j++) { for (final DOMASTNodeLeaf child : children) {
// if (monitor != null && monitor.isCanceled()) return; // this causes a deadlock when checked here
final DOMASTNodeLeaf child = children[j];
if (child != null && child != nodeLeaf && if (child != null && child != nodeLeaf &&
child.getNode().getContainingFilename().equals(path)) { child.getNode().getContainingFilename().equals(path)) {
root.removeChild(child); root.removeChild(child);