diff options
Diffstat (limited to 'javaparser-symbol-solver-logic/src/main/java/com/github/javaparser/symbolsolver/logic/InferenceVariableType.java')
-rw-r--r-- | javaparser-symbol-solver-logic/src/main/java/com/github/javaparser/symbolsolver/logic/InferenceVariableType.java | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-logic/src/main/java/com/github/javaparser/symbolsolver/logic/InferenceVariableType.java b/javaparser-symbol-solver-logic/src/main/java/com/github/javaparser/symbolsolver/logic/InferenceVariableType.java new file mode 100644 index 000000000..4d2e9840b --- /dev/null +++ b/javaparser-symbol-solver-logic/src/main/java/com/github/javaparser/symbolsolver/logic/InferenceVariableType.java @@ -0,0 +1,164 @@ +/* + * 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.symbolsolver.logic; + +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.resolution.types.ResolvedTypeVariable; +import com.github.javaparser.resolution.types.ResolvedWildcard; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * An element using during type inference. + * + * @author Federico Tomassetti + */ +public class InferenceVariableType implements ResolvedType { + @Override + public String toString() { + return "InferenceVariableType{" + + "id=" + id + + '}'; + } + + private int id; + private ResolvedTypeParameterDeclaration correspondingTp; + + public void setCorrespondingTp(ResolvedTypeParameterDeclaration correspondingTp) { + this.correspondingTp = correspondingTp; + } + + private Set<ResolvedType> equivalentTypes = new HashSet<>(); + private ObjectProvider objectProvider; + + public void registerEquivalentType(ResolvedType type) { + this.equivalentTypes.add(type); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof InferenceVariableType)) return false; + + InferenceVariableType that = (InferenceVariableType) o; + + return id == that.id; + + } + + @Override + public int hashCode() { + return id; + } + + private Set<ResolvedType> superTypes = new HashSet<>(); + + public InferenceVariableType(int id, ObjectProvider objectProvider) { + this.id = id; + this.objectProvider = objectProvider; + } + + public static InferenceVariableType fromWildcard(ResolvedWildcard wildcard, int id, ObjectProvider objectProvider) { + InferenceVariableType inferenceVariableType = new InferenceVariableType(id, objectProvider); + if (wildcard.isExtends()) { + inferenceVariableType.superTypes.add(wildcard.getBoundedType()); + } + if (wildcard.isSuper()) { + // I am not sure about this one... + inferenceVariableType.superTypes.add(wildcard.getBoundedType()); + } + return inferenceVariableType; + } + + @Override + public String describe() { + return "InferenceVariable_" + id; + } + + @Override + public boolean isAssignableBy(ResolvedType other) { + throw new UnsupportedOperationException(); + } + + private Set<ResolvedType> concreteEquivalentTypesAlsoIndirectly(Set<InferenceVariableType> considered, InferenceVariableType inferenceVariableType) { + considered.add(inferenceVariableType); + Set<ResolvedType> result = new HashSet<>(); + result.addAll(inferenceVariableType.equivalentTypes.stream().filter(t -> !t.isTypeVariable() && !(t instanceof InferenceVariableType)).collect(Collectors.toSet())); + inferenceVariableType.equivalentTypes.stream().filter(t -> t instanceof InferenceVariableType).forEach(t -> { + InferenceVariableType ivt = (InferenceVariableType)t; + if (!considered.contains(ivt)) { + result.addAll(concreteEquivalentTypesAlsoIndirectly(considered, ivt)); + } + }); + return result; + } + + public ResolvedType equivalentType() { + Set<ResolvedType> concreteEquivalent = concreteEquivalentTypesAlsoIndirectly(new HashSet<>(), this); + if (concreteEquivalent.isEmpty()) { + if (correspondingTp == null) { + return objectProvider.object(); + } else { + return new ResolvedTypeVariable(correspondingTp); + } + } + if (concreteEquivalent.size() == 1) { + return concreteEquivalent.iterator().next(); + } + Set<ResolvedType> notTypeVariables = equivalentTypes.stream() + .filter(t -> !t.isTypeVariable() && !hasInferenceVariables(t)) + .collect(Collectors.toSet()); + if (notTypeVariables.size() == 1) { + return notTypeVariables.iterator().next(); + } else if (notTypeVariables.size() == 0 && !superTypes.isEmpty()) { + if (superTypes.size() == 1) { + return superTypes.iterator().next(); + } else { + throw new IllegalStateException("Super types are: " + superTypes); + } + } else { + throw new IllegalStateException("Equivalent types are: " + equivalentTypes); + } + } + + private boolean hasInferenceVariables(ResolvedType type){ + if (type instanceof InferenceVariableType){ + return true; + } + + if (type.isReferenceType()){ + ResolvedReferenceType refType = type.asReferenceType(); + for (ResolvedType t : refType.typeParametersValues()){ + if (hasInferenceVariables(t)){ + return true; + } + } + return false; + } + + if (type.isWildcard()){ + ResolvedWildcard wildcardType = type.asWildcard(); + return hasInferenceVariables(wildcardType.getBoundedType()); + } + + return false; + } +} |