From d8a536d6f64eae65273b5c24881aad1b4fb3b8e5 Mon Sep 17 00:00:00 2001 From: Benjamin DANGLOT Date: Mon, 31 Oct 2016 13:10:36 +0100 Subject: [PATCH] fix(performance): keep shadow classes (closes #867) --- .../spoon/reflect/factory/TypeFactory.java | 24 +++++++- src/test/java/spoon/test/type/TypeTest.java | 60 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/main/java/spoon/reflect/factory/TypeFactory.java b/src/main/java/spoon/reflect/factory/TypeFactory.java index 43e9dd63321..d0e1e0ae016 100644 --- a/src/main/java/spoon/reflect/factory/TypeFactory.java +++ b/src/main/java/spoon/reflect/factory/TypeFactory.java @@ -19,6 +19,7 @@ import spoon.reflect.code.CtNewClass; import spoon.reflect.declaration.CtAnnotation; import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtPackage; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeParameter; @@ -26,6 +27,7 @@ import spoon.reflect.reference.CtIntersectionTypeReference; import spoon.reflect.reference.CtTypeParameterReference; import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.CtScanner; import spoon.reflect.visitor.filter.TypeFilter; import spoon.support.DefaultCoreFactory; import spoon.support.StandardEnvironment; @@ -36,8 +38,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import static spoon.testing.utils.ModelUtils.createFactory; @@ -76,6 +80,8 @@ public class TypeFactory extends SubFactory { public final CtTypeReference DATE = createReference(Date.class); public final CtTypeReference OBJECT = createReference(Object.class); + private final Map, CtType> shadowCache = new HashMap<>(); + /** * Returns a reference on the null type (type of null). */ @@ -465,7 +471,23 @@ private void addNestedType(List> list, CtType t) { public CtType get(Class cl) { final CtType aType = get(cl.getName()); if (aType == null) { - return new JavaReflectionTreeBuilder(createFactory()).scan((Class) cl); + final CtType shadowClass = (CtType) this.shadowCache.get(cl); + if (shadowClass == null) { + final CtType newShadowClass = new JavaReflectionTreeBuilder(createFactory()).scan((Class) cl); + newShadowClass.setFactory(factory); + newShadowClass.accept(new CtScanner() { + @Override + public void scan(CtElement element) { + if (element != null) { + element.setFactory(factory); + } + } + }); + this.shadowCache.put(cl, newShadowClass); + return newShadowClass; + } else { + return shadowClass; + } } return aType; } diff --git a/src/test/java/spoon/test/type/TypeTest.java b/src/test/java/spoon/test/type/TypeTest.java index 29cc8fef89f..3c329313146 100644 --- a/src/test/java/spoon/test/type/TypeTest.java +++ b/src/test/java/spoon/test/type/TypeTest.java @@ -40,12 +40,15 @@ import spoon.test.type.testclasses.Pozole; import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static spoon.testing.utils.ModelUtils.buildClass; @@ -294,4 +297,61 @@ public boolean matches(CtConstructorCall element) { }).get(0); assertEquals(launcher.getFactory().Type().objectType(), ctConstructorCall.getExecutable().getParameters().get(9)); } + + @Test + public void testShadowType() throws Exception { + + /* Objects and factory have to be the sames */ + + Launcher launcher = new Launcher(); + launcher.buildModel(); + + final CtClass objectCtClass = launcher.getFactory().Class().get(Object.class); + final CtClass objectCtClass1 = launcher.getFactory().Class().get(Object.class); + + assertSame(objectCtClass, objectCtClass1); + + assertSame(launcher.getFactory().Class(), objectCtClass.getFactory().Class()); + assertSame(launcher.getFactory(), objectCtClass.getFactory()); + + assertSame(launcher.getFactory().Class(), objectCtClass1.getFactory().Class()); + assertSame(launcher.getFactory(), objectCtClass1.getFactory()); + + assertSame(objectCtClass.getFactory().Class().get(objectCtClass.getActualClass()), objectCtClass); + assertSame(objectCtClass.getFactory().Class().get(Object.class), objectCtClass); + + assertSame(objectCtClass1.getFactory().Class().get(objectCtClass1.getActualClass()), objectCtClass1); + assertSame(objectCtClass1.getFactory().Class().get(Object.class), objectCtClass1); + + assertTrue(objectCtClass.isShadow()); + assertEquals("java.lang.Object", objectCtClass.getQualifiedName()); + + final CtType objectCtType = launcher.getFactory().Type().get(Object.class); + final CtType objectCtType1 = launcher.getFactory().Type().get(Object.class); + + assertSame(objectCtType, objectCtType1); + + assertSame(launcher.getFactory().Type(), objectCtType.getFactory().Type()); + assertSame(launcher.getFactory(), objectCtType.getFactory()); + + assertSame(launcher.getFactory().Type(), objectCtType1.getFactory().Type()); + assertSame(launcher.getFactory(), objectCtType1.getFactory()); + + assertSame(objectCtType.getFactory().Type().get(objectCtType.getActualClass()), objectCtType); + assertSame(objectCtType.getFactory().Type().get(Object.class), objectCtType); + + assertSame(objectCtType1.getFactory().Type().get(objectCtType1.getActualClass()), objectCtType1); + assertSame(objectCtType1.getFactory().Type().get(Object.class), objectCtType1); + + assertTrue(objectCtClass.isShadow()); + assertEquals("java.lang.Object", objectCtClass.getQualifiedName()); + + final List methodNameList = Arrays.asList(Object.class.getDeclaredMethods()).stream().map(Method::getName).collect(Collectors.toList()); + + for (CtMethod ctMethod : objectCtClass.getMethods()) { + assertTrue(methodNameList.contains(ctMethod.getSimpleName())); + assertTrue(ctMethod.getBody().getStatements().isEmpty()); + } + + } }