aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
diff options
context:
space:
mode:
Diffstat (limited to 'javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java')
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java451
1 files changed, 451 insertions, 0 deletions
diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
new file mode 100644
index 000000000..4fecaf6ec
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser 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
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.resolution.types;
+
+import com.github.javaparser.resolution.MethodUsage;
+import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
+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.ResolvedTypeParametrized;
+import com.github.javaparser.utils.Pair;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * A ReferenceType like a class, an interface or an enum. Note that this type can contain also the values
+ * specified for the type parameters.
+ *
+ * @author Federico Tomassetti
+ */
+public abstract class ResolvedReferenceType implements ResolvedType,
+ ResolvedTypeParametrized, ResolvedTypeParameterValueProvider {
+
+ //
+ // Fields
+ //
+
+ protected ResolvedReferenceTypeDeclaration typeDeclaration;
+ protected ResolvedTypeParametersMap typeParametersMap;
+
+ //
+ // Constructors
+ //
+
+ public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration) {
+ this(typeDeclaration, deriveParams(typeDeclaration));
+ }
+
+ public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeArguments) {
+ if (typeDeclaration.isTypeParameter()) {
+ throw new IllegalArgumentException("You should use only Classes, Interfaces and enums");
+ }
+ if (typeArguments.size() > 0 && typeArguments.size() != typeDeclaration.getTypeParameters().size()) {
+ throw new IllegalArgumentException(String.format(
+ "expected either zero type arguments or has many as defined in the declaration (%d). Found %d",
+ typeDeclaration.getTypeParameters().size(), typeArguments.size()));
+ }
+ ResolvedTypeParametersMap.Builder typeParametersMapBuilder = new ResolvedTypeParametersMap.Builder();
+ for (int i = 0; i < typeArguments.size(); i++) {
+ typeParametersMapBuilder.setValue(typeDeclaration.getTypeParameters().get(i), typeArguments.get(i));
+ }
+ this.typeParametersMap = typeParametersMapBuilder.build();
+ this.typeDeclaration = typeDeclaration;
+ }
+
+ //
+ // Public Object methods
+ //
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ResolvedReferenceType that = (ResolvedReferenceType) o;
+
+ if (!typeDeclaration.equals(that.typeDeclaration)) return false;
+ if (!typeParametersMap.equals(that.typeParametersMap)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = typeDeclaration.hashCode();
+ result = 31 * result + typeParametersMap.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ReferenceType{" + getQualifiedName() +
+ ", typeParametersMap=" + typeParametersMap +
+ '}';
+ }
+
+ ///
+ /// Relation with other types
+ ///
+
+ @Override
+ public final boolean isReferenceType() {
+ return true;
+ }
+
+ ///
+ /// Downcasting
+ ///
+
+ @Override
+ public ResolvedReferenceType asReferenceType() {
+ return this;
+ }
+
+ ///
+ /// Naming
+ ///
+
+ @Override
+ public String describe() {
+ StringBuilder sb = new StringBuilder();
+ if (hasName()) {
+ sb.append(typeDeclaration.getQualifiedName());
+ } else {
+ sb.append("<anonymous class>");
+ }
+ if (!typeParametersMap().isEmpty()) {
+ sb.append("<");
+ sb.append(String.join(", ", typeDeclaration.getTypeParameters().stream()
+ .map(tp -> typeParametersMap().getValue(tp).describe())
+ .collect(Collectors.toList())));
+ sb.append(">");
+ }
+ return sb.toString();
+ }
+
+ ///
+ /// TypeParameters
+ ///
+
+ /**
+ * Execute a transformation on all the type parameters of this element.
+ */
+ public abstract ResolvedType transformTypeParameters(ResolvedTypeTransformer transformer);
+
+ @Override
+ public ResolvedType replaceTypeVariables(ResolvedTypeParameterDeclaration tpToReplace, ResolvedType replaced,
+ Map<ResolvedTypeParameterDeclaration, ResolvedType> inferredTypes) {
+ if (replaced == null) {
+ throw new IllegalArgumentException();
+ }
+
+ ResolvedReferenceType 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);
+ }
+ 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);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Assignability
+ ///
+
+ /**
+ * This method checks if ThisType t = new OtherType() would compile.
+ */
+ @Override
+ public abstract boolean isAssignableBy(ResolvedType other);
+
+ ///
+ /// Ancestors
+ ///
+
+ /**
+ * Return all ancestors, that means all superclasses and interfaces.
+ * This list should always include Object (unless this is a reference to Object).
+ * The type typeParametersValues should be expressed in terms of this type typeParametersValues.
+ * <p>
+ * For example, given:
+ * <p>
+ * class Foo&lt;A, B&gt; {}
+ * class Bar&lt;C&gt; extends Foo&lt;C, String&gt; {}
+ * <p>
+ * a call to getAllAncestors on a reference to Bar having type parameter Boolean should include
+ * Foo&lt;Boolean, String&gt;.
+ */
+ public abstract List<ResolvedReferenceType> getAllAncestors();
+
+ public final List<ResolvedReferenceType> getAllInterfacesAncestors() {
+ return getAllAncestors().stream()
+ .filter(it -> it.getTypeDeclaration().isInterface())
+ .collect(Collectors.toList());
+ }
+
+ public final List<ResolvedReferenceType> getAllClassesAncestors() {
+ return getAllAncestors().stream()
+ .filter(it -> it.getTypeDeclaration().isClass())
+ .collect(Collectors.toList());
+ }
+
+ ///
+ /// Type parameters
+ ///
+
+ /**
+ * 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.
+ */
+ public Optional<ResolvedType> getGenericParameterByName(String name) {
+ for (ResolvedTypeParameterDeclaration tp : typeDeclaration.getTypeParameters()) {
+ if (tp.getName().equals(name)) {
+ return Optional.of(this.typeParametersMap().getValue(tp));
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Get the values for all type parameters declared on this type.
+ * The list can be empty for raw types.
+ */
+ public List<ResolvedType> typeParametersValues() {
+ return this.typeParametersMap.isEmpty() ? Collections.emptyList() : typeDeclaration.getTypeParameters().stream().map(tp -> typeParametersMap.getValue(tp)).collect(Collectors.toList());
+ }
+
+ /**
+ * Get the values for all type parameters declared on this type.
+ * In case of raw types the values correspond to TypeVariables.
+ */
+ public List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> getTypeParametersMap() {
+ List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> typeParametersMap = new ArrayList<>();
+ if (!isRawType()) {
+ for (int i = 0; i < typeDeclaration.getTypeParameters().size(); i++) {
+ typeParametersMap.add(new Pair<>(typeDeclaration.getTypeParameters().get(0), typeParametersValues().get(i)));
+ }
+ }
+ return typeParametersMap;
+ }
+
+ @Override
+ public ResolvedTypeParametersMap typeParametersMap() {
+ return typeParametersMap;
+ }
+
+ ///
+ /// Other methods introduced by ReferenceType
+ ///
+
+ /**
+ * Corresponding TypeDeclaration
+ */
+ public final ResolvedReferenceTypeDeclaration getTypeDeclaration() {
+ return typeDeclaration;
+ }
+
+ /**
+ * The type of the field could be different from the one in the corresponding FieldDeclaration because
+ * type variables would be solved.
+ */
+ public Optional<ResolvedType> getFieldType(String name) {
+ if (!typeDeclaration.hasField(name)) {
+ return Optional.empty();
+ }
+ ResolvedType type = typeDeclaration.getField(name).getType();
+ type = useThisTypeParametersOnTheGivenType(type);
+ return Optional.of(type);
+ }
+
+ /**
+ * Has the TypeDeclaration a name? Anonymous classes do not have one.
+ */
+ public boolean hasName() {
+ return typeDeclaration.hasName();
+ }
+
+ /**
+ * Qualified name of the declaration.
+ */
+ public String getQualifiedName() {
+ return typeDeclaration.getQualifiedName();
+ }
+
+ /**
+ * Id of the declaration. It corresponds to the qualified name, unless for local classes.
+ */
+ public String getId() {
+ return typeDeclaration.getId();
+ }
+
+ /**
+ * Methods declared on this type.
+ */
+ public abstract Set<MethodUsage> getDeclaredMethods();
+
+ public boolean isRawType() {
+ if (!typeDeclaration.getTypeParameters().isEmpty()) {
+ if (typeParametersMap().isEmpty()) {
+ return true;
+ }
+ for (String name : typeParametersMap().getNames()) {
+ Optional<ResolvedType> value = typeParametersMap().getValueBySignature(name);
+ if (value.isPresent() && value.get().isTypeVariable() && value.get().asTypeVariable().qualifiedName().equals(name)) {
+ // nothing to do
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public Optional<ResolvedType> typeParamValue(ResolvedTypeParameterDeclaration typeParameterDeclaration) {
+ if (typeParameterDeclaration.declaredOnMethod()) {
+ throw new IllegalArgumentException();
+ }
+ String typeId = this.getTypeDeclaration().getId();
+ if (typeId.equals(typeParameterDeclaration.getContainerId())) {
+ return Optional.of(this.typeParametersMap().getValue(typeParameterDeclaration));
+ }
+ for (ResolvedReferenceType ancestor : this.getAllAncestors()) {
+ if (ancestor.getId().equals(typeParameterDeclaration.getContainerId())) {
+ return Optional.of(ancestor.typeParametersMap().getValue(typeParameterDeclaration));
+ }
+ }
+ return Optional.empty();
+ }
+
+ public abstract ResolvedType toRawType();
+
+ //
+ // Protected methods
+ //
+
+ protected abstract ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeParameters);
+
+ protected ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, ResolvedTypeParametersMap typeParametersMap) {
+ return create(typeDeclaration, typeDeclaration.getTypeParameters().stream()
+ .map(typeParametersMap::getValue)
+ .collect(Collectors.toList()));
+ }
+
+ protected abstract ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration);
+
+ protected boolean isCorrespondingBoxingType(String typeName) {
+ switch (typeName) {
+ case "boolean":
+ return getQualifiedName().equals(Boolean.class.getCanonicalName());
+ case "char":
+ return getQualifiedName().equals(Character.class.getCanonicalName());
+ case "byte":
+ return getQualifiedName().equals(Byte.class.getCanonicalName());
+ case "short":
+ return getQualifiedName().equals(Short.class.getCanonicalName());
+ case "int":
+ return getQualifiedName().equals(Integer.class.getCanonicalName());
+ case "long":
+ return getQualifiedName().equals(Long.class.getCanonicalName());
+ case "float":
+ return getQualifiedName().equals(Float.class.getCanonicalName());
+ case "double":
+ return getQualifiedName().equals(Double.class.getCanonicalName());
+ default:
+ throw new UnsupportedOperationException(typeName);
+ }
+ }
+
+ protected boolean compareConsideringTypeParameters(ResolvedReferenceType other) {
+ if (other.equals(this)) {
+ return true;
+ }
+ if (this.getQualifiedName().equals(other.getQualifiedName())) {
+ if (this.isRawType() || other.isRawType()) {
+ return true;
+ }
+ if (this.typeParametersValues().size() != other.typeParametersValues().size()) {
+ throw new IllegalStateException();
+ }
+ for (int i = 0; i < typeParametersValues().size(); i++) {
+ ResolvedType thisParam = typeParametersValues().get(i);
+ ResolvedType otherParam = other.typeParametersValues().get(i);
+ if (!thisParam.equals(otherParam)) {
+ if (thisParam instanceof ResolvedWildcard) {
+ ResolvedWildcard thisParamAsWildcard = (ResolvedWildcard) thisParam;
+ if (thisParamAsWildcard.isSuper() && otherParam.isAssignableBy(thisParamAsWildcard.getBoundedType())) {
+ // ok
+ } else if (thisParamAsWildcard.isExtends() && thisParamAsWildcard.getBoundedType().isAssignableBy(otherParam)) {
+ // ok
+ } else if (!thisParamAsWildcard.isBounded()) {
+ // ok
+ } else {
+ return false;
+ }
+ } else {
+ if (thisParam instanceof ResolvedTypeVariable && otherParam instanceof ResolvedTypeVariable) {
+ List<ResolvedType> thisBounds = thisParam.asTypeVariable().asTypeParameter().getBounds().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)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ //
+ // Private methods
+ //
+
+ private static List<ResolvedType> deriveParams(ResolvedReferenceTypeDeclaration typeDeclaration) {
+ return typeDeclaration.getTypeParameters().stream().map((tp) -> new ResolvedTypeVariable(tp)).collect(Collectors.toList());
+ }
+
+ public abstract ResolvedReferenceType deriveTypeParameters(ResolvedTypeParametersMap typeParametersMap);
+}