Skip to content

Commit

Permalink
refactor(ReferenceBuilder): Extract parameterized type reference crea…
Browse files Browse the repository at this point in the history
…tion into helpers (#3966)
  • Loading branch information
slarse authored May 31, 2021
1 parent 719cdc2 commit b2235e8
Showing 1 changed file with 65 additions and 42 deletions.
107 changes: 65 additions & 42 deletions src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static spoon.support.compiler.jdt.JDTTreeBuilderQuery.searchPackage;
import static spoon.support.compiler.jdt.JDTTreeBuilderQuery.searchType;
Expand Down Expand Up @@ -760,48 +762,7 @@ <T> CtTypeReference<T> getTypeReference(TypeBinding binding, boolean resolveGene
if (binding instanceof RawTypeBinding) {
ref = getTypeReference(((ParameterizedTypeBinding) binding).genericType());
} else if (binding instanceof ParameterizedTypeBinding) {
if (binding.actualType() != null && binding.actualType() instanceof LocalTypeBinding) {
// When we define a nested class in a method and when the enclosing class of this method
// is a parameterized type binding, JDT give a ParameterizedTypeBinding for the nested class
// and hide the real class in actualType().
ref = getTypeReference(binding.actualType());
} else {
ref = this.jdtTreeBuilder.getFactory().Core().createTypeReference();
this.exploringParameterizedBindings.put(binding, ref);
if (binding.isAnonymousType()) {
ref.setSimpleName("");
} else {
ref.setSimpleName(String.valueOf(binding.sourceName()));
if (binding.enclosingType() != null) {
ref.setDeclaringType(getTypeReference(binding.enclosingType()));
} else {
ref.setPackage(getPackageReference(binding.getPackage()));
}
}
}
if (binding.actualType() instanceof MissingTypeBinding) {
ref = getTypeReference(binding.actualType());
}

if (((ParameterizedTypeBinding) binding).arguments != null) {
for (TypeBinding b : ((ParameterizedTypeBinding) binding).arguments) {
if (bindingCache.containsKey(b)) {
ref.addActualTypeArgument(getCtCircularTypeReference(b));
} else {
if (!this.exploringParameterizedBindings.containsKey(b)) {
this.exploringParameterizedBindings.put(b, null);
CtTypeReference typeRefB = getTypeReference(b);
this.exploringParameterizedBindings.put(b, typeRefB);
ref.addActualTypeArgument(typeRefB);
} else {
CtTypeReference typeRefB = this.exploringParameterizedBindings.get(b);
if (typeRefB != null) {
ref.addActualTypeArgument(typeRefB.clone());
}
}
}
}
}
ref = getParameterizedTypeReference((ParameterizedTypeBinding) binding);
} else if (binding instanceof MissingTypeBinding) {
ref = this.jdtTreeBuilder.getFactory().Core().createTypeReference();
ref.setSimpleName(new String(binding.sourceName()));
Expand Down Expand Up @@ -988,6 +949,68 @@ <T> CtTypeReference<T> getTypeReference(TypeBinding binding, boolean resolveGene
return (CtTypeReference<T>) ref;
}

/**
* Create a parameterized type reference based on the provided binding.
*/
private CtTypeReference<?> getParameterizedTypeReference(ParameterizedTypeBinding binding) {
CtTypeReference<?> ref;
if (binding.actualType() instanceof LocalTypeBinding) {
// When we define a nested class in a method and when the enclosing class of this method
// is a parameterized type binding, JDT give a ParameterizedTypeBinding for the nested class
// and hide the real class in actualType().
ref = getTypeReference(binding.actualType());
} else {
ref = this.jdtTreeBuilder.getFactory().Core().createTypeReference();
this.exploringParameterizedBindings.put(binding, ref);
if (binding.isAnonymousType()) {
ref.setSimpleName("");
} else {
ref.setSimpleName(String.valueOf(binding.sourceName()));
if (binding.enclosingType() != null) {
ref.setDeclaringType(getTypeReference(binding.enclosingType()));
} else {
ref.setPackage(getPackageReference(binding.getPackage()));
}
}
}
if (binding.actualType() instanceof MissingTypeBinding) {
ref = getTypeReference(binding.actualType());
}

getTypeArguments(binding).forEach(ref::addActualTypeArgument);
return ref;
}

/**
* Get the type arguments from the binding, or an empty list if no type arguments can be found.
*/
private List<CtTypeReference<?>> getTypeArguments(ParameterizedTypeBinding binding) {
return binding.arguments == null
? Collections.emptyList()
: Arrays.stream((binding.arguments))
.map(this::getTypeReferenceFromTypeArgument)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

/**
* Get the type reference for a type argument binding. May return null when called recursively.
*/
private CtTypeReference<?> getTypeReferenceFromTypeArgument(TypeBinding typeArgBinding) {
if (bindingCache.containsKey(typeArgBinding)) {
return getCtCircularTypeReference(typeArgBinding);
} else if (exploringParameterizedBindings.containsKey(typeArgBinding)) {
// note: can be null if this method is called recursively
CtTypeReference<?> typeRefBeingExplored = exploringParameterizedBindings.get(typeArgBinding);
return typeRefBeingExplored == null ? null : typeRefBeingExplored.clone();
} else {
this.exploringParameterizedBindings.put(typeArgBinding, null);
CtTypeReference<?> typeRefB = getTypeReference(typeArgBinding);
this.exploringParameterizedBindings.put(typeArgBinding, typeRefB);
return typeRefB;
}
}

private CtTypeReference<?> getCtCircularTypeReference(TypeBinding b) {
return bindingCache.get(b).clone();
}
Expand Down

0 comments on commit b2235e8

Please sign in to comment.
  NODES
COMMUNITY 1
Note 2
Project 1
USERS 1