From 671e44398372d84e1ad9d69f9acb2d0d2e7b8ac8 Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Tue, 16 Aug 2016 11:11:34 +0200 Subject: [PATCH 1/5] fix(array): Allows array in an array. --- .../spoon/support/compiler/jdt/ParentExiter.java | 3 ++- src/test/java/spoon/test/arrays/ArraysTest.java | 14 ++++++++++++++ .../java/spoon/test/arrays/testclasses/Foo.java | 11 +++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/java/spoon/test/arrays/testclasses/Foo.java diff --git a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java index 2737d0cd60b..cb2a8e4b0a6 100644 --- a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java +++ b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java @@ -22,6 +22,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.CaseStatement; import org.eclipse.jdt.internal.compiler.ast.CastExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; @@ -612,7 +613,7 @@ public void visitCtNewArray(CtNewArray newArray) { } else if (child instanceof CtExpression) { if (isContainedInDimensionExpression()) { newArray.addDimensionExpression((CtExpression) child); - } else if (child instanceof CtNewArray) { + } else if (child instanceof CtNewArray && childJDT instanceof ArrayInitializer && jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ArrayAllocationExpression) { newArray.setElements(((CtNewArray) child).getElements()); } else { newArray.addElement((CtExpression) child); diff --git a/src/test/java/spoon/test/arrays/ArraysTest.java b/src/test/java/spoon/test/arrays/ArraysTest.java index 4f7d972ba35..4ed9b42ce7b 100644 --- a/src/test/java/spoon/test/arrays/ArraysTest.java +++ b/src/test/java/spoon/test/arrays/ArraysTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static spoon.testing.utils.ModelUtils.build; public class ArraysTest { @@ -62,4 +63,17 @@ public void testInitializeWithNewArray() throws Exception { assertEquals("new Type[list.size()]", local.toString()); } + @Test + public void testCtNewArrayInnerCtNewArray() throws Exception { + final Launcher launcher = new Launcher(); + launcher.addInputResource("src/test/java/spoon/test/arrays/testclasses/Foo.java"); + launcher.setSourceOutputDirectory("target/foo"); + launcher.buildModel(); + launcher.prettyprint(); + try { + launcher.getModelBuilder().compile(); + } catch (Exception e) { + fail(); + } + } } diff --git a/src/test/java/spoon/test/arrays/testclasses/Foo.java b/src/test/java/spoon/test/arrays/testclasses/Foo.java new file mode 100644 index 00000000000..c338fd8dcc4 --- /dev/null +++ b/src/test/java/spoon/test/arrays/testclasses/Foo.java @@ -0,0 +1,11 @@ +package spoon.test.arrays.testclasses; + +public class Foo { + String[] s = new String[] { "--help" }; + protected static final int grad4[][] = { + { 0, 1, 1, 1 }, { 0, 1, 1, -1 }, { 0, 1, -1, 1 }, { 0, 1, -1, -1 }, { 0, -1, 1, 1 }, { 0, -1, 1, -1 }, { 0, -1, -1, 1 }, { 0, -1, -1, -1 }, { 1, 0, 1, 1 }, { 1, 0, 1, -1 }, + { 1, 0, -1, 1 }, { 1, 0, -1, -1 }, { -1, 0, 1, 1 }, { -1, 0, 1, -1 }, { -1, 0, -1, 1 }, { -1, 0, -1, -1 }, { 1, 1, 0, 1 }, { 1, 1, 0, -1 }, { 1, -1, 0, 1 }, { 1, -1, 0, -1 }, + { -1, 1, 0, 1 }, { -1, 1, 0, -1 }, { -1, -1, 0, 1 }, { -1, -1, 0, -1 }, { 1, 1, 1, 0 }, { 1, 1, -1, 0 }, { 1, -1, 1, 0 }, { 1, -1, -1, 0 }, { -1, 1, 1, 0 }, { -1, 1, -1, 0 }, + { -1, -1, 1, 0 }, { -1, -1, -1, 0 } + }; +} From 750c5f38c31f79cda2df3585a9f744c95fae606a Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Tue, 16 Aug 2016 14:48:23 +0200 Subject: [PATCH 2/5] fix(array): Builds dimensions with casts. --- src/main/java/spoon/support/compiler/jdt/ParentExiter.java | 4 ++-- src/test/java/spoon/test/arrays/ArraysTest.java | 2 +- src/test/java/spoon/test/arrays/testclasses/Foo.java | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java index cb2a8e4b0a6..f350106a69f 100644 --- a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java +++ b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java @@ -630,7 +630,7 @@ private boolean isContainedInDimensionExpression() { return false; } for (Expression dimension : parent.dimensions) { - if (dimension != null && dimension.equals(childJDT)) { + if (dimension != null && getFinalExpressionFromCast(dimension).equals(childJDT)) { return true; } } @@ -663,7 +663,7 @@ private boolean hasChildEqualsToEnclosingInstance(CtConstructorCall ctCon } final QualifiedAllocationExpression parent = (QualifiedAllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node; // Enclosing instance is equals to the jdt child. - return parent.enclosingInstance != null && parent.enclosingInstance.equals(childJDT) + return parent.enclosingInstance != null && getFinalExpressionFromCast(parent.enclosingInstance).equals(childJDT) // Enclosing instance not yet initialized. && !child.equals(ctConstructorCall.getTarget()); } diff --git a/src/test/java/spoon/test/arrays/ArraysTest.java b/src/test/java/spoon/test/arrays/ArraysTest.java index 4ed9b42ce7b..bf89027ff74 100644 --- a/src/test/java/spoon/test/arrays/ArraysTest.java +++ b/src/test/java/spoon/test/arrays/ArraysTest.java @@ -73,7 +73,7 @@ public void testCtNewArrayInnerCtNewArray() throws Exception { try { launcher.getModelBuilder().compile(); } catch (Exception e) { - fail(); + fail(e.getMessage()); } } } diff --git a/src/test/java/spoon/test/arrays/testclasses/Foo.java b/src/test/java/spoon/test/arrays/testclasses/Foo.java index c338fd8dcc4..5a97b8bc499 100644 --- a/src/test/java/spoon/test/arrays/testclasses/Foo.java +++ b/src/test/java/spoon/test/arrays/testclasses/Foo.java @@ -1,6 +1,12 @@ package spoon.test.arrays.testclasses; +import java.io.EOFException; + public class Foo { + public byte[] readByteArray(long byteCount) throws EOFException { + byte[] result = new byte[(int) byteCount]; + return result; + } String[] s = new String[] { "--help" }; protected static final int grad4[][] = { { 0, 1, 1, 1 }, { 0, 1, 1, -1 }, { 0, 1, -1, 1 }, { 0, 1, -1, -1 }, { 0, -1, 1, 1 }, { 0, -1, 1, -1 }, { 0, -1, -1, 1 }, { 0, -1, -1, -1 }, { 1, 0, 1, 1 }, { 1, 0, 1, -1 }, From 01eb83d86b0cae09cfdb7b9acdcfa5210e5b0667 Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Tue, 16 Aug 2016 16:31:34 +0200 Subject: [PATCH 3/5] fix(executable): Allows block in executable. --- .../spoon/support/compiler/jdt/JDTTreeBuilder.java | 6 ++---- .../java/spoon/support/compiler/jdt/ParentExiter.java | 10 ++++++++-- .../java/spoon/test/executable/ExecutableTest.java | 11 +++++++++++ .../spoon/test/executable/testclasses/Pozole.java | 8 ++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java index 90f392a233d..d3373de5880 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilder.java @@ -940,8 +940,7 @@ public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { // Create block if (!methodDeclaration.isAbstract() && (methodDeclaration.modifiers & ClassFileConstants.AccNative) == 0) { - m.setBody(getFactory().Core().createBlock()); - context.enter(m.getBody(), methodDeclaration); + context.enter(getFactory().Core().createBlock(), methodDeclaration); context.exit(methodDeclaration); } @@ -955,8 +954,7 @@ public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope s context.enter(c, constructorDeclaration); // Create block - c.setBody(factory.Core().createBlock()); - context.enter(c.getBody(), constructorDeclaration); + context.enter(factory.Core().createBlock(), constructorDeclaration); context.exit(constructorDeclaration); return true; diff --git a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java index f350106a69f..3859f0afbb1 100644 --- a/src/main/java/spoon/support/compiler/jdt/ParentExiter.java +++ b/src/main/java/spoon/support/compiler/jdt/ParentExiter.java @@ -257,7 +257,10 @@ public void visitCtAnnotation(CtAnno @Override public void visitCtConstructor(CtConstructor e) { - if (child instanceof CtStatement && !(child instanceof CtBlock)) { + if (e.getBody() == null && child instanceof CtBlock) { + e.setBody((CtBlock) child); + return; + } else if (child instanceof CtStatement) { visitCtBlock(e.getBody()); return; } @@ -266,7 +269,10 @@ public void visitCtConstructor(CtConstructor e) { @Override public void visitCtMethod(CtMethod e) { - if (child instanceof CtStatement && !(child instanceof CtBlock)) { + if (e.getBody() == null && child instanceof CtBlock) { + e.setBody((CtBlock) child); + return; + } else if (child instanceof CtStatement) { visitCtBlock(e.getBody()); return; } else if (child instanceof CtTypeAccess && hasChildEqualsToType(e)) { diff --git a/src/test/java/spoon/test/executable/ExecutableTest.java b/src/test/java/spoon/test/executable/ExecutableTest.java index 59ae699d579..74bb78001e6 100644 --- a/src/test/java/spoon/test/executable/ExecutableTest.java +++ b/src/test/java/spoon/test/executable/ExecutableTest.java @@ -2,13 +2,18 @@ import org.junit.Test; import spoon.Launcher; +import spoon.reflect.code.CtBlock; import spoon.reflect.declaration.CtAnonymousExecutable; +import spoon.reflect.declaration.CtType; import spoon.reflect.visitor.Query; import spoon.reflect.visitor.filter.TypeFilter; +import spoon.test.executable.testclasses.Pozole; +import spoon.testing.utils.ModelUtils; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class ExecutableTest { @Test @@ -29,4 +34,10 @@ public void testInfoInsideAnonymousExecutable() throws Exception { assertEquals(0, anonymousExecutable.getThrownTypes().size()); } } + + @Test + public void testBlockInExecutable() throws Exception { + final CtType aPozole = ModelUtils.buildClass(Pozole.class); + assertTrue(aPozole.getMethod("m").getBody().getStatement(1) instanceof CtBlock); + } } diff --git a/src/test/java/spoon/test/executable/testclasses/Pozole.java b/src/test/java/spoon/test/executable/testclasses/Pozole.java index 84bf45e14e9..d1aa41b9fa0 100644 --- a/src/test/java/spoon/test/executable/testclasses/Pozole.java +++ b/src/test/java/spoon/test/executable/testclasses/Pozole.java @@ -9,4 +9,12 @@ public void cook() { public void run() { } + + void m() { + int i; + { + i = 0; + } + int x = 2 * i; + } } From 40981776d17e51b9a3ebbb42775cc3a62a2adf7a Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Wed, 17 Aug 2016 11:03:20 +0200 Subject: [PATCH 4/5] fix(access): Qualified field access with import static. --- .../compiler/jdt/JDTTreeBuilderHelper.java | 2 +- .../java/spoon/test/imports/ImportTest.java | 17 +++++++++++++++++ .../spoon/test/imports/testclasses/Tacos.java | 9 +++++++++ .../testclasses/internal4/Constants.java | 5 +++++ .../test/imports/testclasses/internal4/Foo.java | 5 +++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/test/java/spoon/test/imports/testclasses/Tacos.java create mode 100644 src/test/java/spoon/test/imports/testclasses/internal4/Constants.java create mode 100644 src/test/java/spoon/test/imports/testclasses/internal4/Foo.java diff --git a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderHelper.java b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderHelper.java index f946b62cd18..5ff57276244 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderHelper.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTTreeBuilderHelper.java @@ -384,7 +384,7 @@ public boolean onAccess(char[][] tokens, int index) { typeAccess.setPosition( jdtTreeBuilder.getPositionBuilder().buildPosition(qualifiedNameReference.sourceStart(), (int) (positions[qualifiedNameReference.indexOfFirstFieldBinding - 1] >>> 32) - 2)); } else { - typeAccess.setImplicit(true); + typeAccess.setImplicit(qualifiedNameReference.isImplicitThis()); } return typeAccess; diff --git a/src/test/java/spoon/test/imports/ImportTest.java b/src/test/java/spoon/test/imports/ImportTest.java index fb5d7e8f1b9..32454d6b2a6 100644 --- a/src/test/java/spoon/test/imports/ImportTest.java +++ b/src/test/java/spoon/test/imports/ImportTest.java @@ -7,6 +7,8 @@ import spoon.compiler.SpoonResourceHelper; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtInvocation; +import spoon.reflect.code.CtLocalVariable; +import spoon.reflect.code.CtStatement; import spoon.reflect.code.CtThisAccess; import spoon.reflect.code.CtTypeAccess; import spoon.reflect.declaration.CtClass; @@ -25,6 +27,7 @@ import spoon.test.imports.testclasses.NotImportExecutableType; import spoon.test.imports.testclasses.Pozole; import spoon.test.imports.testclasses.SubClass; +import spoon.test.imports.testclasses.Tacos; import spoon.test.imports.testclasses.internal.ChildClass; import java.util.Arrays; @@ -261,6 +264,20 @@ public void testImportOfInvocationOfStaticMethod() throws Exception { assertEquals("spoon.test.imports.testclasses.internal2.Menudo", imports.toArray()[0].toString()); } + @Test + public void testImportStaticAndFieldAccess() throws Exception { + // contract: Qualified field access and an import static should rewrite in fully qualified mode. + final Launcher launcher = new Launcher(); + launcher.addInputResource("./src/test/java/spoon/test/imports/testclasses/internal4/"); + launcher.addInputResource("./src/test/java/spoon/test/imports/testclasses/Tacos.java"); + launcher.buildModel(); + + final CtType aTacos = launcher.getFactory().Type().get(Tacos.class); + final CtStatement assignment = aTacos.getMethod("m").getBody().getStatement(0); + assertTrue(assignment instanceof CtLocalVariable); + assertEquals("spoon.test.imports.testclasses.internal4.Constants.CONSTANT.foo", ((CtLocalVariable) assignment).getAssignment().toString()); + } + private Factory getFactory(String...inputs) { final Launcher launcher = new Launcher(); for (String input : inputs) { diff --git a/src/test/java/spoon/test/imports/testclasses/Tacos.java b/src/test/java/spoon/test/imports/testclasses/Tacos.java new file mode 100644 index 00000000000..e3ff084f9a3 --- /dev/null +++ b/src/test/java/spoon/test/imports/testclasses/Tacos.java @@ -0,0 +1,9 @@ +package spoon.test.imports.testclasses; + +import static spoon.test.imports.testclasses.internal4.Constants.*; + +public class Tacos { + void m() { + int i = CONSTANT.foo; + } +} diff --git a/src/test/java/spoon/test/imports/testclasses/internal4/Constants.java b/src/test/java/spoon/test/imports/testclasses/internal4/Constants.java new file mode 100644 index 00000000000..53953fca76f --- /dev/null +++ b/src/test/java/spoon/test/imports/testclasses/internal4/Constants.java @@ -0,0 +1,5 @@ +package spoon.test.imports.testclasses.internal4; + +public interface Constants { + Foo CONSTANT = new Foo(); +} diff --git a/src/test/java/spoon/test/imports/testclasses/internal4/Foo.java b/src/test/java/spoon/test/imports/testclasses/internal4/Foo.java new file mode 100644 index 00000000000..eb2af2e4ecf --- /dev/null +++ b/src/test/java/spoon/test/imports/testclasses/internal4/Foo.java @@ -0,0 +1,5 @@ +package spoon.test.imports.testclasses.internal4; + +public class Foo { + public int foo; +} From 4b106a3e1c9c462248203bff0746f51418fc9801 Mon Sep 17 00:00:00 2001 From: GerardPaligot Date: Wed, 17 Aug 2016 12:25:38 +0200 Subject: [PATCH 5/5] fix(actual): Rewrite actual types with their enclosing class. --- .../visitor/DefaultJavaPrettyPrinter.java | 3 ++ .../test/reference/TypeReferenceTest.java | 15 ++++++++ .../test/reference/testclasses/Panini.java | 34 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 src/test/java/spoon/test/reference/testclasses/Panini.java diff --git a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java index d06b7dfc316..71d3727c2de 100644 --- a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java +++ b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java @@ -1679,7 +1679,10 @@ private void visitCtTypeReference(CtTypeReference ref, boolean withGenerics) printer.write(ref.getSimpleName()); } if (withGenerics && !context.ignoreGenerics) { + final boolean old = context.ignoreEnclosingClass; + context.ignoreEnclosingClass = false; elementPrinterHelper.writeActualTypeArguments(ref); + context.ignoreEnclosingClass = old; } } diff --git a/src/test/java/spoon/test/reference/TypeReferenceTest.java b/src/test/java/spoon/test/reference/TypeReferenceTest.java index 82435bdbc15..f7c6998691c 100644 --- a/src/test/java/spoon/test/reference/TypeReferenceTest.java +++ b/src/test/java/spoon/test/reference/TypeReferenceTest.java @@ -7,9 +7,12 @@ import spoon.compiler.SpoonResource; import spoon.compiler.SpoonResourceHelper; import spoon.reflect.code.CtConstructorCall; +import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtFieldRead; import spoon.reflect.code.CtInvocation; import spoon.reflect.code.CtNewClass; +import spoon.reflect.code.CtReturn; +import spoon.reflect.code.CtStatement; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtInterface; @@ -25,6 +28,7 @@ import spoon.reflect.visitor.filter.ReferenceTypeFilter; import spoon.reflect.visitor.filter.TypeFilter; import spoon.test.reference.testclasses.EnumValue; +import spoon.test.reference.testclasses.Panini; import spoon.testing.utils.ModelUtils; import java.util.ArrayList; @@ -40,6 +44,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static spoon.testing.utils.ModelUtils.buildClass; import static spoon.testing.utils.ModelUtils.canBeBuilt; import static spoon.testing.utils.ModelUtils.createFactory; @@ -498,6 +503,16 @@ public void testReferenceName() throws Exception { typeReference.setSimpleName("?"); } + @Test + public void testIgnoreEnclosingClassInActualTypes() throws Exception { + final CtType aPanini = buildClass(Panini.class); + final CtStatement ctReturn = aPanini.getMethod("entryIterator").getBody().getStatement(0); + assertTrue(ctReturn instanceof CtReturn); + final CtExpression ctConstructorCall = ((CtReturn) ctReturn).getReturnedExpression(); + assertTrue(ctConstructorCall instanceof CtConstructorCall); + assertEquals("spoon.test.reference.testclasses.Panini.Itr>", ctConstructorCall.getType().toString()); + } + class A { class Tacos { } diff --git a/src/test/java/spoon/test/reference/testclasses/Panini.java b/src/test/java/spoon/test/reference/testclasses/Panini.java new file mode 100644 index 00000000000..5db58ed3174 --- /dev/null +++ b/src/test/java/spoon/test/reference/testclasses/Panini.java @@ -0,0 +1,34 @@ +package spoon.test.reference.testclasses; + +import java.util.Iterator; +import java.util.Map; + +public class Panini { + Iterator> entryIterator() { + return new Itr>() { + @Override + Map.Entry output(K key, V value) { + return null; + } + }; + } + + private abstract class Itr implements Iterator { + @Override + public T next() { + return null; + } + + @Override + public boolean hasNext() { + return false; + } + + @Override + public void remove() { + + } + + abstract T output(K key, V value); + } +}