/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eclipse.jdt.core.groovy.tests.model; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.codehaus.groovy.ast.ClassCodeVisitorSupport; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ConstructorNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.expr.ClosureExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.ast.stmt.BlockStatement; import org.codehaus.groovy.ast.stmt.Statement; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.JavaCore; import org.junit.Ignore; import org.junit.Test; public final class GroovyPartialModelTests extends GroovyTypeRootTestSuite { @Test // tests that a static field's initializer is not erased during a reconcile public void testStaticFieldInitializerIsNotMoved1() throws Exception { findFieldInitializer("package p1\n"+ "public class Hello {\n"+ " static aStatic = []\n" + "}\n", ListExpression.class); } @Test // tests that a static field's initializer is not erased during a reconcile public void testStaticFieldInitializerIsNotMoved2() throws Exception { findFieldInitializer("package p1\n"+ "public class Hello {\n"+ " static aStatic = {}\n" + "}\n", ClosureExpression.class); } @Test @Ignore // tests that a non-static field initializer is not erased during a reconcile public void testFieldInitializerIsNotMoved1() throws Exception { findFieldInitializer("package p1\n"+ "public class Hello {\n"+ " def aStatic = []\n" + "}\n", ListExpression.class); } @Test @Ignore // tests that a non-static field initializer is not erased during a reconcile public void testFieldInitializerIsNotMoved2() throws Exception { findFieldInitializer("package p1\n"+ "public class Hello {\n"+ " def aStatic = {}\n" + "}\n", ClosureExpression.class); } @Test public void testClosureReturner() throws Exception { IProject project = createSimpleGroovyProject().getProject(); env.addGroovyClass(project.getFullPath().append("src"), "p1", "Hello2", "class C { def aaa = { 123 } }"); IFile javaFile = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("Project/src/p1/Hello2.groovy")); GroovyCompilationUnit unit = (GroovyCompilationUnit) JavaCore.createCompilationUnitFrom(javaFile); ClassNode inClass = unit.getModuleNode().getClasses().get(0); FieldNode field = inClass.getField("aaa"); Expression initialExpression = field.getInitialExpression(); ClosureExpression cEx = (ClosureExpression)initialExpression; BlockStatement bSt = (BlockStatement) cEx.getCode(); Statement st = bSt.getStatements().get(0); assertEquals("org.codehaus.groovy.ast.stmt.ReturnStatement",st.getClass().getName()); } //-------------------------------------------------------------------------- private Expression findFieldInitializer(String contents, Class<? extends Expression> expressionClass) throws Exception { IProject project = createSimpleGroovyProject().getProject(); env.addGroovyClass(project.getFullPath().append("src"), "p1", "Hello2", contents); IFile javaFile = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path("Project/src/p1/Hello2.groovy")); GroovyCompilationUnit unit = (GroovyCompilationUnit) JavaCore.createCompilationUnitFrom(javaFile); ClassNode inClass = unit.getModuleNode().getClasses().get(0); FieldNode field = inClass.getField("aStatic"); Expression initialExpression = field.getInitialExpression(); assertNotNull(initialExpression); assertTrue(expressionClass.isInstance(initialExpression)); checkClinitAndAllConstructors(initialExpression, inClass); return initialExpression; } private void checkClinitAndAllConstructors(Expression expr, ClassNode inClass) { for (ConstructorNode cons : inClass.getDeclaredConstructors()) { assertUnique(expr, cons); } MethodNode clinit = inClass.getMethod("<clinit>", Parameter.EMPTY_ARRAY); if (clinit!=null) { assertUnique(expr, clinit); } } // asserts that the given expression has not been copied into the constructor // and so makes sure that this expression appears only once in the AST private void assertUnique(Expression expr, MethodNode cons) { UniquenessVisitor visitor = new UniquenessVisitor(expr); visitor.visitMethod(cons); } // Only checks for ClosureExpressions and ListExpressions, but we can easily add more private static class UniquenessVisitor extends ClassCodeVisitorSupport { public UniquenessVisitor(Expression exprToCheck) { this.exprToCheck = exprToCheck; } private final Expression exprToCheck; @Override public void visitListExpression(ListExpression expression) { doCheck(expression); super.visitListExpression(expression); } @Override public void visitClosureExpression(ClosureExpression expression) { doCheck(expression); super.visitClosureExpression(expression); } void doCheck(Expression expr) { assertFalse ("Expression appears twice. Once in constructor and once in field initializer.\nExpr: " + expr, expr == exprToCheck); } } }