Skip to content

Commit

Permalink
issue1154: correcting resolved type hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Sep 27, 2017
1 parent 61db2ec commit c7ee7cc
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 115 deletions.
Expand Up @@ -17,18 +17,13 @@
package com.github.javaparser.resolution.types; package com.github.javaparser.resolution.types;


import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.ReferenceType;
import com.github.javaparser.resolution.MethodUsage;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParameterValueProvider;
import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap; import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap;
import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametrized; import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametrized;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration; import com.github.javaparser.utils.Pair;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.typesystem.parametrization.TypeParameterValueProvider;
import com.github.javaparser.symbolsolver.model.typesystem.parametrization.TypeParametersMap;
import com.github.javaparser.symbolsolver.model.typesystem.parametrization.TypeParametrized;
import javaslang.Tuple2;


import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
Expand All @@ -53,14 +48,7 @@ public abstract class ResolvedReferenceType implements ResolvedType,
// Constructors // Constructors
// //


public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration) { public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeArguments) {
this(typeDeclaration, deriveParams(typeDeclaration));
}

public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeArguments, TypeSolver typeSolver) {
if (typeSolver == null) {
throw new IllegalArgumentException("typeSolver should not be null");
}
if (typeDeclaration.isTypeParameter()) { if (typeDeclaration.isTypeParameter()) {
throw new IllegalArgumentException("You should use only Classes, Interfaces and enums"); throw new IllegalArgumentException("You should use only Classes, Interfaces and enums");
} }
Expand All @@ -69,13 +57,12 @@ public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, L
"expected either zero type arguments or has many as defined in the declaration (%d). Found %d", "expected either zero type arguments or has many as defined in the declaration (%d). Found %d",
typeDeclaration.getTypeParameters().size(), typeArguments.size())); typeDeclaration.getTypeParameters().size(), typeArguments.size()));
} }
TypeParametersMap.Builder typeParametersMapBuilder = new TypeParametersMap.Builder(); ResolvedTypeParametersMap.Builder typeParametersMapBuilder = new ResolvedTypeParametersMap.Builder();
for (int i = 0; i < typeArguments.size(); i++) { for (int i = 0; i < typeArguments.size(); i++) {
typeParametersMapBuilder.setValue(typeDeclaration.getTypeParameters().get(i), typeArguments.get(i)); typeParametersMapBuilder.setValue(typeDeclaration.getTypeParameters().get(i), typeArguments.get(i));
} }
this.typeParametersMap = typeParametersMapBuilder.build(); this.typeParametersMap = typeParametersMapBuilder.build();
this.typeDeclaration = typeDeclaration; this.typeDeclaration = typeDeclaration;
this.typeSolver = typeSolver;
} }


// //
Expand All @@ -87,7 +74,7 @@ public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;


ReferenceType that = (ReferenceType) o; ResolvedReferenceType that = (ResolvedReferenceType) o;


