blob: 8e474fe29f2ff3af46a15adc87df7095b8420f66 [file] [log] [blame]
/*
* 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.model.typesystem;
import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeVariableDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.MethodDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.ReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration;
import com.github.javaparser.symbolsolver.model.declarations.TypeParameterDeclaration.Bound;
import com.github.javaparser.symbolsolver.model.methods.MethodUsage;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Federico Tomassetti
*/
// TODO Remove references to typeSolver: it is needed to instantiate other instances of ReferenceTypeUsage
// and to get the Object type declaration
public class ReferenceTypeImpl extends ReferenceType {
public static ReferenceType undeterminedParameters(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeDeclaration.getTypeParameters().stream().map(
tp -> new TypeVariable(tp)
).collect(Collectors.toList()), typeSolver);
}
@Override
protected ReferenceType create(ReferenceTypeDeclaration typeDeclaration, List<Type> typeParametersCorrected, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeParametersCorrected, typeSolver);
}
@Override
protected ReferenceType create(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
return new ReferenceTypeImpl(typeDeclaration, typeSolver);
}
public ReferenceTypeImpl(ReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) {
super(typeDeclaration, typeSolver);
}
public ReferenceTypeImpl(ReferenceTypeDeclaration typeDeclaration, List<Type> typeParameters, TypeSolver typeSolver) {
super(typeDeclaration, typeParameters, typeSolver);
}
@Override
public TypeParameterDeclaration asTypeParameter() {
if (this.typeDeclaration instanceof JavaParserTypeVariableDeclaration) {
JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) this.typeDeclaration;
return javaParserTypeVariableDeclaration.asTypeParameter();
}
throw new UnsupportedOperationException(this.typeDeclaration.getClass().getCanonicalName());
}
/**
* This method checks if ThisType t = new OtherType() would compile.
*/
@Override
public boolean isAssignableBy(Type other) {
if (other instanceof NullType) {
return !this.isPrimitive();
}
// everything is assignable to Object except void
if (!other.isVoid() && this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
}
// consider boxing
if (other.isPrimitive()) {
if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
} else {
// Check if 'other' can be boxed to match this type
if (isCorrespondingBoxingType(other.describe())) return true;
// Resolve the boxed type and check if it can be assigned via widening reference conversion
SymbolReference<ReferenceTypeDeclaration> type = typeSolver.tryToSolveType(other.asPrimitive().getBoxTypeQName());
return type.getCorrespondingDeclaration().canBeAssignedTo(super.typeDeclaration);
}
}
if (other instanceof LambdaArgumentTypePlaceholder) {
return this.getTypeDeclaration().hasAnnotation(FunctionalInterface.class.getCanonicalName());
} else if (other instanceof ReferenceTypeImpl) {
ReferenceTypeImpl otherRef = (ReferenceTypeImpl) other;
if (compareConsideringTypeParameters(otherRef)) {
return true;
}
for (ReferenceType otherAncestor : otherRef.getAllAncestors()) {
if (compareConsideringTypeParameters(otherAncestor)) {
return true;
}
}
return false;
} else if (other.isTypeVariable()) {
for (Bound bound : other.asTypeVariable().asTypeParameter().getBounds(typeSolver)) {
if (bound.isExtends()) {
if (this.isAssignableBy(bound.getType())) {
return true;
}
}
}
return false;
} else if (other.isConstraint()){
return isAssignableBy(other.asConstraintType().getBound());
} else if (other.isWildcard()) {
if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true;
} else if (other.asWildcard().isExtends()) {
return isAssignableBy(other.asWildcard().getBoundedType());
} else {
return false;
}
} else {
return false;
}
}
@Override
public Set<MethodUsage> getDeclaredMethods() {
// TODO replace variables
Set<MethodUsage> methods = new HashSet<>();
for (MethodDeclaration methodDeclaration : getTypeDeclaration().getDeclaredMethods()) {
MethodUsage methodUsage = new MethodUsage(methodDeclaration);
methods.add(methodUsage);
}
return methods;
}
}