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:
parent
7938f9e2c4
commit
2ec6a92a98
6 changed files with 98 additions and 54 deletions
|
@ -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$
|
||||
|
|
|
@ -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;
|
||||
|
@ -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 {
|
||||
// int a;
|
||||
public void testIncompleteCompositeType() throws Exception {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue