1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Handling problems in declarations, bug 100321, 234085 and 238151.

This commit is contained in:
Markus Schorn 2008-06-24 12:50:46 +00:00
parent 525c3124a7
commit 53841121fb
14 changed files with 1332 additions and 656 deletions

View file

@ -1,26 +1,28 @@
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* Copyright (c) 2005, 2008 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* Created on Jun 9, 2003
* by bnicolle
*/
package org.eclipse.cdt.core.model.tests;
import org.eclipse.cdt.core.model.*;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
import junit.framework.*;
import java.util.List;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IField;
import org.eclipse.cdt.core.model.IMethodDeclaration;
import org.eclipse.cdt.core.model.IStructure;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
/**
* @author bnicolle
*
@ -36,6 +38,7 @@ public class IStructureTests extends IntegratedCModelTest {
/**
* @see org.eclipse.cdt.internal.core.model.IntegratedCModelTest
*/
@Override
public String getSourcefileSubdir() {
return "resources/cmodel/";
}
@ -43,6 +46,7 @@ public class IStructureTests extends IntegratedCModelTest {
/**
* @see org.eclipse.cdt.internal.core.model.IntegratedCModelTest
*/
@Override
public String getSourcefileResource() {
return "IStructure.cpp";
}
@ -83,7 +87,7 @@ public class IStructureTests extends IntegratedCModelTest {
ITranslationUnit tu = getTU();
List arrayStructs = tu.getChildrenOfType(ICElement.C_STRUCT);
String[] myExpectedStructs = {
"testStruct1", "testStruct2", "testStruct3",
"testStruct1", "testStruct2", "testStruct3", "testStruct4NoSemicolon",
/* 2 anonymous structs */ "", "", "testStruct7",
"testStruct8"
};
@ -98,8 +102,8 @@ public class IStructureTests extends IntegratedCModelTest {
ITranslationUnit tu = getTU();
List arrayClasses = tu.getChildrenOfType(ICElement.C_CLASS);
String[] myExpectedClasses = {
"testClass1", "testClass3", "testClass4Abstract",
"testClass5", "testClass6" };
"testClass1", "testClass2NoSemicolon", "testClass3", "testClass4Abstract",
"testClass5", "testClass6"};
assertEquals(myExpectedClasses.length,arrayClasses.size());
for(int i=0; i<myExpectedClasses.length; i++) {
IStructure myIStruct = (IStructure) arrayClasses.get(i);

View file

@ -51,6 +51,8 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.c.CASTVisitor;
import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression;
import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.ISourceCodeParser;
import org.eclipse.cdt.core.dom.parser.c.ANSICParserExtensionConfiguration;
@ -553,6 +555,20 @@ public class AST2BaseTest extends BaseTestCase {
return (T) decls[i_decl];
}
final protected <T extends IASTDeclaration> T getDeclaration(ICPPASTNamespaceDefinition ns, int i_decl) {
Class<T> tclass;
IASTDeclaration[] decls= ns.getDeclarations();
assertTrue(decls.length > i_decl);
return (T) decls[i_decl];
}
final protected <T extends IASTDeclaration> T getDeclaration(ICPPASTLinkageSpecification ls, int i_decl) {
Class<T> tclass;
IASTDeclaration[] decls= ls.getDeclarations();
assertTrue(decls.length > i_decl);
return (T) decls[i_decl];
}
final protected <T extends IASTDeclaration> T getDeclaration(IASTCompositeTypeSpecifier ct, int i_decl) {
Class<T> tclass;
IASTDeclaration[] decls= ct.getMembers();
@ -566,7 +582,10 @@ public class AST2BaseTest extends BaseTestCase {
}
final protected <T extends IASTStatement> T getStatement(IASTFunctionDefinition fdef, int i_stmt) {
IASTCompoundStatement compound= (IASTCompoundStatement) fdef.getBody();
return getStatement((IASTCompoundStatement) fdef.getBody(), i_stmt);
}
final protected <T extends IASTStatement> T getStatement(IASTCompoundStatement compound, int i_stmt) {
IASTStatement[] stmts= compound.getStatements();
assertTrue(stmts.length > i_stmt);
return (T) stmts[i_stmt];

View file

@ -76,6 +76,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
@ -5737,4 +5738,30 @@ public class AST2CPPTests extends AST2BaseTest {
}
isTypeEqual(CPPVisitor.createType(newExpr.getTypeId()), type);
}
// namespace ns {
// void test() {}
// +error
// }
public void testTrailingSyntaxErrorInNamespace() throws Exception {
final String comment= getAboveComment();
IASTTranslationUnit tu= parse(comment, ParserLanguage.CPP, false, false);
ICPPASTNamespaceDefinition ns= getDeclaration(tu, 0);
IASTDeclaration decl= getDeclaration(ns, 0);
IASTProblemDeclaration pdecl= getDeclaration(ns, 1);
assertEquals("+error", pdecl.getRawSignature());
}
// extern "C" {
// void test() {}
// +error
// }
public void testTrailingSyntaxErrorInLinkageSpec() throws Exception {
final String comment= getAboveComment();
IASTTranslationUnit tu= parse(comment, ParserLanguage.CPP, false, false);
ICPPASTLinkageSpecification ls= getDeclaration(tu, 0);
IASTDeclaration decl= getDeclaration(ls, 0);
IASTProblemDeclaration pdecl= getDeclaration(ls, 1);
assertEquals("+error", pdecl.getRawSignature());
}
}

View file

@ -1,13 +1,14 @@
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* Copyright (c) 2005, 2008 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Rational Software - Initial API and implementation
* Anton Leherbauer (Wind River Systems)
* IBM Rational Software - Initial API and implementation
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@ -17,6 +18,7 @@ import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
@ -277,8 +279,9 @@ public class AST2KnRTests extends AST2BaseTest {
buffer.append( "int f(x) char\n" ); //$NON-NLS-1$
buffer.append( "{ return x == 0; }\n" ); //$NON-NLS-1$
IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.C, true, false );
assertTrue( tu.getDeclarations()[0] instanceof IASTProblemDeclaration );
IASTDeclaration[] decls= tu.getDeclarations();
assertTrue(CVisitor.getProblems(tu).length > 0);
}
public void testKRCProblem2() throws Exception {
@ -288,8 +291,8 @@ public class AST2KnRTests extends AST2BaseTest {
buffer.append( "{ return x == 0; }\n" ); //$NON-NLS-1$
IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.C, true, false );
assertTrue( tu.getDeclarations()[1] instanceof IASTProblemDeclaration );
assertTrue( tu.getDeclarations()[2] instanceof IASTProblemDeclaration );
IASTSimpleDeclaration sd= getDeclaration(tu, 0);
assertTrue(CVisitor.getProblems(tu).length > 0);
}
public void testKRCProblem3() throws Exception {

View file

@ -50,6 +50,7 @@ import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
@ -4957,4 +4958,65 @@ public class AST2Tests extends AST2BaseTest {
assertEquals("ptr", p.getName());
}
}
// void test() {}
// +error
public void testTrailingSyntaxErrorInTU() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTDeclaration decl= getDeclaration(tu, 0);
IASTProblemDeclaration pdecl= getDeclaration(tu, 1);
assertEquals("+error", pdecl.getRawSignature());
}
}
// struct X {
// int test;
// +error
// };
public void testTrailingSyntaxErrorInCompositeType() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTCompositeTypeSpecifier ct= getCompositeType(tu, 0);
IASTDeclaration decl= getDeclaration(ct, 0);
IASTProblemDeclaration pdecl= getDeclaration(ct, 1);
assertEquals("+error", pdecl.getRawSignature());
}
}
// void func() {
// {
// int test;
// +error
// }
// }
public void testTrailingSyntaxErrorInCompoundStatements() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTFunctionDefinition def= getDeclaration(tu, 0);
IASTCompoundStatement compStmt= getStatement(def, 0);
IASTDeclarationStatement dstmt= getStatement(compStmt, 0);
IASTProblemStatement pstmt= getStatement(compStmt, 1);
assertEquals("+error", pstmt.getRawSignature());
}
}
// struct X {
// ;
// };
// ;
public void testEmptyDeclarations() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTCompositeTypeSpecifier ct= getCompositeType(tu, 0);
IASTDeclaration empty= getDeclaration(ct, 0);
assertEquals(";", empty.getRawSignature());
empty= getDeclaration(tu, 1);
assertEquals(";", empty.getRawSignature());
}
}
}

View file

@ -467,7 +467,7 @@ public class DOMLocationTests extends AST2BaseTest {
assertSoleLocation(problems[0], code, "xxx(!");
assertSoleLocation( decls[0], code, "int x;");
assertSoleLocation( problems[1], code, "\\");
assertFileLocation( decls[1], code, "int x\\i");
assertFileLocation( decls[1], code, "int x\\i;");
assertSoleLocation( decls[2], code, "int x2;");
}
}

View file

@ -50,6 +50,7 @@ public class DOMParserTestSuite extends TestCase {
suite.addTest(TaskParserTest.suite());
suite.addTest(CompletionTestSuite.suite());
suite.addTestSuite(CharArrayMapTest.class);
suite.addTest(FaultToleranceTests.suite());
return suite;
}
}

View file

@ -0,0 +1,216 @@
/*******************************************************************************
* Copyright (c) 2008 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
import junit.framework.TestSuite;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
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.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.parser.ParserLanguage;
/**
* Testcases related to recovery from invalid syntax.
*/
public class FaultToleranceTests extends AST2BaseTest {
public static TestSuite suite() {
return suite(FaultToleranceTests.class);
}
public FaultToleranceTests() {
super();
}
public FaultToleranceTests(String name) {
super(name);
}
// typedef int tint;
// struct X {
// int a;
// }
// tint b;
public void testCompositeTypeWithoutSemi() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTCompositeTypeSpecifier def= getCompositeType(tu, 1);
IASTProblemDeclaration pdecl= getDeclaration(tu, 2);
IASTSimpleDeclaration sdecl= getDeclaration(tu, 3);
}
}
// typedef int tint;
// struct X {
// int a;
// } c
// tint b;
public void testCompositeTypeWithDtorWithoutSemi() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTSimpleDeclaration sdecl= getDeclaration(tu, 1);
assertInstance(sdecl.getDeclSpecifier(), IASTCompositeTypeSpecifier.class);
assertEquals(1, sdecl.getDeclarators().length);
IASTProblemDeclaration pdecl= getDeclaration(tu, 2);
sdecl= getDeclaration(tu, 3);
}
}
// typedef int tint;
// int a
// tint b;
public void testVariableWithoutSemi() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTSimpleDeclaration sdecl= getDeclaration(tu, 1);
assertEquals("int a", sdecl.getRawSignature());
IASTProblemDeclaration pdecl= getDeclaration(tu, 2);
sdecl= getDeclaration(tu, 3);
}
}
// typedef int tint;
// int a()
// tint b;
public void testPrototypeWithoutSemi() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTSimpleDeclaration sdecl= getDeclaration(tu, 1);
assertEquals("int a()", sdecl.getRawSignature());
IASTProblemDeclaration pdecl= getDeclaration(tu, 2);
sdecl= getDeclaration(tu, 3);
}
}
// struct X {
// int a;
public void testIncompleteCompositeType() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTCompositeTypeSpecifier comp= getCompositeType(tu, 0);
IASTProblemDeclaration pdecl= getDeclaration(tu, 1);
IASTSimpleDeclaration sdecl= getDeclaration(comp, 0);
}
}
// void func() {
// int a;
public void testIncompleteFunctionDefinition() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTFunctionDefinition fdef= getDeclaration(tu, 0);
IASTProblemDeclaration pdecl= getDeclaration(tu, 1);
IASTDeclarationStatement sdecl= getStatement(fdef, 0);
}
}
// namespace ns {
// int a;
public void testIncompleteNamespace() throws Exception {
final String comment= getAboveComment();
IASTTranslationUnit tu= parse(comment, ParserLanguage.CPP, false, false);
ICPPASTNamespaceDefinition ns= getDeclaration(tu, 0);
IASTProblemDeclaration pdecl= getDeclaration(tu, 1);
IASTSimpleDeclaration sdecl= getDeclaration(ns, 0);
}
// extern "C" {
// int a;
public void testIncompleteLinkageSpec() throws Exception {
final String comment= getAboveComment();
IASTTranslationUnit tu= parse(comment, ParserLanguage.CPP, false, false);
ICPPASTLinkageSpecification ls= getDeclaration(tu, 0);
IASTProblemDeclaration pdecl= getDeclaration(tu, 1);
IASTSimpleDeclaration sdecl= getDeclaration(ls, 0);
}
// void test() {
// int a= offsetof(struct mystruct, singlechar);
// }
public void testRangeOfProblemNode_Bug238151() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTFunctionDefinition fdef= getDeclaration(tu, 0);
IASTProblemStatement pdecl= getStatement(fdef, 0);
assertEquals("int a= offsetof(struct mystruct, singlechar);", pdecl.getRawSignature());
}
}
// int f(){
// if( 12 A )
// return -1;
// int v;
// }
public void testProblemInIfExpression_Bug100321() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTFunctionDefinition fdef= getDeclaration(tu, 0);
IASTIfStatement ifstmt= getStatement(fdef, 0);
assertInstance(ifstmt.getConditionExpression(), IASTProblemExpression.class);
assertEquals("12 A", ifstmt.getConditionExpression().getRawSignature());
assertInstance(ifstmt.getThenClause(), IASTReturnStatement.class);
}
}
// _MYMACRO_ myType foo();
// _MYMACRO_ myType foo() {}
// extern void foo2() _MYMACRO_;
public void testUndefinedMacrosInFunctionDeclarations_Bug234085() throws Exception {
final String comment= getAboveComment();
for (ParserLanguage lang : ParserLanguage.values()) {
IASTTranslationUnit tu= parse(comment, lang, false, false);
IASTProblemDeclaration pd= getDeclaration(tu, 0);
assertEquals("_MYMACRO_", pd.getRawSignature());
IASTSimpleDeclaration sdecl= getDeclaration(tu, 1);
assertEquals("myType foo();", sdecl.getRawSignature());
pd= getDeclaration(tu, 2);
assertEquals("_MYMACRO_", pd.getRawSignature());
IASTFunctionDefinition fdef= getDeclaration(tu, 3);
assertEquals("myType foo() {}", fdef.getRawSignature());
sdecl= getDeclaration(tu, 4);
assertEquals("extern void foo2()", sdecl.getRawSignature());
pd= getDeclaration(tu, 5);
assertEquals("", pd.getRawSignature()); // the missing semicolon
if (lang == ParserLanguage.CPP) {
pd= getDeclaration(tu, 6);
assertEquals("_MYMACRO_;", pd.getRawSignature());
} else {
sdecl= getDeclaration(tu, 6);
assertEquals("_MYMACRO_;", sdecl.getRawSignature());
}
}
}
}

View file

@ -1,12 +1,13 @@
/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and others.
* Copyright (c) 2004, 2008 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Rational Software - Initial API and implementation
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@ -210,10 +211,11 @@ public class GCCCompleteParseExtensionsTest extends AST2BaseTest {
{
parseGPP("class B { public: B(); int a;}; B::B() : a(({ 1; })) {}"); //$NON-NLS-1$
Writer writer = new StringWriter();
writer.write( "int foo(); class B { public: B(); int a;};");
writer.write( "B::B() : a(( { int y = foo (); int z;\n" ); //$NON-NLS-1$
writer.write( "if (y > 0) z = y;\n" ); //$NON-NLS-1$
writer.write( "else z = - y;\n" );//$NON-NLS-1$
writer.write( "z; }))\n" );//$NON-NLS-1$
writer.write( "z; })) {}\n" );//$NON-NLS-1$
parseGPP( writer.toString() );
writer = new StringWriter();

View file

@ -6,7 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Rational Software - Initial API and implementation
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
@ -846,7 +847,7 @@ public class QuickParser2Tests extends TestCase {
parse(
"class Functor {" +
"Functor(const Functor& rhs) : spImpl_(Impl::Clone(rhs.spImpl_.get())){}" +
"}"
"};"
);
}
@ -1524,7 +1525,7 @@ public class QuickParser2Tests extends TestCase {
writer.write("B::B() : a(( { int y = foo (); int z;\n");
writer.write("if (y > 0) z = y;\n");
writer.write("else z = - y;\n");
writer.write("z; }))\n");
writer.write("z; })) {}\n");
parse(writer.toString(), true, ParserLanguage.CPP, true);
writer = new StringWriter();
writer.write("int x = ({ int y = foo (); int z;\n");

View file

@ -36,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
@ -47,6 +48,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNullStatement;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
import org.eclipse.cdt.core.dom.ast.IASTProblemStatement;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
@ -74,6 +76,7 @@ import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.ParseError;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
/**
* @author jcamelon
@ -90,6 +93,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected final boolean supportAttributeSpecifiers;
protected final boolean supportDeclspecSpecifiers;
protected final IBuiltinBindingsProvider builtinBindingsProvider;
/**
* Marks the beginning of the current declaration. It is important to clear the mark whenever we
* enter a nested declaration, in order to avoid holding on to all the tokens.
*/
protected IToken declarationMark;
protected IToken currToken;
protected int eofOffset;
protected boolean parsePassed = true;
protected int backtrackCount = 0;
protected BacktrackException backtrack = new BacktrackException();
protected ASTCompletionNode completionNode;
protected AbstractGNUSourceCodeParser(IScanner scanner,
IParserLogService logService, ParserMode parserMode,
@ -110,12 +125,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
this.builtinBindingsProvider= builtinBindingsProvider;
}
protected boolean parsePassed = true;
protected BacktrackException backtrack = new BacktrackException();
protected int backtrackCount = 0;
private AbstractParserLogService wrapLogService(IParserLogService logService) {
if (logService instanceof AbstractParserLogService) {
return (AbstractParserLogService) logService;
@ -129,11 +138,6 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
throw backtrack;
}
protected IToken currToken;
protected ASTCompletionNode completionNode;
public IASTCompletionNode getCompletionNode() {
return completionNode;
}
@ -175,6 +179,17 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return retToken;
}
/**
* Same as {@link #LA(int)}, but returns <code>null</code> when eof is reached.
*/
protected IToken LAcatchEOF(int i) {
try {
return LA(i);
} catch (EndOfFileException e) {
return null;
}
}
/**
* Look ahead in the token list and return the token type.
*
@ -187,6 +202,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected int LT(int i) throws EndOfFileException {
return LA(i).getType();
}
/**
* Same as {@link #LT(int)}, but returns <code>0</code> when eof is reached.
*/
protected int LTcatchEOF(int i) {
try {
return LT(i);
} catch (EndOfFileException e) {
return 0;
}
}
protected boolean isOnSameLine(int offset1, int offset2) {
ILocationResolver lr= (ILocationResolver) getTranslationUnit().getAdapter(ILocationResolver.class);
IASTFileLocation floc= lr.getMappedFileLocation(offset1, offset2-offset1+1);
return floc.getFileName().equals(lr.getContainingFilePath(offset1)) &&
floc.getStartingLineNumber() == floc.getEndingLineNumber();
}
protected int calculateEndOffset(IASTNode n) {
ASTNode node = (ASTNode) n;
@ -263,7 +296,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
*/
protected IToken fetchToken() throws EndOfFileException {
try {
return scanner.nextToken();
final IToken result= scanner.nextToken();
eofOffset= result.getEndOffset();
return result;
} catch (OffsetLimitReachedException olre) {
handleOffsetLimitException(olre);
// never returns, to make the java-compiler happy:
@ -344,24 +379,11 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return backtrackCount;
}
/**
* @deprecated
*/
@Deprecated
protected void throwBacktrack(BacktrackException bt) throws BacktrackException {
throw bt;
}
protected IASTProblem failParse(BacktrackException bt) {
IASTProblem result = null;
if (bt.getProblem() == null)
result = createProblem(IProblem.SYNTAX_ERROR, bt.getOffset(), bt
.getLength());
else
result = bt.getProblem();
failParse();
protected IASTProblem createProblem(BacktrackException bt) {
IASTProblem result= bt.getProblem();
if (result == null) {
result= createProblem(IProblem.SYNTAX_ERROR, bt.getOffset(), bt.getLength());
}
return result;
}
@ -413,16 +435,18 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
protected final void throwBacktrack(IASTProblem problem)
throws BacktrackException {
protected final void throwBacktrack(IASTProblem problem, IASTNode node) throws BacktrackException {
++backtrackCount;
backtrack.initialize(problem, node);
throw backtrack;
}
protected final void throwBacktrack(IASTProblem problem) throws BacktrackException {
++backtrackCount;
backtrack.initialize(problem);
throw backtrack;
}
private static final IASTNode[] EMPTY_NODE_ARRAY = new IASTNode[0];
public IASTTranslationUnit parse() {
long startTime = System.currentTimeMillis();
translationUnit();
@ -474,92 +498,189 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return result;
}
/**
* @throws EndOfFileException
*/
protected void errorHandling() throws EndOfFileException {
int depth = (LT(1) == IToken.tLBRACE) ? 1 : 0;
int type = consume().getType();
if (type == IToken.tSEMI)
return;
while (!((LT(1) == IToken.tSEMI && depth == 0) || (LT(1) == IToken.tRBRACE && depth == 1))) {
switch (LT(1)) {
case IToken.tLBRACE:
++depth;
break;
case IToken.tRBRACE:
--depth;
break;
case IToken.tEOC:
throw new EndOfFileException();
}
if (depth < 0)
return;
consume();
}
// eat the SEMI/RBRACE as well
consume();
protected IASTProblemDeclaration skipProblemDeclaration(int offset) {
failParse();
declarationMark= null;
int endOffset = skipToSemiOrClosingBrace(offset);
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
return createProblemDeclaration(problem);
}
protected IASTProblemStatement skipProblemStatement(int offset) {
failParse();
declarationMark= null;
int endOffset = skipToSemiOrClosingBrace(offset);
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
return createProblemStatement(problem);
}
/**
* This function is called whenever we encounter and error that we cannot
* backtrack out of and we still wish to try and continue on with the parse
* to do a best-effort parse for our client.
*
* @throws EndOfFileException
* We can potentially hit EndOfFile here as we are skipping
* ahead.
*/
protected void failParseWithErrorHandling() throws EndOfFileException {
failParse();
errorHandling();
}
private int skipToSemiOrClosingBrace(int offset) {
failParse();
declarationMark= null;
int depth= 0;
int endOffset;
loop: try {
endOffset= LA(1).getOffset();
while(true) {
switch (LT(1)) {
case IToken.tEOC:
endOffset= eofOffset;
break loop;
case IToken.tSEMI:
if (depth == 0) {
endOffset= consume().getEndOffset();
break loop;
}
break;
case IToken.tLBRACE:
++depth;
break;
case IToken.tRBRACE:
if (--depth <= 0) {
if (depth == 0 || offset == endOffset) {
endOffset= consume().getEndOffset(); // consume closing brace
}
break loop;
}
break;
}
endOffset= consume().getEndOffset();
}
} catch (EndOfFileException e) {
endOffset= eofOffset;
}
return endOffset;
}
protected IASTProblemExpression skipProblemConditionInParenthesis(int offset) {
failParse();
int compExpr= 0;
int depth= 0;
int endOffset= offset;
loop: try {
while(true) {
switch (LT(1)) {
case IToken.tEOC:
endOffset= eofOffset;
break loop;
case IToken.tSEMI:
case IToken.tLBRACE:
if (compExpr == 0) {
break loop;
}
break;
case IToken.tLPAREN:
depth++;
if (LTcatchEOF(2) == IToken.tLBRACE) {
if (compExpr == 0) {
compExpr= depth;
}
consume();
}
break;
case IToken.tRPAREN:
if (--depth < 0) {
break loop;
}
if (depth < compExpr) {
compExpr= 0;
}
break;
}
endOffset= consume().getEndOffset();
}
} catch (EndOfFileException e) {
endOffset= eofOffset;
}
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
return createProblemExpression(problem);
}
/**
* @return TODO
* @throws BacktrackException
*/
protected IASTCompoundStatement compoundStatement()
throws EndOfFileException, BacktrackException {
protected IASTCompoundStatement compoundStatement() throws EndOfFileException, BacktrackException {
IASTCompoundStatement result = createCompoundStatement();
if (LT(1) == IToken.tEOC)
return result;
int startingOffset = consume(IToken.tLBRACE).getOffset();
final int offset= LA(1).getOffset();
int endOffset= consume(IToken.tLBRACE).getOffset();
((ASTNode) result).setOffset(startingOffset);
//result.setPropertyInParent(IASTFunctionDefinition.FUNCTION_BODY);
while (LT(1) != IToken.tRBRACE && LT(1) != IToken.tEOC) {
int checkToken = LA(1).hashCode();
int stmtOffset= -1;
while(true) {
IToken next= LAcatchEOF(1);
if (next == null) {
((ASTNode) result).setOffsetAndLength(offset, endOffset-offset);
throwBacktrack(createProblem(IProblem.SYNTAX_ERROR, endOffset, 0), result);
return null; // hint for java-compiler
}
try {
IASTStatement s = statement();
result.addStatement(s);
} catch (BacktrackException b) {
IASTProblem p = failParse(b);
IASTProblemStatement ps = createProblemStatement();
ps.setProblem(p);
((ASTNode) ps).setOffsetAndLength(((ASTNode) p).getOffset(),
((ASTNode) p).getLength());
result.addStatement(ps);
if (LA(1).hashCode() == checkToken)
failParseWithErrorHandling();
if (next.getType() == IToken.tEOC)
break;
if (next.getType() == IToken.tRBRACE) {
endOffset= consume().getEndOffset();
break;
}
final int nextOffset = next.getOffset();
declarationMark= next;
next= null; // don't hold on to the token while parsing namespaces, class bodies, etc.
IASTStatement stmt;
if (stmtOffset == nextOffset) {
// no progress
stmt= skipProblemStatement(stmtOffset);
} else {
stmtOffset= nextOffset;
stmt= statement();
}
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
} catch (BacktrackException bt) {
IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
} catch (EndOfFileException e) {
IASTStatement stmt= skipProblemStatement(stmtOffset);
result.addStatement(stmt);
endOffset= calculateEndOffset(stmt);
break;
} finally {
declarationMark= null;
}
}
IToken token = consume();
int lastOffset = token.getEndOffset();
((ASTNode) result).setLength(lastOffset - startingOffset);
((ASTNode) result).setOffsetAndLength(offset, endOffset-offset);
return result;
}
protected abstract IASTProblemStatement createProblemStatement();
protected abstract IASTProblemDeclaration createProblemDeclaration();
protected abstract IASTCompoundStatement createCompoundStatement();
private IASTProblemDeclaration createProblemDeclaration(IASTProblem problem) {
IASTProblemDeclaration pd = createProblemDeclaration();
pd.setProblem(problem);
((ASTNode) pd).setOffsetAndLength(((ASTNode) problem));
return pd;
}
private IASTProblemStatement createProblemStatement(IASTProblem problem) {
IASTProblemStatement pstmt = createProblemStatement();
pstmt.setProblem(problem);
((ASTNode) pstmt).setOffsetAndLength(((ASTNode) problem));
return pstmt;
}
private IASTProblemExpression createProblemExpression(IASTProblem problem) {
IASTProblemExpression pexpr = createProblemExpression();
pexpr.setProblem(problem);
((ASTNode) pexpr).setOffsetAndLength(((ASTNode) problem));
return pexpr;
}
protected IASTExpression compoundStatementExpression() throws EndOfFileException, BacktrackException {
int startingOffset = consume().getOffset(); // tLPAREN always
IASTCompoundStatement compoundStatement = null;
@ -637,10 +758,62 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTExpression buildTypeIdExpression(int op,
IASTTypeId typeId, int startingOffset, int endingOffset);
protected abstract void translationUnit();
protected abstract IASTTranslationUnit getTranslationUnit();
protected abstract void setupTranslationUnit() throws Exception;
protected void translationUnit() {
try {
setupTranslationUnit();
} catch (Exception e2) {
logException("translationUnit::createCompilationUnit()", e2); //$NON-NLS-1$
return;
}
parseTranslationUnit();
}
protected void parseTranslationUnit() {
final IASTTranslationUnit tu= getTranslationUnit();
int offset= -1;
while (true) {
try {
IToken next= LAcatchEOF(1);
if (next == null || next.getType() == IToken.tEOC)
break;
final int nextOffset = next.getOffset();
declarationMark= next;
next= null; // don't hold on to the token while parsing namespaces, class bodies, etc.
if (offset == nextOffset) {
// no progress
tu.addDeclaration(skipProblemDeclaration(offset));
} else {
offset= nextOffset;
final IASTDeclaration declaration= declaration(DeclarationOptions.GLOBAL);
tu.addDeclaration(declaration);
}
} catch (BacktrackException bt) {
IASTDeclaration[] decls= problemDeclaration(offset, bt, DeclarationOptions.GLOBAL);
for (IASTDeclaration declaration : decls) {
tu.addDeclaration(declaration);
}
} catch (EndOfFileException e) {
tu.addDeclaration(skipProblemDeclaration(offset));
break;
} catch (OutOfMemoryError oome) {
logThrowable("translationUnit", oome); //$NON-NLS-1$
throw oome;
} catch (Exception e) {
logException("translationUnit", e); //$NON-NLS-1$
tu.addDeclaration(skipProblemDeclaration(offset));
} finally {
declarationMark= null;
}
}
((ASTNode) tu).setLength(eofOffset);
}
protected IASTExpression assignmentOperatorExpression(int kind,
IASTExpression lhs) throws EndOfFileException, BacktrackException {
consume();
@ -910,6 +1083,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
protected IASTStatement handleFunctionBody() throws BacktrackException, EndOfFileException {
declarationMark= null;
if (mode == ParserMode.QUICK_PARSE || mode == ParserMode.STRUCTURAL_PARSE) {
IToken curr = LA(1);
IToken last = skipOverCompoundStatement();
@ -1089,9 +1263,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTName createName(IToken token);
protected IASTExpression condition() throws BacktrackException, EndOfFileException {
IASTExpression cond = expression();
return cond;
protected IASTExpression condition(boolean followedByParenthesis) throws BacktrackException, EndOfFileException {
IToken mark= mark();
try {
IASTExpression expr= expression();
if (!followedByParenthesis)
return expr;
switch (LT(1)) {
case IToken.tEOC:
case IToken.tRPAREN:
return expr;
}
} catch (BacktrackException b) {
if (!followedByParenthesis)
throw b;
}
backup(mark);
return skipProblemConditionInParenthesis(mark.getOffset());
}
public boolean encounteredError() {
@ -1143,8 +1332,67 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTDeclaration declaration(DeclarationOptions option) throws BacktrackException, EndOfFileException;
protected IASTDeclaration[] problemDeclaration(int offset, BacktrackException bt, DeclarationOptions option) {
failParse();
IASTProblem origProblem= createProblem(bt);
// a node was detected by assuming additional tokens (e.g. missing semicolon)
IASTNode n= bt.getNodeBeforeProblem();
if (n instanceof IASTDeclaration) {
declarationMark= null;
return new IASTDeclaration[] {(IASTDeclaration) n, createProblemDeclaration(origProblem)};
}
if (declarationMark != null) {
IASTDeclaration trailingProblem= null;
offset= declarationMark.getOffset();
// try to skip identifiers (undefined macros?)
IASTDeclaration decl= null;
int endOffset= 0;
loop: while (declarationMark != null && declarationMark.getType() == IToken.tIDENTIFIER) {
endOffset= declarationMark.getEndOffset();
declarationMark= declarationMark.getNext();
if (declarationMark != null) {
backup(declarationMark);
// avoid creating an empty declaration
switch(LTcatchEOF(1)) {
case 0: // eof
case IToken.tEOC:
case IToken.tSEMI:
break loop;
}
try {
decl= declaration(option);
break;
} catch (BacktrackException bt2) {
n= bt.getNodeBeforeProblem();
if (n instanceof IASTDeclaration) {
decl= (IASTDeclaration) n;
trailingProblem= createProblemDeclaration(bt.getProblem());
break;
}
} catch (EndOfFileException e) {
endOffset= eofOffset;
break;
}
}
}
declarationMark= null;
if (decl != null) {
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, offset, endOffset-offset);
IASTDeclaration pd= createProblemDeclaration(problem);
if (trailingProblem != null)
return new IASTDeclaration[] {pd, decl, trailingProblem};
return new IASTDeclaration[] {pd, decl};
}
}
protected IASTDeclaration asmDeclaration() throws EndOfFileException,
return new IASTDeclaration[] {skipProblemDeclaration(offset)};
}
protected IASTDeclaration asmDeclaration() throws EndOfFileException,
BacktrackException {
IToken first = consume(); // t_asm
IToken next= LA(1);
@ -1463,7 +1711,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (LT(1) != IToken.tEOC) {
consume(IToken.t_while);
consume(IToken.tLPAREN);
do_condition = condition();
do_condition = condition(true);
}
int lastOffset;
@ -1500,7 +1748,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected IASTStatement parseWhileStatement() throws EndOfFileException, BacktrackException {
int startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTExpression while_condition = condition();
IASTExpression while_condition = condition(true);
switch (LT(1)) {
case IToken.tRPAREN:
consume();
@ -1668,7 +1916,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
return new IASTNode[] {unaryExpression};
}
return EMPTY_NODE_ARRAY;
return IASTNode.EMPTY_NODE_ARRAY;
}

View file

@ -6,10 +6,12 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
/**
@ -17,20 +19,35 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem;
*/
public class BacktrackException extends Exception {
private IASTProblem problem;
private IASTNode nodeBeforeProblem; // a node has been created in spite of the problem.
private int offset, length;
public BacktrackException() {
}
public BacktrackException(BacktrackException e) {
problem= e.problem;
nodeBeforeProblem= e.nodeBeforeProblem;
offset= e.offset;
length= e.length;
}
/**
* @param p
*/
public void initialize(IASTProblem p) {
reset();
problem = p;
}
public void initialize(IASTProblem p, IASTNode node) {
reset();
problem = p;
nodeBeforeProblem= node;
}
/**
*
*/
private void reset() {
nodeBeforeProblem= null;
problem = null;
offset = 0;
length = 0;
@ -41,6 +58,10 @@ public class BacktrackException extends Exception {
public final IASTProblem getProblem() {
return problem;
}
public final IASTNode getNodeBeforeProblem() {
return nodeBeforeProblem;
}
public void initialize(int start, int l ) {
reset();

View file

@ -18,6 +18,7 @@ import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
@ -361,27 +362,46 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
switch (LT(1)) {
case IToken.t_asm:
return asmDeclaration();
default:
IASTDeclaration d = simpleDeclaration(declOption);
return d;
case IToken.tSEMI:
IToken semi= consume();
IASTSimpleDeclaration decl= createSimpleDeclaration();
IASTDeclSpecifier declspec= createSimpleTypeSpecifier();
decl.setDeclSpecifier(declspec);
((ASTNode) declspec).setOffsetAndLength(semi.getOffset(), 0);
((ASTNode) decl).setOffsetAndLength(semi.getOffset(), semi.getLength());
return decl;
}
return simpleDeclaration(declOption);
}
private IASTDeclaration simpleDeclaration(final DeclarationOptions declOption) throws BacktrackException, EndOfFileException {
final IToken firstToken = LA(1);
if (firstToken.getType() == IToken.tLBRACE)
throwBacktrack(firstToken);
private IASTDeclaration simpleDeclaration(final DeclarationOptions declOption)
throws BacktrackException, EndOfFileException {
if (LT(1) == IToken.tLBRACE)
throwBacktrack(LA(1));
final int firstOffset = firstToken.getOffset();
final int firstOffset= LA(1).getOffset();
int endOffset= firstOffset;
IASTDeclSpecifier declSpec;
IASTDeclarator dtor= null;
IToken markBeforDtor= null;
try {
declSpec = declSpecifierSeq(declOption);
final int lt1= LT(1);
if (lt1 != IToken.tSEMI && lt1 != IToken.tEOC) {
dtor= initDeclarator(declOption);
switch(LTcatchEOF(1)) {
case 0: // eof
case IToken.tSEMI:
case IToken.tEOC:
break;
default:
markBeforDtor= mark();
try {
dtor= initDeclarator(declOption);
} catch (BacktrackException e) {
backup(markBeforDtor);
} catch (EndOfFileException e) {
backup(markBeforDtor);
}
}
} catch (FoundDeclaratorException e) {
if (e.altSpec != null) {
@ -395,13 +415,15 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
}
IASTDeclarator[] declarators= {dtor};
while (LT(1) == IToken.tCOMMA) {
while (LTcatchEOF(1) == IToken.tCOMMA) {
consume();
declarators= (IASTDeclarator[]) ArrayUtil.append( IASTDeclarator.class, declarators, initDeclarator(declOption));
}
declarators= (IASTDeclarator[]) ArrayUtil.removeNulls( IASTDeclarator.class, declarators );
switch (LT(1)) {
boolean insertSemi= false;
final int lt1= LTcatchEOF(1);
switch (lt1) {
case IToken.tLBRACE:
return functionDefinition(firstOffset, declSpec, declarators);
@ -412,18 +434,38 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
endOffset= figureEndOffset(declSpec, declarators);
break;
default:
throwBacktrack(firstOffset, LA(1).getEndOffset() - firstOffset);
insertSemi= true;
if (markBeforDtor == null || !isOnSameLine(calculateEndOffset(declSpec), markBeforDtor.getOffset())) {
if (markBeforDtor != null) {
backup(markBeforDtor);
}
declarators= IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
endOffset= calculateEndOffset(declSpec);
break;
}
endOffset= figureEndOffset(declSpec, declarators);
if (lt1 == 0 || !isOnSameLine(endOffset, LA(1).getOffset())) {
break;
}
if (declarators.length == 1 && declarators[0] instanceof IASTFunctionDeclarator) {
break;
}
throwBacktrack(LA(1));
}
// no function body
IASTSimpleDeclaration simpleDeclaration = createSimpleDeclaration();
simpleDeclaration.setDeclSpecifier(declSpec);
for (int i = 0; i < declarators.length; ++i) {
IASTDeclarator declarator = declarators[i];
for (IASTDeclarator declarator : declarators) {
simpleDeclaration.addDeclarator(declarator);
}
((ASTNode) simpleDeclaration).setOffsetAndLength(firstOffset, endOffset-firstOffset);
if (insertSemi) {
IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, endOffset, 0);
throwBacktrack(problem, simpleDeclaration);
}
return simpleDeclaration;
}
@ -440,12 +482,22 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
IASTFunctionDefinition funcDefinition = createFunctionDefinition();
funcDefinition.setDeclSpecifier(declSpec);
funcDefinition.setDeclarator((IASTFunctionDeclarator) fdtor);
try {
IASTStatement s= handleFunctionBody();
funcDefinition.setBody(s);
((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(s) - firstOffset);
IASTStatement s= handleFunctionBody();
funcDefinition.setBody(s);
((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(s) - firstOffset);
return funcDefinition;
return funcDefinition;
} catch (BacktrackException bt) {
final IASTNode n= bt.getNodeBeforeProblem();
if (n instanceof IASTCompoundStatement) {
funcDefinition.setBody((IASTCompoundStatement) n);
((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(n) - firstOffset);
throwBacktrack(bt.getProblem(), funcDefinition);
}
throw bt;
}
}
protected IASTFunctionDefinition createFunctionDefinition() {
@ -463,88 +515,25 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
return t;
}
/**
* This is the top-level entry point into the ANSI C++ grammar.
*
* translationUnit : (declaration)*
*/
@Override
protected void translationUnit() {
try {
translationUnit = createTranslationUnit();
translationUnit.setIndex(index);
@Override
protected void setupTranslationUnit() throws DOMException {
translationUnit = createTranslationUnit();
translationUnit.setIndex(index);
// add built-in names to the scope
if (builtinBindingsProvider != null) {
IScope tuScope = translationUnit.getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
}
// add built-in names to the scope
if (builtinBindingsProvider != null) {
IScope tuScope = translationUnit.getScope();
IBinding[] bindings = builtinBindingsProvider.getBuiltinBindings(tuScope);
for (IBinding binding : bindings) {
ASTInternal.addBinding(tuScope, binding);
}
} catch (Exception e2) {
logException("translationUnit::createCompilationUnit()", e2); //$NON-NLS-1$
return;
}
}
translationUnit.setLocationResolver(scanner.getLocationResolver());
}
translationUnit.setLocationResolver(scanner.getLocationResolver());
int lastBacktrack = -1;
while (true) {
try {
if (LT(1) == IToken.tEOC)
break;
int checkOffset = LA(1).hashCode();
IASTDeclaration d = declaration(DeclarationOptions.GLOBAL);
translationUnit.addDeclaration(d);
if (LA(1).hashCode() == checkOffset)
failParseWithErrorHandling();
} catch (EndOfFileException e) {
break;
} catch (BacktrackException b) {
try {
// Mark as failure and try to reach a recovery point
IASTProblem p = failParse(b);
IASTProblemDeclaration pd = createProblemDeclaration();
pd.setProblem(p);
((ASTNode) pd).setOffsetAndLength(((ASTNode) p).getOffset(), ((ASTNode) p).getLength());
translationUnit.addDeclaration(pd);
errorHandling();
if (lastBacktrack != -1 && lastBacktrack == LA(1).hashCode()) {
// we haven't progressed from the
// last backtrack
// try and find tne next definition
failParseWithErrorHandling();
} else {
// start again from here
lastBacktrack = LA(1).hashCode();
}
} catch (EndOfFileException e) {
break;
}
} catch (OutOfMemoryError oome) {
logThrowable("translationUnit", oome); //$NON-NLS-1$
throw oome;
} catch (Exception e) {
logException("translationUnit", e); //$NON-NLS-1$
try {
failParseWithErrorHandling();
} catch (EndOfFileException e3) {
// nothing
}
}
}
IASTDeclaration[] declarations = translationUnit.getDeclarations();
if (declarations.length != 0) {
ASTNode d = (ASTNode) declarations[declarations.length-1];
((ASTNode) translationUnit).setLength(d.getOffset() + d.getLength());
} else {
((ASTNode) translationUnit).setLength(0);
}
}
protected IASTProblemDeclaration createProblemDeclaration() {
@Override
protected IASTProblemDeclaration createProblemDeclaration() {
return new CASTProblemDeclaration();
}
@ -1092,13 +1081,14 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
boolean encounteredTypename= false;
declSpecifiers: for (;;) {
final IToken token= LA(1);
final int lt1= token.getType();
final int lt1= LTcatchEOF(1);
switch (lt1) {
// Storage Class Specifiers
case 0: // eof
break declSpecifiers;
// storage class specifiers
case IToken.t_auto:
endOffset= consume().getEndOffset();
storageClass = IASTDeclSpecifier.sc_auto;
endOffset= consume().getEndOffset();
break;
case IToken.t_register:
storageClass = IASTDeclSpecifier.sc_register;
@ -1139,60 +1129,84 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
// Type Specifiers
case IToken.t_void:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_void;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_char:
simpleType = IASTSimpleDeclSpecifier.t_char;
encounteredRawType= true;
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_char;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_short:
if (encounteredTypename)
break declSpecifiers;
options |= SHORT;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_int:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_int;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_long:
if (encounteredTypename)
break declSpecifiers;
isLong++;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_float:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_float;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_double:
if (encounteredTypename)
break declSpecifiers;
simpleType = IASTSimpleDeclSpecifier.t_double;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_signed:
if (encounteredTypename)
break declSpecifiers;
options |= SIGNED;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t_unsigned:
if (encounteredTypename)
break declSpecifiers;
options |= UNSIGNED;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t__Bool:
if (encounteredTypename)
break declSpecifiers;
simpleType = ICASTSimpleDeclSpecifier.t_Bool;
encounteredRawType= true;
endOffset= consume().getEndOffset();
break;
case IToken.t__Complex:
if (encounteredTypename)
break declSpecifiers;
options |= COMPLEX;
endOffset= consume().getEndOffset();
break;
case IToken.t__Imaginary:
if (encounteredTypename)
break declSpecifiers;
options |= IMAGINARY;
endOffset= consume().getEndOffset();
break;
@ -1232,7 +1246,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_struct:
case IToken.t_union:
if (encounteredTypename || encounteredRawType)
throwBacktrack(token);
break declSpecifiers;
try {
result= structOrUnionSpecifier();
} catch (BacktrackException bt) {
@ -1243,7 +1257,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
break;
case IToken.t_enum:
if (encounteredTypename || encounteredRawType)
throwBacktrack(token);
break declSpecifiers;
try {
result= enumSpecifier();
} catch (BacktrackException bt) {
@ -1256,35 +1270,35 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
case IGCCToken.t__attribute__: // if __attribute__ is after the declSpec
if (!supportAttributeSpecifiers)
throwBacktrack(token);
throwBacktrack(LA(1));
__attribute_decl_seq(true, false);
break;
case IGCCToken.t__declspec: // __declspec precedes the identifier
if (identifier != null || !supportDeclspecSpecifiers)
throwBacktrack(token);
throwBacktrack(LA(1));
__attribute_decl_seq(false, true);
break;
case IGCCToken.t_typeof:
if (encounteredRawType || encounteredTypename)
throwBacktrack(LA(1));
typeofExpression = unaryTypeofExpression();
encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression);
break;
default:
if (lt1 >= IExtensionToken.t__otherDeclSpecModifierFirst && lt1 <= IExtensionToken.t__otherDeclSpecModifierLast) {
handleOtherDeclSpecModifier();
endOffset= LA(1).getOffset();
break;
}
if (lt1 == IGCCToken.t_typeof) {
if (encounteredRawType || encounteredTypename)
throwBacktrack(token);
typeofExpression = unaryTypeofExpression();
encounteredTypename= true;
endOffset= calculateEndOffset(typeofExpression);
break;
}
break declSpecifiers;
}
if (encounteredRawType && encounteredTypename)
throwBacktrack(token);
throwBacktrack(LA(1));
}
// check for empty specification
@ -1402,33 +1416,31 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
*
* @throws BacktrackException to request a backtrack
*/
protected ICASTCompositeTypeSpecifier structOrUnionSpecifier()
throws BacktrackException, EndOfFileException {
protected ICASTCompositeTypeSpecifier structOrUnionSpecifier() throws BacktrackException, EndOfFileException {
int classKind = 0;
IToken classKey = null;
IToken mark = mark();
IToken mark= mark();
final int offset= mark.getOffset();
// class key
switch (LT(1)) {
case IToken.t_struct:
classKey = consume();
consume();
classKind = IASTCompositeTypeSpecifier.k_struct;
break;
case IToken.t_union:
classKey = consume();
consume();
classKind = IASTCompositeTypeSpecifier.k_union;
break;
default:
throwBacktrack(mark.getOffset(), mark.getLength());
throwBacktrack(LA(1));
return null; // line never reached, hint for the parser.
}
// if __attribute__ or __declspec occurs after struct/union/class and before the identifier
__attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
IToken nameToken = null;
// class name
IToken nameToken = null;
if (LT(1) == IToken.tIDENTIFIER) {
nameToken = identifier();
}
@ -1439,40 +1451,55 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
if (LT(1) != IToken.tLBRACE) {
IToken errorPoint = LA(1);
backup(mark);
throwBacktrack(errorPoint.getOffset(), errorPoint.getLength());
throwBacktrack(errorPoint);
}
consume();
IASTName name = (nameToken == null) ? createName() : createName(nameToken);
ICASTCompositeTypeSpecifier result = createCompositeTypeSpecifier();
result.setKey(classKind);
((ASTNode) result).setOffset(classKey.getOffset());
result.setName(name);
int endOffset;
memberDeclarationLoop: while (true) {
switch (LT(1)) {
case IToken.tRBRACE:
case IToken.tEOC:
endOffset = consume().getEndOffset();
break memberDeclarationLoop;
default:
int checkToken = LA(1).hashCode();
try {
IASTDeclaration d = declaration(DeclarationOptions.C_MEMBER);
result.addMemberDeclaration(d);
} catch (BacktrackException bt) {
if (checkToken == LA(1).hashCode())
failParseWithErrorHandling();
}
if (checkToken == LA(1).hashCode())
failParseWithErrorHandling();
}
int endOffset= consume().getEndOffset();
int declOffset= -1;
loop: while (true) {
try {
IToken next= LAcatchEOF(1);
if (next == null || next.getType() == IToken.tEOC)
break loop; // the missing semicolon will cause a problem, just break the loop.
if (next.getType() == IToken.tRBRACE) {
endOffset= consume().getEndOffset();
break loop;
}
final int nextOffset = next.getOffset();
declarationMark= next;
next= null; // don't hold on to the token while parsing namespaces, class bodies, etc.
IASTDeclaration d;
if (declOffset == nextOffset) {
// no progress
d= skipProblemDeclaration(declOffset);
} else {
d = declaration(DeclarationOptions.C_MEMBER);
}
result.addMemberDeclaration(d);
endOffset= calculateEndOffset(d);
} catch (BacktrackException bt) {
IASTDeclaration[] decls= problemDeclaration(declOffset, bt, DeclarationOptions.C_MEMBER);
for (IASTDeclaration declaration : decls) {
result.addMemberDeclaration(declaration);
endOffset= calculateEndOffset(declaration);
}
} catch (EndOfFileException e) {
result.addMemberDeclaration(skipProblemDeclaration(declOffset));
endOffset= eofOffset;
break loop;
} finally {
declarationMark= null;
}
}
((ASTNode) result).setLength(endOffset - classKey.getOffset());
((ASTNode) result).setOffsetAndLength(offset, endOffset - offset);
return result;
}
@ -2344,39 +2371,21 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
if_loop: while (true) {
int so = consume(IToken.t_if).getOffset();
consume(IToken.tLPAREN);
IASTExpression condition = null;
try {
condition = condition();
if (LT(1) == IToken.tEOC) {
// Completing in the condition
IASTIfStatement new_if = createIfStatement();
new_if.setConditionExpression(condition);
if (if_statement != null) {
if_statement.setElseClause(new_if);
}
return result != null ? result : new_if;
}
consume(IToken.tRPAREN);
} catch (BacktrackException b) {
IASTProblem p = failParse(b);
IASTProblemExpression ps = createProblemExpression();
ps.setProblem(p);
((ASTNode) ps).setOffsetAndLength(((ASTNode) p).getOffset(), ((ASTNode) p).getLength());
condition = ps;
if( LT(1) == IToken.tRPAREN )
consume();
else if( LT(2) == IToken.tRPAREN )
{
consume();
consume();
}
else
failParseWithErrorHandling();
// condition
IASTExpression condition= condition(true);
if (LT(1) == IToken.tEOC) {
// Completing in the condition
IASTIfStatement new_if = createIfStatement();
new_if.setConditionExpression(condition);
if (if_statement != null) {
if_statement.setElseClause(new_if);
}
return result != null ? result : new_if;
}
consume(IToken.tRPAREN);
IASTStatement thenClause = statement();
IASTIfStatement new_if_statement = createIfStatement();
((ASTNode) new_if_statement).setOffset(so);
if( condition != null ) // shouldn't be possible but failure in condition() makes it so
@ -2463,7 +2472,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
int startOffset;
startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTExpression switch_condition = condition();
IASTExpression switch_condition = condition(true);
switch (LT(1)) {
case IToken.tRPAREN:
consume();
@ -2500,7 +2509,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
case IToken.tEOC:
break;
default:
for_condition = condition();
for_condition = condition(false);
}
switch (LT(1)) {
case IToken.tSEMI: