From 1aae35abf1f91b9b4bc3f034483db67d593f41ad Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Tue, 5 Aug 2008 09:44:53 +0000 Subject: [PATCH] Empty versus no exception specification, bug 86943. --- .../core/parser/tests/ast2/AST2CPPTests.java | 24 +++++++++++ .../changegenerator/remove/ExceptionTest.java | 2 +- .../internal/core/model/ASTStringUtil.java | 5 ++- .../ast/cpp/ICPPASTFunctionDeclarator.java | 19 ++++++++- .../cdt/core/parser/util/ArrayUtil.java | 10 ++--- .../parser/cpp/CPPASTFunctionDeclarator.java | 9 ++-- .../dom/parser/cpp/GNUCPPSourceParser.java | 42 ++++--------------- .../rewrite/astwriter/DeclaratorWriter.java | 2 +- .../ModifiedASTDeclaratorWriter.java | 7 ++++ 9 files changed, 71 insertions(+), 49 deletions(-) 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 8dfdb44a7cf..b55ccb29351 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 @@ -5962,4 +5962,28 @@ public class AST2CPPTests extends AST2BaseTest { public void testTypeIdForPtrToMember_Bug242197() throws Exception { parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP); } + + // void test1(); + // void test2() throw (); + // void test3() throw (int); + public void testEmptyExceptionSpecification_Bug86943() throws Exception { + IASTTranslationUnit tu= parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP); + + IASTSimpleDeclaration d= getDeclaration(tu, 0); + ICPPASTFunctionDeclarator fdtor= (ICPPASTFunctionDeclarator) d.getDeclarators()[0]; + IASTTypeId[] specs= fdtor.getExceptionSpecification(); + assertEquals(0, specs.length); + assertSame(ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION, specs); + + d= getDeclaration(tu, 1); + fdtor= (ICPPASTFunctionDeclarator) d.getDeclarators()[0]; + specs= fdtor.getExceptionSpecification(); + assertEquals(0, specs.length); + assertNotSame(ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION, specs); + + d= getDeclaration(tu, 2); + fdtor= (ICPPASTFunctionDeclarator) d.getDeclarators()[0]; + specs= fdtor.getExceptionSpecification(); + assertEquals(1, specs.length); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/remove/ExceptionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/remove/ExceptionTest.java index 1167cb86ec9..aa0d6f03d55 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/remove/ExceptionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/remove/ExceptionTest.java @@ -31,7 +31,7 @@ public class ExceptionTest extends ChangeGeneratorTest { @Override protected void setUp() throws Exception { source = "void foo(int parameter) throw (int){\n}\n\n"; //$NON-NLS-1$ - expectedSource = "void foo(int parameter){\n}\n\n"; //$NON-NLS-1$ + expectedSource = "void foo(int parameter) throw (){\n}\n\n"; //$NON-NLS-1$ super.setUp(); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTStringUtil.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTStringUtil.java index e7e5b869fe5..b5a81617acb 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTStringUtil.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ASTStringUtil.java @@ -295,14 +295,15 @@ public class ASTStringUtil { buffer.append("=0 "); //$NON-NLS-1$ } final IASTTypeId[] exceptionTypeIds= cppFunctionDecl.getExceptionSpecification(); - if (exceptionTypeIds.length > 0) { - buffer.append(Keywords.THROW).append(' '); + if (exceptionTypeIds != ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION) { + buffer.append(Keywords.THROW).append(" ("); //$NON-NLS-1$ for (int i= 0; i < exceptionTypeIds.length; i++) { if (i > 0) { buffer.append(COMMA_SPACE); } appendTypeIdString(buffer, exceptionTypeIds[i]); } + buffer.append(')'); } } } else if (declarator instanceof IASTFieldDeclarator) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java index ef44e2e958b..20e3b037826 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java @@ -22,6 +22,12 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId; */ public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarator { + /** + * Used as return value for {@link #getExceptionSpecification()}. + * @since 5.1 + */ + public static final IASTTypeId[] NO_EXCEPTION_SPECIFICATION = {}; + /** * EXCEPTION_TYPEID represents the type IDs throws in the * exception specification. @@ -60,7 +66,9 @@ public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarato public void setPureVirtual(boolean isPureVirtual); /** - * Get the exception specification. + * Returns an array of type-ids representing the exception specification. The return value + * {@link #NO_EXCEPTION_SPECIFICATION} indicates that no exceptions are specified, whereas + * {@link IASTTypeId#EMPTY_TYPEID_ARRAY} is used for an empty exception specification. */ public IASTTypeId[] getExceptionSpecification(); @@ -69,6 +77,13 @@ public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarato */ public void addExceptionSpecificationTypeId(IASTTypeId typeId); + /** + * Configures the declarator with an empty exception specification (as opposed to having none). + * + * @since 5.1 + */ + public void setEmptyExceptionSpecification(); + /** * Get function scope this node represents. Returns null, if this declarator does not * declare a function-prototype or function-definition. @@ -79,7 +94,7 @@ public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarato @Deprecated public static final ASTNodeProperty CONSTRUCTOR_CHAIN_MEMBER = new ASTNodeProperty( "ICPPASTFunctionDeclarator.CONSTRUCTOR_CHAIN_MEMBER - Role of a Constructor Chain Initializer"); //$NON-NLS-1$ - + /** * @deprecated use {@link ICPPASTFunctionDefinition#getMemberInitializers}, instead. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java index b6ad6c9c1b3..15b0fccb740 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java @@ -284,15 +284,13 @@ public class ArrayUtil { * The position of the last non-null element in the array must also be known. */ public static Object[] removeNullsAfter(Class c, Object[] array, int index) { - if( array == null || index < 0) - return (Object[]) Array.newInstance( c, 0 ); - final int newLen= index+1; - if( array.length == newLen) - return array; + if (array != null && array.length == newLen) + return array; Object[] newArray = (Object[]) Array.newInstance(c, newLen); - System.arraycopy(array, 0, newArray, 0, newLen); + if (array != null && newLen > 0) + System.arraycopy(array, 0, newArray, 0, newLen); return newArray; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java index 52c6e5e2af2..1278656708b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java @@ -29,7 +29,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPASTFunctionDeclarator { private IASTParameterDeclaration[] parameters = null; private int parametersPos = -1; - private IASTTypeId[] typeIds = null; + private IASTTypeId[] typeIds = NO_EXCEPTION_SPECIFICATION; private int typeIdsPos = -1; private boolean varArgs; @@ -86,11 +86,12 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS } public IASTTypeId[] getExceptionSpecification() { - if (typeIds == null) - return IASTTypeId.EMPTY_TYPEID_ARRAY; - return typeIds= ArrayUtil.trimAt(IASTTypeId.class, typeIds, typeIdsPos); } + + public void setEmptyExceptionSpecification() { + typeIds= IASTTypeId.EMPTY_TYPEID_ARRAY; + } public void addExceptionSpecificationTypeId(IASTTypeId typeId) { if (typeId != null) { 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 0465c88132e..fd9a182f803 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 @@ -170,9 +170,7 @@ import org.eclipse.cdt.internal.core.parser.token.TokenFactory; public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { private static final int DEFAULT_PARM_LIST_SIZE = 4; private static final int DEFAULT_POINTEROPS_LIST_SIZE = 4; - private static final int DEFAULT_SIZE_EXCEPTIONS_LIST = 2; private static final int DEFAULT_CATCH_HANDLER_LIST_SIZE= 4; - private static final int DEFAULT_PARAMETER_LIST_SIZE= 4; private static final ASTVisitor EMPTY_VISITOR = new ASTVisitor() {}; private static enum DtorStrategy {PREFER_FUNCTION, PREFER_NESTED} @@ -3434,10 +3432,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { IToken last = consume(IToken.tLPAREN); int startOffset= last.getOffset(); boolean seenParameter= false; - boolean encounteredVarArgs= false; - List parameters= null; int endOffset= last.getEndOffset(); + final ICPPASTFunctionDeclarator fc= createFunctionDeclarator(); paramLoop: while(true) { switch (LT(1)) { case IToken.tRPAREN: @@ -3446,7 +3443,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { break paramLoop; case IToken.tELLIPSIS: endOffset= consume().getEndOffset(); - encounteredVarArgs = true; + fc.setVarArgs(true); break; case IToken.tCOMMA: endOffset= consume().getEndOffset(); @@ -3457,10 +3454,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { throwBacktrack(startOffset, endOffset - startOffset); IASTParameterDeclaration pd = parameterDeclaration(); + fc.addParameterDeclaration(pd); endOffset = calculateEndOffset(pd); - if (parameters == null) - parameters = new ArrayList(DEFAULT_PARAMETER_LIST_SIZE); - parameters.add(pd); seenParameter = true; break; } @@ -3469,20 +3464,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // Consume any number of __attribute__ tokens after the parameters __attribute_decl_seq(supportAttributeSpecifiers, false); - boolean isConst= false; - boolean isVolatile= false; - boolean isPureVirtual= false; - ArrayList exceptionSpecIds= null; - // cv-qualifiers cvloop: while(true) { switch(LT(1)) { case IToken.t_const: - isConst= true; + fc.setConst(true); endOffset= consume().getEndOffset(); break; case IToken.t_volatile: - isVolatile= true; + fc.setVolatile(true); endOffset= consume().getEndOffset(); break; default: @@ -3492,7 +3482,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // throws clause if (LT(1) == IToken.t_throw) { - exceptionSpecIds = new ArrayList(DEFAULT_SIZE_EXCEPTIONS_LIST); + fc.setEmptyExceptionSpecification(); consume(); // throw consume(IToken.tLPAREN); @@ -3509,7 +3499,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { int thoffset= LA(1).getOffset(); IASTTypeId typeId= typeId(DeclarationOptions.TYPEID); if (typeId != null) { - exceptionSpecIds.add(typeId); + fc.addExceptionSpecificationTypeId(typeId); } else { int thendoffset= LA(1).getOffset(); if (thoffset == thendoffset) { @@ -3519,7 +3509,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { IASTProblemTypeId typeIdProblem = createTypeIDProblem(); typeIdProblem.setProblem(p); ((ASTNode) typeIdProblem).setOffsetAndLength(((ASTNode) p)); - exceptionSpecIds.add(typeIdProblem); + fc.addExceptionSpecificationTypeId(typeIdProblem); } break; } @@ -3535,24 +3525,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (image.length == 1 && image[0] == '0') { consume(); // tASSIGN endOffset= consume().getEndOffset(); // tINTEGER - isPureVirtual= true; + fc.setPureVirtual(true); } } - final ICPPASTFunctionDeclarator fc= createFunctionDeclarator(); - fc.setVarArgs(encounteredVarArgs); - fc.setConst(isConst); - fc.setVolatile(isVolatile); - fc.setPureVirtual(isPureVirtual); - if (parameters != null) { - for (IASTParameterDeclaration param : parameters) { - fc.addParameterDeclaration(param); - } - } - if (exceptionSpecIds != null) - for (IASTTypeId exception : exceptionSpecIds) { - fc.addExceptionSpecificationTypeId(exception); - } ((ASTNode) fc).setOffsetAndLength(startOffset, endOffset-startOffset); return fc; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java index e03a5ca6bfd..75380101325 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java @@ -146,7 +146,7 @@ public class DeclaratorWriter extends NodeWriter { } protected void writeExceptionSpecification(ICPPASTFunctionDeclarator funcDec, IASTTypeId[] exceptions) { - if(exceptions.length != 0) { + if (exceptions != ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION) { scribe.printSpace(); scribe.print(THROW); scribe.print('('); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ModifiedASTDeclaratorWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ModifiedASTDeclaratorWriter.java index a7b40f532c3..25297f3b46c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ModifiedASTDeclaratorWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ModifiedASTDeclaratorWriter.java @@ -65,6 +65,13 @@ public class ModifiedASTDeclaratorWriter extends DeclaratorWriter { @Override protected void writeExceptionSpecification(ICPPASTFunctionDeclarator funcDec, IASTTypeId[] exceptions ) { IASTTypeId[] modifiedExceptions = modificationHelper.createModifiedChildArray(funcDec, exceptions, IASTTypeId.class); + // it makes a difference whether the exception array is identical to + // ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION + if (modifiedExceptions.length == 0 && + exceptions == ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION) { + modifiedExceptions= ICPPASTFunctionDeclarator.NO_EXCEPTION_SPECIFICATION; + } + super.writeExceptionSpecification(funcDec, modifiedExceptions); }