diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/AstWriterTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/AstWriterTestSuite.java index 8743e332c5f..d26fe7dddb7 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/AstWriterTestSuite.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/AstWriterTestSuite.java @@ -48,6 +48,7 @@ public class AstWriterTestSuite{ suite.addTest(SourceRewriteTester.suite("CommentTests", "resources/rewrite/ASTWriterCommentedTestSource.awts")); suite.addTest(SourceRewriteTester.suite("NewCommentTests", "resources/rewrite/ASTWriterCommentedTestSource2.awts")); + suite.addTestSuite(ExpressionWriterTest.class); return suite; } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/ExpressionWriterTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/ExpressionWriterTest.java new file mode 100644 index 00000000000..310f6402947 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/astwriter/ExpressionWriterTest.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2010 University of Applied Sciences Rapperswil (HSR). + * 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: Pascal Kesseli (HSR) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.parser.tests.rewrite.astwriter; + +import junit.framework.TestCase; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTCapture; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTCompoundStatement; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTDeclarator; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDeclarator; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLambdaExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeId; +import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriterVisitor; +import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ExpressionWriterTest extends TestCase { + private static final String BR = System.getProperty("line.separator"); + private static CPPASTSimpleDeclSpecifier INT = new CPPASTSimpleDeclSpecifier(); + private static IASTName NO_NAME = new CPPASTName(new char[] {}); + private NodeCommentMap commentMap = new NodeCommentMap(); + private ASTVisitor visitor; + + static { + INT.setType(CPPASTSimpleDeclSpecifier.t_int); + } + + @Override + @Before + protected void setUp() throws Exception { + visitor = new ASTWriterVisitor(commentMap); + } + + @Test + public void testWriteLambdaExpressionEmptyIntroducerNoDeclarator() throws Exception { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.accept(visitor); + String expected = "[] {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(expected, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionDefaultCaptureByCopyNoDeclarator() { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.setCaptureDefault(ICPPASTLambdaExpression.CaptureDefault.BY_COPY); + lambda.accept(visitor); + String expected = "[=] {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(expected, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionDefaultCaptureByReferenceNoDeclarator() { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.setCaptureDefault(ICPPASTLambdaExpression.CaptureDefault.BY_REFERENCE); + lambda.accept(visitor); + String expected = "[&] {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(expected, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionThisCaptureNoDeclarator() { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.addCapture(new CPPASTCapture()); + lambda.accept(visitor); + String expected = "[this] {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(expected, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionMixedCaptureNoDeclarator() { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.setCaptureDefault(ICPPASTLambdaExpression.CaptureDefault.BY_COPY); + lambda.addCapture(new CPPASTCapture()); + ICPPASTCapture x = new CPPASTCapture(), y = new CPPASTCapture(); + x.setIdentifier(new CPPASTName(new char[] { 'x' })); + x.setIsByReference(true); + y.setIdentifier(new CPPASTName(new char[] { 'y' })); + lambda.addCapture(x); + lambda.addCapture(y); + lambda.accept(visitor); + String r = "[=, this, &x, y] {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionEmptyIntroducerSimpleDeclarator() throws Exception { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + lambda.setDeclarator(getSimpleFunctionDeclarator()); + lambda.accept(visitor); + String r = "[](int i, int j) {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionEmptyIntroducerMutableDeclarator() throws Exception { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + ICPPASTFunctionDeclarator f = getSimpleFunctionDeclarator(); + f.setMutable(true); + lambda.setDeclarator(f); + lambda.accept(visitor); + String r = "[](int i, int j) mutable {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionEmptyIntroducerExceptionSpecificationDeclarator() throws Exception { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + ICPPASTFunctionDeclarator f = getSimpleFunctionDeclarator(); + f.addExceptionSpecificationTypeId(new CPPASTTypeId(INT, new CPPASTDeclarator(NO_NAME))); + lambda.setDeclarator(f); + lambda.accept(visitor); + String r = "[](int i, int j) throw (int) {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + @Test + public void testWriteLambdaExpressionEmptyIntroducerTrailingReturnTypeDeclarator() throws Exception { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + ICPPASTFunctionDeclarator f = getSimpleFunctionDeclarator(); + f.setTrailingReturnType(new CPPASTTypeId(INT, new CPPASTDeclarator(NO_NAME))); + lambda.setDeclarator(f); + lambda.accept(visitor); + String r = "[](int i, int j) -> int {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + @Test + public void testWriteAllEmbracingLambdaExpression() { + ICPPASTLambdaExpression lambda = getEmptyLambdaExpression(); + ICPPASTFunctionDeclarator f = getSimpleFunctionDeclarator(); + lambda.setCaptureDefault(ICPPASTLambdaExpression.CaptureDefault.BY_REFERENCE); + ICPPASTCapture x = new CPPASTCapture(), y = new CPPASTCapture(); + x.setIdentifier(new CPPASTName(new char[] { 'x' })); + y.setIdentifier(new CPPASTName(new char[] { 'y' })); + y.setIsByReference(true); + lambda.addCapture(x); + lambda.addCapture(y); + lambda.addCapture(new CPPASTCapture()); + f.setMutable(true); + f.setTrailingReturnType(new CPPASTTypeId(INT, new CPPASTDeclarator(NO_NAME))); + f.addExceptionSpecificationTypeId(new CPPASTTypeId(INT, new CPPASTDeclarator(NO_NAME))); + lambda.setDeclarator(f); + lambda.accept(visitor); + String r = "[&, x, &y, this](int i, int j) mutable throw (int) -> int {" + BR + " return 7;" + BR + "}" + BR; + Assert.assertEquals(r, visitor.toString()); + } + + private static ICPPASTFunctionDeclarator getSimpleFunctionDeclarator() { + ICPPASTFunctionDeclarator f = new CPPASTFunctionDeclarator(new CPPASTName()); + IASTName name = new CPPASTName(new char[] { 'i' }); + IASTDeclarator d = new CPPASTDeclarator(name); + f.addParameterDeclaration(new CPPASTParameterDeclaration(INT, d)); + name = new CPPASTName(new char[] { 'j' }); + d = new CPPASTDeclarator(name); + f.addParameterDeclaration(new CPPASTParameterDeclaration(INT, d)); + return f; + } + + private static ICPPASTLambdaExpression getEmptyLambdaExpression() { + ICPPASTLambdaExpression lambda = new CPPASTLambdaExpression(); + CPPASTCompoundStatement stmt = new CPPASTCompoundStatement(); + stmt.addStatement(new CPPASTReturnStatement(new CPPASTLiteralExpression( + IASTLiteralExpression.lk_integer_constant, + new char[] { '7' }))); + lambda.setBody(stmt); + return lambda; + } +} 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 171f370ee43..53c2655397c 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 @@ -49,6 +49,8 @@ public class DeclaratorWriter extends NodeWriter { private static final String AMPERSAND__AMPERSAND_SPACE = "&& "; //$NON-NLS-1$ private static final String STAR_SPACE = "* "; //$NON-NLS-1$ private static final String PURE_VIRTUAL = " =0"; //$NON-NLS-1$ + private static final String MUTABLE = "mutable"; //$NON-NLS-1$ + private static final String ARROW_OPERATOR = "->"; //$NON-NLS-1$ public DeclaratorWriter(Scribe scribe, ASTVisitor visitor, NodeCommentMap commentMap) { super(scribe, visitor, commentMap); @@ -93,7 +95,10 @@ public class DeclaratorWriter extends NodeWriter { private void writeFunctionDeclarator(IASTStandardFunctionDeclarator funcDec) { IASTPointerOperator[] pointOps = funcDec.getPointerOperators(); writePointerOperators(funcDec, pointOps); - funcDec.getName().accept(visitor); + // XXX: Lambda declarators happen to have null names rather than empty ones when parsed + if (funcDec.getName() != null) { + funcDec.getName().accept(visitor); + } writeNestedDeclarator(funcDec); writeParameters(funcDec); writeInitializer(funcDec); @@ -134,10 +139,20 @@ public class DeclaratorWriter extends NodeWriter { scribe.printSpace(); scribe.print(VOLATILE); } + if (funcDec.isMutable()) { + scribe.printSpace(); + scribe.print(MUTABLE); + } if(funcDec.isPureVirtual()) { scribe.print(PURE_VIRTUAL); } writeExceptionSpecification(funcDec, funcDec.getExceptionSpecification()); + if (funcDec.getTrailingReturnType() != null) { + scribe.printSpace(); + scribe.print(ARROW_OPERATOR); + scribe.printSpace(); + funcDec.getTrailingReturnType().accept(visitor); + } } protected void writeExceptionSpecification(ICPPASTFunctionDeclarator funcDec, IASTTypeId[] exceptions) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ExpressionWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ExpressionWriter.java index 8dbf6b354d0..c72974ca3db 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ExpressionWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ExpressionWriter.java @@ -30,9 +30,11 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeIdExpression; @@ -112,6 +114,9 @@ public class ExpressionWriter extends NodeWriter{ private static final String MODULO_OP = " % "; //$NON-NLS-1$ private static final String DIVIDE_OP = " / "; //$NON-NLS-1$ private static final String MULTIPLY_OP = " * "; //$NON-NLS-1$ + private static final String OPENING_SQUARE_BRACKET = "["; //$NON-NLS-1$ + private static final String CLOSING_SQUARE_BRACKET = "]"; //$NON-NLS-1$ + private static final String THIS = "this"; //$NON-NLS-1$ private final MacroExpansionHandler macroHandler; public ExpressionWriter(Scribe scribe, CPPASTVisitor visitor, MacroExpansionHandler macroHandler, NodeCommentMap commentMap) { @@ -150,6 +155,8 @@ public class ExpressionWriter extends NodeWriter{ writeDeleteExpression((ICPPASTDeleteExpression) expression); }else if (expression instanceof ICPPASTSimpleTypeConstructorExpression) { writeSimpleTypeConstructorExpression((ICPPASTSimpleTypeConstructorExpression) expression); + } else if (expression instanceof ICPPASTLambdaExpression) { + writeLambdaExpression((ICPPASTLambdaExpression) expression); } } @@ -525,5 +532,45 @@ public class ExpressionWriter extends NodeWriter{ simpTypeCtorExp.getDeclSpecifier().accept(visitor); visitNodeIfNotNull(simpTypeCtorExp.getInitializer()); } + + private void writeLambdaExpression(ICPPASTLambdaExpression lambdaExpression) { + writeLambdaIntroducer(lambdaExpression); + if (lambdaExpression.getDeclarator() != null) { + lambdaExpression.getDeclarator().accept(visitor); + } + scribe.printSpace(); + lambdaExpression.getBody().accept(visitor); + } + + private void writeLambdaIntroducer(ICPPASTLambdaExpression lambdaExpression) { + scribe.print(OPENING_SQUARE_BRACKET); + ICPPASTLambdaExpression.CaptureDefault captureDefault = lambdaExpression.getCaptureDefault(); + if (captureDefault.equals(ICPPASTLambdaExpression.CaptureDefault.BY_COPY)) { + scribe.print('='); + } else if (captureDefault.equals(ICPPASTLambdaExpression.CaptureDefault.BY_REFERENCE)) { + scribe.print('&'); + } + for (ICPPASTCapture capture : lambdaExpression.getCaptures()) { + boolean isNotFirst = capture != lambdaExpression.getCaptures()[0]; + boolean hasDefaultCapture = captureDefault != ICPPASTLambdaExpression.CaptureDefault.UNSPECIFIED; + if (isNotFirst || hasDefaultCapture) { + scribe.print(COMMA_SPACE); + } + writeCapture(capture); + } + scribe.print(CLOSING_SQUARE_BRACKET); + } + + private void writeCapture(ICPPASTCapture capture) { + if (capture.capturesThisPointer()) { + scribe.print(THIS); + } else { + if (capture.isByReference()) { + scribe.print(AMPERSAND_OP); + } + capture.getIdentifier().accept(visitor); + } + } + }