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:
+ *
+ * input type. if `includingSelf==true`
+ * all interfaces of type recursively
+ * parent class of type
+ * 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;
}