From 53841121fbee541530adce785617d5b58ae0ea5e Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Tue, 24 Jun 2008 12:50:46 +0000 Subject: [PATCH] Handling problems in declarations, bug 100321, 234085 and 238151. --- .../cdt/core/model/tests/IStructureTests.java | 32 +- .../core/parser/tests/ast2/AST2BaseTest.java | 21 +- .../core/parser/tests/ast2/AST2CPPTests.java | 27 + .../core/parser/tests/ast2/AST2KnRTests.java | 17 +- .../cdt/core/parser/tests/ast2/AST2Tests.java | 62 ++ .../parser/tests/ast2/DOMLocationTests.java | 2 +- .../parser/tests/ast2/DOMParserTestSuite.java | 1 + .../tests/ast2/FaultToleranceTests.java | 216 ++++++ .../ast2/GCCCompleteParseExtensionsTest.java | 8 +- .../parser/tests/ast2/QuickParser2Tests.java | 7 +- .../parser/AbstractGNUSourceCodeParser.java | 464 +++++++++--- .../core/dom/parser/BacktrackException.java | 29 +- .../core/dom/parser/c/GNUCSourceParser.java | 385 +++++----- .../dom/parser/cpp/GNUCPPSourceParser.java | 717 ++++++++++-------- 14 files changed, 1332 insertions(+), 656 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/IStructureTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/IStructureTests.java index fadec34ac62..56068949636 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/IStructureTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/IStructureTests.java @@ -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 T getDeclaration(ICPPASTNamespaceDefinition ns, int i_decl) { + Class tclass; + IASTDeclaration[] decls= ns.getDeclarations(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + + final protected T getDeclaration(ICPPASTLinkageSpecification ls, int i_decl) { + Class tclass; + IASTDeclaration[] decls= ls.getDeclarations(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + final protected T getDeclaration(IASTCompositeTypeSpecifier ct, int i_decl) { Class tclass; IASTDeclaration[] decls= ct.getMembers(); @@ -566,7 +582,10 @@ public class AST2BaseTest extends BaseTestCase { } final protected T getStatement(IASTFunctionDefinition fdef, int i_stmt) { - IASTCompoundStatement compound= (IASTCompoundStatement) fdef.getBody(); + return getStatement((IASTCompoundStatement) fdef.getBody(), i_stmt); + } + + final protected T getStatement(IASTCompoundStatement compound, int i_stmt) { IASTStatement[] stmts= compound.getStatements(); assertTrue(stmts.length > i_stmt); return (T) stmts[i_stmt]; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 76354569e44..c30f1317447 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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()); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2KnRTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2KnRTests.java index d10cf26a39f..ee35ca7e0e0 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2KnRTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2KnRTests.java @@ -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 { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index c94b11b1422..c1322455348 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -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()); + } + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java index 68429982a18..4f720a1116c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java @@ -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;"); } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java index 04581a3f1dd..716312420ea 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java @@ -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; } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java new file mode 100644 index 00000000000..232ae4993e7 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/FaultToleranceTests.java @@ -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()); + } + } + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java index 09a9189cc2e..bebbe0eccbf 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java @@ -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(); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/QuickParser2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/QuickParser2Tests.java index 40de3b495b5..1df2d778f12 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/QuickParser2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/QuickParser2Tests.java @@ -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"); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 377ad230f3a..9d472e19119 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -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 null 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 0 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; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java index ade7a92ba61..0be886eca5d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/BacktrackException.java @@ -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(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index cace918efae..92b3ef61357 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -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: diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 08ff5f0883f..969d5c9decc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -19,6 +19,7 @@ import java.util.ArrayList; 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; @@ -1869,48 +1870,68 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { */ protected ICPPASTLinkageSpecification linkageSpecification() throws EndOfFileException, BacktrackException { - IToken firstToken = consume(); // t_extern - IToken spec = consume(); // tString + int offset= consume().getOffset(); // t_extern + String spec = consume().getImage(); // tString ICPPASTLinkageSpecification linkage = createLinkageSpecification(); - ((ASTNode) linkage).setOffset(firstToken.getOffset()); - linkage.setLiteral(spec.getImage()); + linkage.setLiteral(spec); if (LT(1) == IToken.tLBRACE) { - consume(); + int endOffset= consume().getEndOffset(); + int declOffset= -1; + while(true) { + IToken next= LAcatchEOF(1); + if (next == null) { + ((ASTNode) linkage).setOffsetAndLength(offset, endOffset-offset); + throwBacktrack(createProblem(IProblem.SYNTAX_ERROR, endOffset, 0), linkage); + return null; // hint for java-compiler + } + try { + 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. - linkageDeclarationLoop: while (LT(1) != IToken.tRBRACE) { - int checkToken = LA(1).hashCode(); - switch (LT(1)) { - case IToken.tRBRACE: - break linkageDeclarationLoop; - default: - try { - IASTDeclaration d = declaration(DeclarationOptions.GLOBAL); - linkage.addDeclaration(d); - } catch (BacktrackException bt) { - IASTProblem p = failParse(bt); - IASTProblemDeclaration pd = createProblemDeclaration(); - pd.setProblem(p); - ((ASTNode) pd).setOffsetAndLength(((ASTNode) p)); - linkage.addDeclaration(pd); - errorHandling(); - if (checkToken == LA(1).hashCode()) - errorHandling(); - } + IASTDeclaration d; + if (declOffset == nextOffset) { + // no progress + d= skipProblemDeclaration(declOffset); + } else { + declOffset= nextOffset; + d= declaration(DeclarationOptions.GLOBAL); + } + linkage.addDeclaration(d); + endOffset= calculateEndOffset(d); + } catch (BacktrackException bt) { + IASTDeclaration[] decls= problemDeclaration(declOffset, bt, DeclarationOptions.GLOBAL); + for (IASTDeclaration declaration : decls) { + linkage.addDeclaration(declaration); + endOffset= calculateEndOffset(declaration); + } + } catch (EndOfFileException e) { + IASTDeclaration d= skipProblemDeclaration(declOffset); + linkage.addDeclaration(d); + endOffset= calculateEndOffset(d); + break; + } finally { + declarationMark= null; } - if (checkToken == LA(1).hashCode()) - failParseWithErrorHandling(); } - // consume the } - int endOffset = consume(IToken.tRBRACE).getEndOffset(); - ((ASTNode) linkage).setLength(endOffset - firstToken.getOffset()); + ((ASTNode) linkage).setOffsetAndLength(offset, endOffset - offset); return linkage; } // single declaration IASTDeclaration d = declaration(DeclarationOptions.GLOBAL); linkage.addDeclaration(d); - ((ASTNode) linkage).setLength(calculateEndOffset(d) - firstToken.getOffset()); + int endOffset= calculateEndOffset(d); + ((ASTNode) linkage).setOffsetAndLength(offset, endOffset-offset); return linkage; } @@ -2220,78 +2241,96 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { * request a backtrack */ protected IASTDeclaration namespaceDefinitionOrAlias() throws BacktrackException, EndOfFileException { - IToken first = consume(); - int last = first.getEndOffset(); - IASTName name = null; + final int offset= consume().getOffset(); + int endOffset; + // optional name + IASTName name = null; if (LT(1) == IToken.tIDENTIFIER) { name = createName(identifier()); - last = calculateEndOffset(name); - } else + endOffset= calculateEndOffset(name); + } else { name = createName(); + } // bug 195701, gcc 4.2 allows visibility attribute for namespaces. __attribute_decl_seq(true, false); - - if (LT(1) == IToken.tLBRACE) { - consume(); - ICPPASTNamespaceDefinition namespaceDefinition = createNamespaceDefinition(); - ((ASTNode) namespaceDefinition).setOffset(first.getOffset()); - namespaceDefinition.setName(name); - namespaceDeclarationLoop: while (true) { - switch (LT(1)) { - case IToken.tRBRACE: - case IToken.tEOC: - break namespaceDeclarationLoop; - default: - int checkToken = LA(1).hashCode(); - try { - IASTDeclaration d = declaration(DeclarationOptions.GLOBAL); - namespaceDefinition.addDeclaration(d); - } catch (BacktrackException bt) { - IASTProblem p = failParse(bt); - IASTProblemDeclaration pd = createProblemDeclaration(); - pd.setProblem(p); - ((ASTNode) pd).setOffsetAndLength((ASTNode) p); - namespaceDefinition.addDeclaration(pd); - errorHandling(); - if (checkToken == LA(1).hashCode()) - errorHandling(); - } - if (checkToken == LA(1).hashCode()) - failParseWithErrorHandling(); + if (LT(1) == IToken.tLBRACE) { + ICPPASTNamespaceDefinition ns= createNamespaceDefinition(); + ns.setName(name); + endOffset= consume().getEndOffset(); + int declOffset= -1; + while(true) { + IToken next= LAcatchEOF(1); + if (next == null) { + ((ASTNode) ns).setOffsetAndLength(offset, endOffset-offset); + throwBacktrack(createProblem(IProblem.SYNTAX_ERROR, endOffset, 0), ns); + return null; // hint for java-compiler + } + try { + 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. + + IASTDeclaration d; + if (declOffset == nextOffset) { + // no progress + d= skipProblemDeclaration(declOffset); + } else { + declOffset= nextOffset; + d= declaration(DeclarationOptions.GLOBAL); + } + ns.addDeclaration(d); + endOffset= calculateEndOffset(d); + } catch (BacktrackException bt) { + IASTDeclaration[] decls= problemDeclaration(declOffset, bt, DeclarationOptions.GLOBAL); + for (IASTDeclaration declaration : decls) { + ns.addDeclaration(declaration); + endOffset= calculateEndOffset(declaration); + } + } catch (EndOfFileException e) { + IASTDeclaration d= skipProblemDeclaration(declOffset); + ns.addDeclaration(d); + endOffset= calculateEndOffset(d); + break; + } finally { + declarationMark= null; } } - - // consume the } - int end = consume().getEndOffset(); - ((ASTNode) namespaceDefinition).setLength(end - first.getOffset()); - return namespaceDefinition; - } else if (LT(1) == IToken.tASSIGN) { - IToken assign = consume(); - + ((ASTNode) ns).setOffsetAndLength(offset, endOffset - offset); + return ns; + } + + if (LT(1) == IToken.tASSIGN) { + endOffset= consume().getEndOffset(); if (name.toString() == null) { - throwBacktrack(first.getOffset(), assign.getEndOffset() - first.getOffset()); + throwBacktrack(offset, endOffset - offset); return null; } ITokenDuple duple = name(); IASTName qualifiedName = createName(duple); - int end = consume(IToken.tSEMI).getEndOffset(); + endOffset = consume(IToken.tSEMI).getEndOffset(); ICPPASTNamespaceAlias alias = createNamespaceAlias(); - ((ASTNode) alias).setOffsetAndLength(first.getOffset(), end - first.getOffset()); + ((ASTNode) alias).setOffsetAndLength(offset, endOffset - offset); alias.setAlias(name); alias.setMappingName(qualifiedName); return alias; - } else { - throwBacktrack(first.getOffset(), last - first.getOffset()); - return null; - } + } + throwBacktrack(LA(1)); + return null; } - protected ICPPASTNamespaceAlias createNamespaceAlias() { return new CPPASTNamespaceAlias(); } @@ -2449,26 +2488,45 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { /** * Parses a declaration with the given options. */ - protected IASTDeclaration simpleDeclaration(DeclarationOptions option) + protected IASTDeclaration simpleDeclaration(DeclarationOptions declOption) throws BacktrackException, EndOfFileException { - final IToken firstToken = LA(1); - if (firstToken.getType() == IToken.tLBRACE) - throwBacktrack(firstToken); + if (LT(1) == IToken.tLBRACE) + throwBacktrack(LA(1)); - final int firstOffset= firstToken.getOffset(); + final int firstOffset= LA(1).getOffset(); int endOffset= firstOffset; ICPPASTDeclSpecifier declSpec; IASTDeclarator dtor= null; + IToken markBeforDtor= null; try { - declSpec = declSpecifierSeq(option); - final int lt1= LT(1); - if (lt1 == IToken.tSEMI) { - if (!validWithoutDtor(option, declSpec)) { + declSpec = declSpecifierSeq(declOption); + switch(LTcatchEOF(1)) { + case 0: // eof + case IToken.tSEMI: + if (!validWithoutDtor(declOption, declSpec)) { throwBacktrack(LA(1)); } - } else if (lt1 != IToken.tEOC) { - dtor= initDeclarator(declSpec, option); + break; + case IToken.tCOMMA: + throwBacktrack(LA(1)); + break; + case IToken.tEOC: + break; + default: + markBeforDtor= mark(); + try { + dtor= initDeclarator(declSpec, declOption); + } catch (BacktrackException e) { + if (!validWithoutDtor(declOption, declSpec)) + throw e; + backup(markBeforDtor); + } catch (EndOfFileException e) { + if (!validWithoutDtor(declOption, declSpec)) + throw e; + backup(markBeforDtor); + } + break; } } catch (FoundDeclaratorException e) { declSpec= (ICPPASTDeclSpecifier) e.declSpec; @@ -2477,16 +2535,16 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } IASTDeclarator[] declarators= {dtor}; - while (LT(1) == IToken.tCOMMA) { + while (LTcatchEOF(1) == IToken.tCOMMA) { consume(); - declarators= (IASTDeclarator[]) ArrayUtil.append( IASTDeclarator.class, declarators, initDeclarator(declSpec, option)); + declarators= (IASTDeclarator[]) ArrayUtil.append( IASTDeclarator.class, declarators, initDeclarator(declSpec, declOption)); } + declarators= (IASTDeclarator[]) ArrayUtil.removeNulls( IASTDeclarator.class, declarators ); - boolean needFunctionBody = false; - boolean hasFunctionTryBlock = false; - - switch (LT(1)) { + boolean insertSemi= false; + final int lt1= LTcatchEOF(1); + switch (lt1) { case IToken.tEOC: endOffset= figureEndOffset(declSpec, declarators); break; @@ -2495,19 +2553,32 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { break; case IToken.t_try: consume(); - needFunctionBody= true; - hasFunctionTryBlock= true; - break; + return functionDefinition(firstOffset, declSpec, declarators, true); case IToken.tCOLON: case IToken.tLBRACE: - needFunctionBody = true; - break; + return functionDefinition(firstOffset, declSpec, declarators, false); default: - throwBacktrack(firstOffset, LA(1).getEndOffset() - firstOffset); - } - - if (needFunctionBody) { - return functionDefinition(firstOffset, declSpec, declarators, hasFunctionTryBlock); + insertSemi= true; + if (validWithoutDtor(declOption, declSpec)) { + // class definition without semicolon + 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())) { + insertSemi= true; + break; + } + if (declarators.length == 1 && declarators[0] instanceof IASTFunctionDeclarator) { + break; + } + throwBacktrack(LA(1)); } // no function body @@ -2518,6 +2589,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } ((ASTNode) simpleDeclaration).setOffsetAndLength(firstOffset, endOffset-firstOffset); + + if (insertSemi) { + IASTProblem problem= createProblem(IProblem.SYNTAX_ERROR, endOffset, 0); + throwBacktrack(problem, simpleDeclaration); + } return simpleDeclaration; } @@ -2557,10 +2633,23 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } } - - final IASTStatement body= handleFunctionBody(); + IASTStatement body; + try { + body= handleFunctionBody(); + } catch (BacktrackException bt) { + final IASTNode n= bt.getNodeBeforeProblem(); + if (n instanceof IASTCompoundStatement) { + IASTFunctionDefinition funcDefinition = createFunctionDefinition(); + funcDefinition.setDeclSpecifier(declSpec); + funcDefinition.setDeclarator(fdtor); + funcDefinition.setBody((IASTCompoundStatement) n); + ((ASTNode) funcDefinition).setOffsetAndLength(firstOffset, calculateEndOffset(n) - firstOffset); + throwBacktrack(bt.getProblem(), funcDefinition); + } + throw bt; + } + int endOffset= calculateEndOffset(body); - if (hasFunctionTryBlock) { List handlers = new ArrayList(DEFAULT_CATCH_HANDLER_LIST_SIZE); catchHandlerSequence(handlers); @@ -2731,9 +2820,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { int endOffset= offset; declSpecifiers: for (;;) { - final IToken token= LA(1); - final int lt1= token.getType(); + final int lt1= LTcatchEOF(1); switch (lt1) { + case 0: // encountered eof + break declSpecifiers; // storage class specifiers case IToken.t_auto: storageClass = IASTDeclSpecifier.sc_auto; @@ -2790,69 +2880,97 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { 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_short: + if (encounteredTypename) + break declSpecifiers; options |= SHORT; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_long: + if (encounteredTypename) + break declSpecifiers; isLong++; 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; case IToken.t_char: + if (encounteredTypename) + break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_char; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_wchar_t: + if (encounteredTypename) + break declSpecifiers; simpleType = ICPPASTSimpleDeclSpecifier.t_wchar_t; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_bool: + if (encounteredTypename) + break declSpecifiers; simpleType = ICPPASTSimpleDeclSpecifier.t_bool; 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_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_void: + if (encounteredTypename) + break declSpecifiers; simpleType = IASTSimpleDeclSpecifier.t_void; encounteredRawType= true; endOffset= consume().getEndOffset(); break; case IToken.t_typename: + if (encounteredTypename || encounteredRawType) + break declSpecifiers; consume(); identifier= name(); endOffset= identifier.getLastToken().getEndOffset(); @@ -2867,7 +2985,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { break declSpecifiers; try { - if (option.fAllowEmptySpecifier && lt1 != IToken.tCOMPLETION) { + if (option.fAllowEmptySpecifier && LT(1) != IToken.tCOMPLETION) { lookAheadForDeclarator(option); } } catch (FoundDeclaratorException e) { @@ -2885,7 +3003,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.t_struct: case IToken.t_union: if (encounteredTypename || encounteredRawType) - throwBacktrack(token); + break declSpecifiers; try { result= classSpecifier(); } catch (BacktrackException bt) { @@ -2897,7 +3015,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { case IToken.t_enum: if (encounteredTypename || encounteredRawType) - throwBacktrack(token); + break declSpecifiers; try { result= (ICPPASTDeclSpecifier) enumSpecifier(); } catch (BacktrackException bt) { @@ -2909,35 +3027,35 @@ public class GNUCPPSourceParser 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 (LT(1) >= IExtensionToken.t__otherDeclSpecModifierFirst && LT(1) <= IExtensionToken.t__otherDeclSpecModifierLast) { + if (lt1 >= IExtensionToken.t__otherDeclSpecModifierFirst && lt1 <= IExtensionToken.t__otherDeclSpecModifierLast) { handleOtherDeclSpecModifier(); endOffset= LA(1).getOffset(); break; } - if (LT(1) == 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 @@ -3781,37 +3899,35 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { * @throws BacktrackException * request a backtrack */ - protected ICPPASTCompositeTypeSpecifier classSpecifier() - throws BacktrackException, EndOfFileException { + protected ICPPASTCompositeTypeSpecifier classSpecifier() throws BacktrackException, EndOfFileException { int classKind = 0; - IToken classKey = null; IToken mark = mark(); + final int offset= mark.getOffset(); // class key switch (LT(1)) { case IToken.t_class: - classKey = consume(); + consume(); classKind = ICPPASTCompositeTypeSpecifier.k_class; break; 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(mark); return null; // line is never reached, hint for the parser } - IASTName name = null; - // if __attribute__ or __declspec occurs after struct/union/class and before the identifier __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); // class name + IASTName name = null; if (LT(1) == IToken.tIDENTIFIER) name = createName(name()); else @@ -3820,85 +3936,103 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // if __attribute__ or __declspec occurs after struct/union/class identifier and before the { or ; __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); - if (LT(1) != IToken.tCOLON && LT(1) != IToken.tLBRACE) { - IToken errorPoint = LA(1); - backup(mark); - throwBacktrack(errorPoint.getOffset(), errorPoint.getLength()); - } - ICPPASTCompositeTypeSpecifier astClassSpecifier = createClassSpecifier(); - ((ASTNode) astClassSpecifier).setOffset(classKey.getOffset()); astClassSpecifier.setKey(classKind); astClassSpecifier.setName(name); // base clause if (LT(1) == IToken.tCOLON) { baseSpecifier(astClassSpecifier); - } - - if (LT(1) == IToken.tLBRACE) { - consume(); - final char[] outerName= currentClassName; - if (name instanceof ICPPASTQualifiedName) { - currentClassName= ((ICPPASTQualifiedName)name).getLastName().toCharArray(); - } else { - currentClassName= name.toCharArray(); - } - try { - memberDeclarationLoop: while (true) { - int checkToken = LA(1).hashCode(); - switch (LT(1)) { - case IToken.t_public: - case IToken.t_protected: - case IToken.t_private: { - IToken key = consume(); - int l = consume(IToken.tCOLON).getEndOffset(); - ICPPASTVisibilityLabel label = createVisibilityLabel(); - ((ASTNode) label).setOffsetAndLength(key.getOffset(), l - key.getOffset()); - label.setVisibility(token2Visibility(key.getType())); - astClassSpecifier.addMemberDeclaration(label); - label.setParent(astClassSpecifier); - // this overrides the MEMBER_DECLARATION property - label.setPropertyInParent(ICPPASTCompositeTypeSpecifier.VISIBILITY_LABEL); - break; - } - case IToken.tRBRACE: { - int l = consume().getEndOffset(); - ((ASTNode) astClassSpecifier).setLength(l - classKey.getOffset()); - break memberDeclarationLoop; - } - case IToken.tEOC: - // Don't care about the offsets - break memberDeclarationLoop; - default: - try { - final IToken m= mark(); - try { - IASTDeclaration d= declaration(DeclarationOptions.CPP_MEMBER); - astClassSpecifier.addMemberDeclaration(d); - } catch (BacktrackException e) { - backup(m); - IASTDeclaration d= usingDeclaration(m.getOffset()); - astClassSpecifier.addMemberDeclaration(d); - } - } catch (BacktrackException bt) { - IASTProblem p = failParse(bt); - IASTProblemDeclaration pd = createProblemDeclaration(); - pd.setProblem(p); - ((ASTNode) pd).setOffsetAndLength(((ASTNode) p)); - astClassSpecifier.addMemberDeclaration(pd); - if (checkToken == LA(1).hashCode()) - errorHandling(); - } - - if (checkToken == LA(1).hashCode()) - failParseWithErrorHandling(); - } - } - } finally { - currentClassName= outerName; + // content assist within the base-clause + if (LT(1) == IToken.tEOC) { + return astClassSpecifier; } } + + if (LT(1) != IToken.tLBRACE) { + IToken errorPoint = LA(1); + backup(mark); + throwBacktrack(errorPoint); + } + mark= null; // don't hold on to tokens while parsing the members. + + + int endOffset= consume().getEndOffset(); + final char[] outerName= currentClassName; + if (name instanceof ICPPASTQualifiedName) { + currentClassName= ((ICPPASTQualifiedName)name).getLastName().toCharArray(); + } else { + currentClassName= name.toCharArray(); + } + try { + int declOffset= -1; + loop: while (true) { + BacktrackException origBackTrack= null; + 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 { + declOffset= nextOffset; + switch (LT(1)) { + case IToken.t_public: + case IToken.t_protected: + case IToken.t_private: + int key= consume().getType(); + endOffset= consume(IToken.tCOLON).getEndOffset(); + ICPPASTVisibilityLabel label = createVisibilityLabel(); + label.setVisibility(token2Visibility(key)); + ((ASTNode) label).setOffsetAndLength(declOffset, endOffset - declOffset); + astClassSpecifier.addMemberDeclaration(label); + continue loop; + } + try { + d= declaration(DeclarationOptions.CPP_MEMBER); + } catch (BacktrackException e) { + if (declarationMark == null) + throw e; + origBackTrack= new BacktrackException(e); + backup(declarationMark); + d= usingDeclaration(declarationMark.getOffset()); + } + } + astClassSpecifier.addMemberDeclaration(d); + endOffset= calculateEndOffset(d); + } catch (BacktrackException bt) { + if (origBackTrack != null) { + bt= origBackTrack; + } + IASTDeclaration[] decls= problemDeclaration(declOffset, bt, DeclarationOptions.CPP_MEMBER); + for (IASTDeclaration declaration : decls) { + astClassSpecifier.addMemberDeclaration(declaration); + endOffset= calculateEndOffset(declaration); + } + } catch (EndOfFileException e) { + astClassSpecifier.addMemberDeclaration(skipProblemDeclaration(declOffset)); + endOffset= eofOffset; + break loop; + } finally { + declarationMark= null; + } + } + } finally { + currentClassName= outerName; + } + ((ASTNode) astClassSpecifier).setOffsetAndLength(offset, endOffset - offset); return astClassSpecifier; } @@ -4033,15 +4167,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (LT(1) == IToken.tEOC) return; - if (LT(1) != IToken.t_catch) { - IToken la = LA(1); - throwBacktrack(la.getOffset(), la.getLength()); // error, need at - // least - // one of these - } - - int nextToken = LT(1); - while (nextToken == IToken.t_catch) { + if (LT(1) != IToken.t_catch) + throwBacktrack(LA(1)); // error, need at least one + + int lt1 = LT(1); + while (lt1 == IToken.t_catch) { int startOffset = consume().getOffset(); consume(IToken.tLPAREN); boolean isEllipsis = false; @@ -4056,7 +4186,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (LT(1) != IToken.tEOC) consume(IToken.tRPAREN); } catch (BacktrackException bte) { - IASTProblem p = failParse(bte); + failParse(); + IASTProblem p = createProblem(bte); IASTProblemDeclaration pd = createProblemDeclaration(); pd.setProblem(p); ((ASTNode) pd).setOffsetAndLength(((ASTNode) p)); @@ -4081,7 +4212,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { collection.add(handler); try { - nextToken = LT(1); + lt1 = LT(1); } catch (EndOfFileException eofe) { // if EOF is reached, then return here and let it be encountered elsewhere // (i.e. try/catch won't be added to the declaration if the exception is thrown here) @@ -4138,83 +4269,30 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { return compoundStatement(); } - /** - * 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 - // 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 + // 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()); - - while (true) { - try { - if (LT(1) == IToken.tEOC) - break; - int checkOffset = LA(1).hashCode(); - IASTDeclaration declaration = declaration(DeclarationOptions.GLOBAL); - translationUnit.addDeclaration(declaration); - - 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)); - translationUnit.addDeclaration(pd); - errorHandling(); - } 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); - } - } + } + translationUnit.setLocationResolver(scanner.getLocationResolver()); + } - protected IASTProblemDeclaration createProblemDeclaration() { + @Override + protected IASTProblemDeclaration createProblemDeclaration() { return new CPPASTProblemDeclaration(); } - protected CPPASTTranslationUnit createTranslationUnit() { return new CPPASTTranslationUnit(); } @@ -4560,17 +4638,18 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (lt1 == expectToken || lt1 == IToken.tEOC) { return e; } - throwBacktrack(LA(1)); } catch (BacktrackException bt) { - backup(mark); - try { - return simpleSingleDeclaration(DeclarationOptions.CONDITION); - } catch (BacktrackException b) { - failParse(); - throw b; - } } - return null; + backup(mark); + try { + return simpleSingleDeclaration(DeclarationOptions.CONDITION); + } catch (BacktrackException b) { + if (expectToken == IToken.tRPAREN) { + backup(mark); + return skipProblemConditionInParenthesis(mark.getOffset()); + } + throw b; + } } @@ -4591,41 +4670,25 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if_loop: while (true) { int so = consume(IToken.t_if).getOffset(); consume(IToken.tLPAREN); - IASTNode condition = null; - try { - condition = cppStyleCondition(IToken.tRPAREN); - // condition - if (LT(1) == IToken.tEOC) { - // Completing in the condition - ICPPASTIfStatement new_if = createIfStatement(); - if (condition instanceof IASTExpression) - new_if.setConditionExpression((IASTExpression) condition); - else if (condition instanceof IASTDeclaration) - new_if.setConditionDeclaration((IASTDeclaration) condition); + // condition + IASTNode condition= cppStyleCondition(IToken.tRPAREN); + if (LT(1) == IToken.tEOC) { + // Completing in the condition + ICPPASTIfStatement new_if = createIfStatement(); + if (condition instanceof IASTExpression) + new_if.setConditionExpression((IASTExpression) condition); + else if (condition instanceof IASTDeclaration) + new_if.setConditionDeclaration((IASTDeclaration) 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(); + if (if_statement != null) { + if_statement.setElseClause(new_if); + } + return result != null ? result : new_if; } + consume(IToken.tRPAREN); + IASTStatement thenClause = statement(); - ICPPASTIfStatement new_if_statement = createIfStatement(); ((ASTNode) new_if_statement).setOffset(so); if (condition != null && (condition instanceof IASTExpression || condition instanceof IASTDeclaration))