if (!typeDeclaration.equals(that.typeDeclaration)) return false; if (!typeDeclaration.equals(that.typeDeclaration)) return false;
if (!typeParametersMap.equals(that.typeParametersMap)) return false; if (!typeParametersMap.equals(that.typeParametersMap)) return false;
Expand Down Expand Up @@ -156,57 +143,7 @@ public String describe() {
/** /**
* Execute a transformation on all the type parameters of this element. * Execute a transformation on all the type parameters of this element.
*/ */
public Type transformTypeParameters(TypeTransformer transformer) { public abstract ResolvedType transformTypeParameters(ResolvedTypeTransformer transformer);
Type result = this;
int i = 0;
for (Type tp : this.typeParametersValues()) {
Type transformedTp = transformer.transform(tp);
// Identity comparison on purpose
if (transformedTp != tp) {
List<Type> typeParametersCorrected = result.asReferenceType().typeParametersValues();
typeParametersCorrected.set(i, transformedTp);
result = create(typeDeclaration, typeParametersCorrected, typeSolver);
}
i++;
}
return result;
}

@Override
public ResolvedType replaceTypeVariables(ResolvedTypeParameterDeclaration tpToReplace,
ResolvedType replaced,
Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) {
if (replaced == null) {
throw new IllegalArgumentException();
}

ReferenceType result = this;
int i = 0;
for (ResolvedType tp : this.typeParametersValues()) {
ResolvedType transformedTp = tp.replaceTypeVariables(tpToReplace, replaced, inferredTypes);
// Identity comparison on purpose
if (tp.isTypeVariable() && tp.asTypeVariable().describe().equals(tpToReplace.getName())) {
inferredTypes.put(tp.asTypeParameter(), replaced);
}
// FIXME
if (true) {
List<ResolvedType> typeParametersCorrected = result.asReferenceType().typeParametersValues();
typeParametersCorrected.set(i, transformedTp);
result = create(typeDeclaration, typeParametersCorrected, typeSolver);
}
i++;
}

List<ResolvedType> values = result.typeParametersValues();
// FIXME
if(values.contains(tpToReplace)){
int index = values.indexOf(tpToReplace);
values.set(index, replaced);
return create(result.getTypeDeclaration(), values, typeSolver);
}

return result;
}


/// ///
/// Assignability /// Assignability
Expand Down Expand Up @@ -235,22 +172,7 @@ public ResolvedType replaceTypeVariables(ResolvedTypeParameterDeclaration tpToRe
* a call to getAllAncestors on a reference to Bar having type parameter Boolean should include * a call to getAllAncestors on a reference to Bar having type parameter Boolean should include
* Foo&lt;Boolean, String&gt;. * Foo&lt;Boolean, String&gt;.
*/ */
public List<ResolvedReferenceType> getAllAncestors() { public abstract List<ResolvedReferenceType> getAllAncestors();
// We need to go through the inheritance line and propagate the type parametes

List<ReferenceType> ancestors = typeDeclaration.getAllAncestors();

ancestors = ancestors.stream()
.map(a -> typeParametersMap().replaceAll(a).asReferenceType())
.collect(Collectors.toList());

// Avoid repetitions of Object
ancestors.removeIf(a -> a.getQualifiedName().equals(Object.class.getCanonicalName()));
ResolvedReferenceTypeDeclaration objectType = typeSolver.solveType(Object.class.getCanonicalName());
ReferenceType objectRef = create(objectType, typeSolver);
ancestors.add(objectRef);
return ancestors;
}


public final List<ResolvedReferenceType> getAllInterfacesAncestors() { public final List<ResolvedReferenceType> getAllInterfacesAncestors() {
return getAllAncestors().stream() return getAllAncestors().stream()
Expand All @@ -272,7 +194,7 @@ public final List<ResolvedReferenceType> getAllClassesAncestors() {
* Get the type associated with the type parameter with the given name. * Get the type associated with the type parameter with the given name.
* It returns Optional.empty unless the type declaration declares a type parameter with the given name. * It returns Optional.empty unless the type declaration declares a type parameter with the given name.
*/ */
public Optional<ReferenceType> getGenericParameterByName(String name) { public Optional<ResolvedType> getGenericParameterByName(String name) {
for (ResolvedTypeParameterDeclaration tp : typeDeclaration.getTypeParameters()) { for (ResolvedTypeParameterDeclaration tp : typeDeclaration.getTypeParameters()) {
if (tp.getName().equals(name)) { if (tp.getName().equals(name)) {
return Optional.of(this.typeParametersMap().getValue(tp)); return Optional.of(this.typeParametersMap().getValue(tp));
Expand All @@ -293,11 +215,11 @@ public List<ResolvedType> typeParametersValues() {
* Get the values for all type parameters declared on this type. * Get the values for all type parameters declared on this type.
* In case of raw types the values correspond to TypeVariables. * In case of raw types the values correspond to TypeVariables.
*/ */
public List<Tuple2<ResolvedTypeParameterDeclaration, ResolvedType>> getTypeParametersMap() { public List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> getTypeParametersMap() {
List<Tuple2<TypeParameterDeclaration, Type>> typeParametersMap = new ArrayList<>(); List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> typeParametersMap = new ArrayList<>();
if (!isRawType()) { if (!isRawType()) {
for (int i = 0; i < typeDeclaration.getTypeParameters().size(); i++) { for (int i = 0; i < typeDeclaration.getTypeParameters().size(); i++) {
typeParametersMap.add(new Tuple2<>(typeDeclaration.getTypeParameters().get(0), typeParametersValues().get(i))); typeParametersMap.add(new Pair<>(typeDeclaration.getTypeParameters().get(0), typeParametersValues().get(i)));
} }
} }
return typeParametersMap; return typeParametersMap;
Expand Down Expand Up @@ -364,7 +286,7 @@ public boolean isRawType() {
return true; return true;
} }
for (String name : typeParametersMap().getNames()) { for (String name : typeParametersMap().getNames()) {
Optional<Type> value = typeParametersMap().getValueBySignature(name); Optional<ResolvedType> value = typeParametersMap().getValueBySignature(name);
if (value.isPresent() && value.get().isTypeVariable() && value.get().asTypeVariable().qualifiedName().equals(name)) { if (value.isPresent() && value.get().isTypeVariable() && value.get().asTypeVariable().qualifiedName().equals(name)) {
// nothing to do // nothing to do
} else { } else {
Expand All @@ -376,37 +298,37 @@ public boolean isRawType() {
return false; return false;
} }


public Optional<Type> typeParamValue(TypeParameterDeclaration typeParameterDeclaration) { public Optional<ResolvedType> typeParamValue(ResolvedTypeParameterDeclaration typeParameterDeclaration) {
if (typeParameterDeclaration.declaredOnMethod()) { if (typeParameterDeclaration.declaredOnMethod()) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
String typeId = this.getTypeDeclaration().getId(); String typeId = this.getTypeDeclaration().getId();
if (typeId.equals(typeParameterDeclaration.getContainerId())) { if (typeId.equals(typeParameterDeclaration.getContainerId())) {
return Optional.of(this.typeParametersMap().getValue(typeParameterDeclaration)); return Optional.of(this.typeParametersMap().getValue(typeParameterDeclaration));
} }
for (ReferenceType ancestor : this.getAllAncestors()) { for (ResolvedReferenceType ancestor : this.getAllAncestors()) {
if (ancestor.getId().equals(typeParameterDeclaration.getContainerId())) { if (ancestor.getId().equals(typeParameterDeclaration.getContainerId())) {
return Optional.of(ancestor.typeParametersMap().getValue(typeParameterDeclaration)); return Optional.of(ancestor.typeParametersMap().getValue(typeParameterDeclaration));
} }
} }
return Optional.empty(); return Optional.empty();
} }


public abstract Type toRawType(); public abstract ResolvedType toRawType();


// //
// Protected methods // Protected methods
// //


protected abstract ReferenceType create(ReferenceTypeDeclaration typeDeclaration, List<Type> typeParameters, TypeSolver typeSolver); protected abstract ReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeParameters);


protected ReferenceType create(ReferenceTypeDeclaration typeDeclaration, TypeParametersMap typeParametersMap, TypeSolver typeSolver) { protected ReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, ResolvedTypeParametersMap typeParametersMap) {
return create(typeDeclaration, typeDeclaration.getTypeParameters().stream() return create(typeDeclaration, typeDeclaration.getTypeParameters().stream()
.map(typeParametersMap::getValue) .map(typeParametersMap::getValue)
.collect(Collectors.toList()), typeSolver); .collect(Collectors.toList()));
} }


protected abstract ReferenceType create(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver); protected abstract ReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration);


protected boolean isCorrespondingBoxingType(String typeName) { protected boolean isCorrespondingBoxingType(String typeName) {
switch (typeName) { switch (typeName) {
Expand All @@ -431,7 +353,7 @@ protected boolean isCorrespondingBoxingType(String typeName) {
} }
} }


protected boolean compareConsideringTypeParameters(ReferenceType other) { protected boolean compareConsideringTypeParameters(ResolvedReferenceType other) {
if (other.equals(this)) { if (other.equals(this)) {
return true; return true;
} }
Expand All @@ -443,11 +365,11 @@ protected boolean compareConsideringTypeParameters(ReferenceType other) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
for (int i = 0; i < typeParametersValues().size(); i++) { for (int i = 0; i < typeParametersValues().size(); i++) {
Type thisParam = typeParametersValues().get(i); ResolvedType thisParam = typeParametersValues().get(i);
Type otherParam = other.typeParametersValues().get(i); ResolvedType otherParam = other.typeParametersValues().get(i);
if (!thisParam.equals(otherParam)) { if (!thisParam.equals(otherParam)) {
if (thisParam instanceof Wildcard) { if (thisParam instanceof ResolvedWildcard) {
Wildcard thisParamAsWildcard = (Wildcard) thisParam; ResolvedWildcard thisParamAsWildcard = (ResolvedWildcard) thisParam;
if (thisParamAsWildcard.isSuper() && otherParam.isAssignableBy(thisParamAsWildcard.getBoundedType())) { if (thisParamAsWildcard.isSuper() && otherParam.isAssignableBy(thisParamAsWildcard.getBoundedType())) {
// ok // ok
} else if (thisParamAsWildcard.isExtends() && thisParamAsWildcard.getBoundedType().isAssignableBy(otherParam)) { } else if (thisParamAsWildcard.isExtends() && thisParamAsWildcard.getBoundedType().isAssignableBy(otherParam)) {
Expand All @@ -458,9 +380,9 @@ protected boolean compareConsideringTypeParameters(ReferenceType other) {
return false; return false;
} }
} else { } else {
if (thisParam instanceof TypeVariable && otherParam instanceof TypeVariable) { if (thisParam instanceof ResolvedTypeVariable && otherParam instanceof ResolvedTypeVariable) {
List<Type> thisBounds = thisParam.asTypeVariable().asTypeParameter().getBounds(this.typeSolver).stream().map(bound -> bound.getType()).collect(Collectors.toList()); List<ResolvedType> thisBounds = thisParam.asTypeVariable().asTypeParameter().getBounds().stream().map(bound -> bound.getType()).collect(Collectors.toList());
List<Type> otherBounds = otherParam.asTypeVariable().asTypeParameter().getBounds(other.typeSolver).stream().map(bound -> bound.getType()).collect(Collectors.toList()); List<ResolvedType> otherBounds = otherParam.asTypeVariable().asTypeParameter().getBounds().stream().map(bound -> bound.getType()).collect(Collectors.toList());
if (thisBounds.size() == otherBounds.size() && otherBounds.containsAll(thisBounds)) { if (thisBounds.size() == otherBounds.size() && otherBounds.containsAll(thisBounds)) {
return true; return true;
} }
Expand All @@ -478,11 +400,9 @@ protected boolean compareConsideringTypeParameters(ReferenceType other) {
// Private methods // Private methods
// //


private static List<ResolvedType> deriveParams(ReferenceTypeDeclaration typeDeclaration) { private static List<ResolvedType> deriveParams(ResolvedReferenceTypeDeclaration typeDeclaration) {
return typeDeclaration.getTypeParameters().stream().map((tp) -> new TypeVariable(tp)).collect(Collectors.toList()); return typeDeclaration.getTypeParameters().stream().map((tp) -> new ResolvedTypeVariable(tp)).collect(Collectors.toList());
} }


public ReferenceType deriveTypeParameters(ResolvedTypeParametersMap typeParametersMap) { public abstract ReferenceType deriveTypeParameters(ResolvedTypeParametersMap typeParametersMap);
return create(typeDeclaration, typeParametersMap, typeSolver);
}
} }
@@ -0,0 +1,25 @@
/*
* Copyright 2016 Federico Tomassetti
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.javaparser.resolution.types;

/**
* @author Federico Tomassetti
*/
@FunctionalInterface
public interface ResolvedTypeTransformer {
ResolvedType transform(ResolvedType type);
}
Expand Up @@ -17,7 +17,6 @@
package com.github.javaparser.resolution.types; package com.github.javaparser.resolution.types;


import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;


import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
Expand Down
@@ -0,0 +1,51 @@
package com.github.javaparser.resolution.types.parametrization;

import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.resolution.types.ResolvedWildcard;

import java.util.Optional;

/**
* @author Federico Tomassetti
*/
public interface ResolvedTypeParameterValueProvider {

/**
* Calculate the value for the given type parameter.
* It could be inherited.
*/
Optional<ResolvedType> typeParamValue(ResolvedTypeParameterDeclaration typeParameterDeclaration);

/**
* Replace the type typeParametersValues present in the given type with the ones for which this type
* has a value.
*/
default ResolvedType useThisTypeParametersOnTheGivenType(ResolvedType type) {
if (type.isTypeVariable()) {
ResolvedTypeParameterDeclaration typeParameter = type.asTypeParameter();
if (typeParameter.declaredOnType()) {
Optional<ResolvedType> typeParam = typeParamValue(typeParameter);
if (typeParam.isPresent()) {
type = typeParam.get();
}
}
}

if (type.isWildcard() && type.asWildcard().isBounded()) {
if (type.asWildcard().isExtends()) {
return ResolvedWildcard.extendsBound(useThisTypeParametersOnTheGivenType(type.asWildcard().getBoundedType()));
} else {
return ResolvedWildcard.superBound(useThisTypeParametersOnTheGivenType(type.asWildcard().getBoundedType()));
}
}

if (type.isReferenceType()) {
type = type.asReferenceType().transformTypeParameters(this::useThisTypeParametersOnTheGivenType);
}

return type;
}

Optional<ResolvedType> getGenericParameterByName(String name);
}
Expand Up @@ -38,7 +38,8 @@ public Builder() {
nameToDeclaration = new HashMap<>(); nameToDeclaration = new HashMap<>();
} }


private Builder(Map<String, ResolvedType> nameToValue, Map<String, ResolvedTypeParameterDeclaration> nameToDeclaration) { private Builder(Map<String, ResolvedType> nameToValue,
Map<String, ResolvedTypeParameterDeclaration> nameToDeclaration) {
this.nameToValue = new HashMap<>(); this.nameToValue = new HashMap<>();
this.nameToValue.putAll(nameToValue); this.nameToValue.putAll(nameToValue);
this.nameToDeclaration = new HashMap<>(); this.nameToDeclaration = new HashMap<>();
Expand All @@ -49,7 +50,8 @@ public ResolvedTypeParametersMap build() {
return new ResolvedTypeParametersMap(nameToValue, nameToDeclaration); return new ResolvedTypeParametersMap(nameToValue, nameToDeclaration);
} }


public Builder setValue(ResolvedTypeParameterDeclaration typeParameter, ResolvedType value) { public Builder setValue(ResolvedTypeParameterDeclaration typeParameter,
ResolvedType value) {
// TODO: we shouldn't just silently overwrite existing types! // TODO: we shouldn't just silently overwrite existing types!
String qualifiedName = typeParameter.getQualifiedName(); String qualifiedName = typeParameter.getQualifiedName();
nameToValue.put(qualifiedName, value); nameToValue.put(qualifiedName, value);
Expand Down Expand Up @@ -88,7 +90,8 @@ public static ResolvedTypeParametersMap empty() {
return new Builder().build(); return new Builder().build();
} }


private ResolvedTypeParametersMap(Map<String, ResolvedType> nameToValue, Map<String, ResolvedTypeParameterDeclaration> nameToDeclaration) { private ResolvedTypeParametersMap(Map<String, ResolvedType> nameToValue,
Map<String, ResolvedTypeParameterDeclaration> nameToDeclaration) {
this.nameToValue = new HashMap<>(); this.nameToValue = new HashMap<>();
this.nameToValue.putAll(nameToValue); this.nameToValue.putAll(nameToValue);
this.nameToDeclaration = new HashMap<>(); this.nameToDeclaration = new HashMap<>();
Expand Down

0 comments on commit c7ee7cc

Please sign in to comment.