From b4b709298107a609b949435706c830f980d6522c Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Wed, 22 Feb 2017 21:01:53 +0100 Subject: [PATCH 1/3] feature: SuperHierarchyFunction --- .../filter/SuperHierarchyFunction.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java diff --git a/src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java b/src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java new file mode 100644 index 00000000000..094890a302b --- /dev/null +++ b/src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java @@ -0,0 +1,195 @@ +/** + * Copyright (C) 2006-2017 INRIA and contributors + * Spoon - http://spoon.gforge.inria.fr/ + * + * This software is governed by the CeCILL-C License under French law and + * abiding by the rules of distribution of free software. You can use, modify + * and/or redistribute the software under the terms of the CeCILL-C license as + * circulated by CEA, CNRS and INRIA at http://www.cecill.info. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +package spoon.reflect.visitor.filter; + +import java.util.Set; + +import spoon.reflect.declaration.CtAnnotationType; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtInterface; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeParameter; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.chain.CtConsumableFunction; +import spoon.reflect.visitor.chain.CtConsumer; +import spoon.reflect.visitor.chain.CtQuery; +import spoon.reflect.visitor.chain.CtQueryAware; +import spoon.support.SpoonClassNotFoundException; + +/** + * Expects a {@link CtType} as input + * and produces all super classes and super interfaces recursively.
+ * The output is produced in following order: + *
    + *
  1. input type. if `includingSelf==true` + *
  2. all interfaces of type recursively + *
  3. parent class of type + *
  4. goto 1: using parent class as input type + *
+ */ +public class SuperHierarchyFunction implements CtConsumableFunction>, CtQueryAware { + private boolean includingSelf = false; + private boolean includingInterfaces = true; + private Set visitedSet; + private CtQuery query; + private boolean failOnClassNotFound = false; + + /** + * The mapping function create using this constructor + * will visit each super class and super interface + * following super hierarchy. It can happen + * that some interfaces will be visited more then once + * if they are in hierarchy more then once.
+ * Use second constructor if you want to visit each interface only once. + */ + public SuperHierarchyFunction() { + } + + /** + * @param visitedSet assures that each class/interface is visited only once + */ + public SuperHierarchyFunction(Set visitedSet) { + this.visitedSet = visitedSet; + } + + /** + * @param includingSelf if true then input element is sent to output too. By default it is false. + */ + public SuperHierarchyFunction includingSelf(boolean includingSelf) { + this.includingSelf = includingSelf; + return this; + } + + /** + * @param includingInterfaces if false then interfaces are not visited - only super classes. By default it is true. + */ + public SuperHierarchyFunction includingInterfaces(boolean includingInterfaces) { + this.includingInterfaces = includingInterfaces; + return this; + } + + @Override + public void apply(CtType input, CtConsumer outputConsumer) { + if (includingSelf) { + if (canVisitType(input.getQualifiedName()) == false) { + return; + } + outputConsumer.accept(input); + if (query.isTerminated()) { + return; + } + } + if (input instanceof CtClass) { + visitSuperClasses(input, outputConsumer, includingInterfaces); + } else if (input instanceof CtInterface) { + visitSuperInterfaces(input, outputConsumer); + } else if (input instanceof CtAnnotationType) { + return; + } else if (input instanceof CtTypeParameter) { + visitSuperClasses(input, outputConsumer, false); + } + } + + /** + * calls `outputConsumer.accept(superClass)` all super classes of superType. + * + * @param includingInterfaces if true then all superInterfaces of each type are sent to `outputConsumer` too. + */ + protected void visitSuperClasses(CtType superType, CtConsumer outputConsumer, boolean includingInterfaces) { + while (true) { + if (includingInterfaces) { + if (visitSuperInterfaces(superType, outputConsumer) == false) { + return; + } + } + CtTypeReference superClassRef = superType.getSuperclass(); + if (superClassRef == null) { + if (superType instanceof CtClass) { + // only CtCLasses extend object, so visit Object too + superType = superType.getFactory().Type().get(Object.class); + if (canVisitType(Object.class.getName())) { + outputConsumer.accept(superType); + } + } + return; + } + if (canVisitType(superClassRef.getQualifiedName()) == false) { + return; + } + try { + superType = superClassRef.getTypeDeclaration(); + } catch (SpoonClassNotFoundException e) { + if (failOnClassNotFound) { + throw e; + } + } + outputConsumer.accept(superType); + if (query.isTerminated()) { + return; + } + } + } + + /** + * calls `outputConsumer.accept(interface)` for all superInterfaces of type recursively. + * @return false if query is terminated + */ + protected boolean visitSuperInterfaces(CtType type, CtConsumer outputConsumer) { + for (CtTypeReference ifaceRef : type.getSuperInterfaces()) { + if (canVisitType(ifaceRef.getQualifiedName()) == false) { + continue; + } + CtType superType; + try { + superType = ifaceRef.getTypeDeclaration(); + } catch (SpoonClassNotFoundException e) { + if (failOnClassNotFound) { + throw e; + } + continue; + } + if (superType == null) { + continue; + } + outputConsumer.accept(superType); + if (query.isTerminated()) { + return false; + } + if (visitSuperInterfaces(superType, outputConsumer) == false) { + return false; + } + } + return true; + } + + protected boolean canVisitType(String qualifiedName) { + if (visitedSet != null) { + return visitedSet.add(qualifiedName); + } + return true; + } + + @Override + public void setQuery(CtQuery query) { + this.query = query; + } + + public SuperHierarchyFunction failOnClassNotFound(boolean failOnClassNotFound) { + this.failOnClassNotFound = failOnClassNotFound; + return this; + } +} From 987f868754f87573a0efbd990530b93bcd6c8dcb Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Wed, 22 Feb 2017 21:37:18 +0100 Subject: [PATCH 2/3] feature: AllTypeMembersFunction --- .../filter/AllTypeMembersFunction.java | 85 ++++++++++++++++++ .../reflect/declaration/CtTypeImpl.java | 89 +++++-------------- 2 files changed, 106 insertions(+), 68 deletions(-) create mode 100644 src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java diff --git a/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java b/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java new file mode 100644 index 00000000000..6ad1cc7469d --- /dev/null +++ b/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2006-2017 INRIA and contributors + * Spoon - http://spoon.gforge.inria.fr/ + * + * This software is governed by the CeCILL-C License under French law and + * abiding by the rules of distribution of free software. You can use, modify + * and/or redistribute the software under the terms of the CeCILL-C license as + * circulated by CEA, CNRS and INRIA at http://www.cecill.info. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +package spoon.reflect.visitor.filter; + +import java.util.HashSet; +import java.util.Set; + +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; +import spoon.reflect.visitor.chain.CtConsumableFunction; +import spoon.reflect.visitor.chain.CtConsumer; +import spoon.reflect.visitor.chain.CtQuery; +import spoon.reflect.visitor.chain.CtQueryAware; + +/** + * Expects {@link CtType} as input + * and produces all {@link CtTypeMember}s declared in input class + * or any super class or super interface + */ +public class AllTypeMembersFunction implements CtConsumableFunction>, CtQueryAware { + + private CtQuery query; + private final Class memberClass; + private Set distintSet; + + /** + * returns all type members + */ + public AllTypeMembersFunction() { + this.memberClass = null; + } + + /** + * returns all type members which are instance of `memberClass`.
+ * Example:
+ * + * CtField allFields = ctType.map(new AllTypeMembersFunction(CtField.class)).list(); + * + */ + public AllTypeMembersFunction(Class memberClass) { + this.memberClass = memberClass; + } + + public AllTypeMembersFunction distinctSet(Set distintSet) { + this.distintSet = distintSet; + return this; + } + + @Override + public void apply(CtType input, final CtConsumer outputConsumer) { + final CtQuery q = input.map(new SuperHierarchyFunction(distintSet == null ? new HashSet() : distintSet).includingSelf(true)); + q.forEach(new CtConsumer>() { + @Override + public void accept(CtType type) { + for (CtTypeMember typeMember : type.getTypeMembers()) { + if (memberClass == null || memberClass.isInstance(typeMember)) { + outputConsumer.accept(typeMember); + } + if (query.isTerminated()) { + q.terminate(); + } + } + } + }); + } + + @Override + public void setQuery(CtQuery query) { + this.query = query; + } +} diff --git a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java index 8debde709fd..14588555ae3 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java @@ -20,7 +20,6 @@ import spoon.reflect.code.CtBlock; import spoon.reflect.declaration.CtAnnotation; import spoon.reflect.declaration.CtAnnotationType; -import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtConstructor; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtField; @@ -43,9 +42,11 @@ import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.EarlyTerminatingScanner; import spoon.reflect.visitor.Query; +import spoon.reflect.visitor.chain.CtConsumer; +import spoon.reflect.visitor.filter.AllTypeMembersFunction; +import spoon.reflect.visitor.filter.NameFilter; import spoon.reflect.visitor.filter.ReferenceTypeFilter; import spoon.support.UnsettableProperty; -import spoon.support.SpoonClassNotFoundException; import spoon.support.compiler.SnippetCompilationHelper; import spoon.support.util.QualifiedNameBasedSortedSet; import spoon.support.util.SignatureBasedSortedSet; @@ -56,6 +57,7 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -185,25 +187,8 @@ public CtFieldReference getDeclaredField(String name) { @Override public CtFieldReference getDeclaredOrInheritedField(String fieldName) { - CtFieldReference field = getDeclaredField(fieldName); - if (field != null) { - return field; - } - CtTypeReference typeRef = getSuperclass(); - if (typeRef != null) { - field = typeRef.getDeclaredOrInheritedField(fieldName); - if (field != null) { - return field; - } - } - Set> ifaces = getSuperInterfaces(); - for (CtTypeReference iface : ifaces) { - field = iface.getDeclaredOrInheritedField(fieldName); - if (field != null) { - return field; - } - } - return field; + CtField field = map(new AllTypeMembersFunction(CtField.class)).select(new NameFilter<>(fieldName)).first(); + return field == null ? null : field.getReference(); } @@ -510,17 +495,13 @@ public boolean isGenerics() { @Override public List> getAllFields() { - final List> fields = getDeclaredFields(); - if (this instanceof CtClass) { - CtTypeReference st = ((CtClass) this).getSuperclass(); - if (st != null) { - fields.addAll(st.getAllFields()); - } - Set> superIFaces = ((CtClass) this).getSuperInterfaces(); - for (CtTypeReference superIFace : superIFaces) { - fields.addAll(superIFace.getAllFields()); + final List> fields = new ArrayList<>(); + map(new AllTypeMembersFunction(CtField.class)).forEach(new CtConsumer>() { + @Override + public void accept(CtField field) { + fields.add(field.getReference()); } - } + }); return fields; } @@ -884,46 +865,18 @@ public Collection> getAllExecutables() { return l; } - /** - * puts all methods of from in destination based on signatures only - */ - private void addAllBasedOnSignature(Set> from, Set> destination) { - List signatures = new ArrayList<>(); - for (CtMethod m : destination) { - signatures.add(m.getSignature()); - } - - for (CtMethod m : from) { - if (!signatures.contains(m.getSignature())) { - destination.add(m); - } - } - } - @Override public Set> getAllMethods() { - Set> l = new SignatureBasedSortedSet<>(getMethods()); - if ((getSuperclass() != null)) { - try { - CtType t = getSuperclass().getTypeDeclaration(); - addAllBasedOnSignature(t.getAllMethods(), l); - } catch (SpoonClassNotFoundException ignored) { - // should not be thrown in 'noClasspath' environment (#775) - } - } else if (this instanceof CtClass) { - // only CtCLasses extend object - addAllBasedOnSignature(getFactory().Type().get(Object.class).getMethods(), l); - } - - for (CtTypeReference ref : getSuperInterfaces()) { - try { - CtType t = ref.getTypeDeclaration(); - addAllBasedOnSignature(t.getAllMethods(), l); - } catch (SpoonClassNotFoundException ignored) { - // should not be thrown in 'noClasspath' environment (#775) + final Set distinctSignatures = new HashSet<>(); + final Set> l = new SignatureBasedSortedSet<>(); + map(new AllTypeMembersFunction(CtMethod.class)).forEach(new CtConsumer>() { + @Override + public void accept(CtMethod method) { + if (distinctSignatures.add(method.getSignature())) { + l.add(method); + } } - } - + }); return Collections.unmodifiableSet(l); } From c7600d33250fa44e3f6801d0d7e9683a253a650a Mon Sep 17 00:00:00 2001 From: Pavel Vojtechovsky Date: Sat, 11 Mar 2017 12:36:01 +0100 Subject: [PATCH 3/3] rename to SuperInheritanceHierarchyFunction --- .../visitor/filter/AllTypeMembersFunction.java | 2 +- ...ava => SuperInheritanceHierarchyFunction.java} | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) rename src/main/java/spoon/reflect/visitor/filter/{SuperHierarchyFunction.java => SuperInheritanceHierarchyFunction.java} (87%) diff --git a/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java b/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java index 6ad1cc7469d..4cb88a515bf 100644 --- a/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java +++ b/src/main/java/spoon/reflect/visitor/filter/AllTypeMembersFunction.java @@ -62,7 +62,7 @@ public AllTypeMembersFunction distinctSet(Set distintSet) { @Override public void apply(CtType input, final CtConsumer outputConsumer) { - final CtQuery q = input.map(new SuperHierarchyFunction(distintSet == null ? new HashSet() : distintSet).includingSelf(true)); + final CtQuery q = input.map(new SuperInheritanceHierarchyFunction(distintSet == null ? new HashSet() : distintSet).includingSelf(true)); q.forEach(new CtConsumer>() { @Override public void accept(CtType type) { diff --git a/src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java b/src/main/java/spoon/reflect/visitor/filter/SuperInheritanceHierarchyFunction.java similarity index 87% rename from src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java rename to src/main/java/spoon/reflect/visitor/filter/SuperInheritanceHierarchyFunction.java index 094890a302b..1a0d277c96b 100644 --- a/src/main/java/spoon/reflect/visitor/filter/SuperHierarchyFunction.java +++ b/src/main/java/spoon/reflect/visitor/filter/SuperInheritanceHierarchyFunction.java @@ -41,7 +41,7 @@ *
  • goto 1: using parent class as input type * */ -public class SuperHierarchyFunction implements CtConsumableFunction>, CtQueryAware { +public class SuperInheritanceHierarchyFunction implements CtConsumableFunction>, CtQueryAware { private boolean includingSelf = false; private boolean includingInterfaces = true; private Set visitedSet; @@ -56,20 +56,20 @@ public class SuperHierarchyFunction implements CtConsumableFunction>, * if they are in hierarchy more then once.
    * Use second constructor if you want to visit each interface only once. */ - public SuperHierarchyFunction() { + public SuperInheritanceHierarchyFunction() { } /** * @param visitedSet assures that each class/interface is visited only once */ - public SuperHierarchyFunction(Set visitedSet) { + public SuperInheritanceHierarchyFunction(Set visitedSet) { this.visitedSet = visitedSet; } /** * @param includingSelf if true then input element is sent to output too. By default it is false. */ - public SuperHierarchyFunction includingSelf(boolean includingSelf) { + public SuperInheritanceHierarchyFunction includingSelf(boolean includingSelf) { this.includingSelf = includingSelf; return this; } @@ -77,7 +77,7 @@ public SuperHierarchyFunction includingSelf(boolean includingSelf) { /** * @param includingInterfaces if false then interfaces are not visited - only super classes. By default it is true. */ - public SuperHierarchyFunction includingInterfaces(boolean includingInterfaces) { + public SuperInheritanceHierarchyFunction includingInterfaces(boolean includingInterfaces) { this.includingInterfaces = includingInterfaces; return this; } @@ -188,7 +188,10 @@ public void setQuery(CtQuery query) { this.query = query; } - public SuperHierarchyFunction failOnClassNotFound(boolean failOnClassNotFound) { + /** + * @param failOnClassNotFound sets whether processing should throw an exception if class is missing in noClassPath mode + */ + public SuperInheritanceHierarchyFunction failOnClassNotFound(boolean failOnClassNotFound) { this.failOnClassNotFound = failOnClassNotFound; return this; }