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);
}