1 /* 2 * Copyright 2016 Federico Tomassetti 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.github.javaparser.symbolsolver.model.typesystem; 18 19 import com.github.javaparser.resolution.MethodUsage; 20 import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; 21 import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; 22 import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; 23 import com.github.javaparser.resolution.types.ResolvedReferenceType; 24 import com.github.javaparser.resolution.types.ResolvedType; 25 import com.github.javaparser.resolution.types.ResolvedTypeTransformer; 26 import com.github.javaparser.resolution.types.ResolvedTypeVariable; 27 import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap; 28 import com.github.javaparser.symbolsolver.javaparsermodel.LambdaArgumentTypePlaceholder; 29 import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserTypeVariableDeclaration; 30 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 31 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 32 33 import java.util.Collections; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Set; 37 import java.util.stream.Collectors; 38 39 /** 40 * @author Federico Tomassetti 41 */ 42 // TODO Remove references to typeSolver: it is needed to instantiate other instances of ReferenceTypeUsage 43 // and to get the Object type declaration 44 public class ReferenceTypeImpl extends ResolvedReferenceType { 45 46 private TypeSolver typeSolver; 47 48 public static ResolvedReferenceType undeterminedParameters(ResolvedReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) { 49 return new ReferenceTypeImpl(typeDeclaration, typeDeclaration.getTypeParameters().stream().map( 50 ResolvedTypeVariable::new 51 ).collect(Collectors.toList()), typeSolver); 52 } 53 54 @Override 55 protected ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeParametersCorrected) { 56 return new ReferenceTypeImpl(typeDeclaration, typeParametersCorrected, typeSolver); 57 } 58 59 @Override 60 protected ResolvedReferenceType create(ResolvedReferenceTypeDeclaration typeDeclaration) { 61 return new ReferenceTypeImpl(typeDeclaration, typeSolver); 62 } 63 64 public ReferenceTypeImpl(ResolvedReferenceTypeDeclaration typeDeclaration, TypeSolver typeSolver) { 65 super(typeDeclaration); 66 this.typeSolver = typeSolver; 67 } 68 69 public ReferenceTypeImpl(ResolvedReferenceTypeDeclaration typeDeclaration, List<ResolvedType> typeArguments, TypeSolver typeSolver) { 70 super(typeDeclaration, typeArguments); 71 this.typeSolver = typeSolver; 72 } 73 74 @Override 75 public ResolvedTypeParameterDeclaration asTypeParameter() { 76 if (this.typeDeclaration instanceof JavaParserTypeVariableDeclaration) { 77 JavaParserTypeVariableDeclaration javaParserTypeVariableDeclaration = (JavaParserTypeVariableDeclaration) this.typeDeclaration; 78 return javaParserTypeVariableDeclaration.asTypeParameter(); 79 } 80 throw new UnsupportedOperationException(this.typeDeclaration.getClass().getCanonicalName()); 81 } 82 83 /** 84 * This method checks if ThisType t = new OtherType() would compile. 85 */ 86 @Override 87 public boolean isAssignableBy(ResolvedType other) { 88 if (other instanceof NullType) { 89 return !this.isPrimitive(); 90 } 91 // everything is assignable to Object except void 92 if (!other.isVoid() && this.getQualifiedName().equals(Object.class.getCanonicalName())) { 93 return true; 94 } 95 // consider boxing 96 if (other.isPrimitive()) { 97 if (this.getQualifiedName().equals(Object.class.getCanonicalName())) { 98 return true; 99 } else { 100 // Check if 'other' can be boxed to match this type 101 if (isCorrespondingBoxingType(other.describe())) return true; 102 103 // Resolve the boxed type and check if it can be assigned via widening reference conversion 104 SymbolReference<ResolvedReferenceTypeDeclaration> type = typeSolver.tryToSolveType(other.asPrimitive().getBoxTypeQName()); 105 return type.getCorrespondingDeclaration().canBeAssignedTo(super.typeDeclaration); 106 } 107 } 108 if (other instanceof LambdaArgumentTypePlaceholder) { 109 return this.getTypeDeclaration().hasAnnotation(FunctionalInterface.class.getCanonicalName()); 110 } else if (other instanceof ReferenceTypeImpl) { 111 ReferenceTypeImpl otherRef = (ReferenceTypeImpl) other; 112 if (compareConsideringTypeParameters(otherRef)) { 113 return true; 114 } 115 for (ResolvedReferenceType otherAncestor : otherRef.getAllAncestors()) { 116 if (compareConsideringTypeParameters(otherAncestor)) { 117 return true; 118 } 119 } 120 return false; 121 } else if (other.isTypeVariable()) { 122 for (ResolvedTypeParameterDeclaration.Bound bound : other.asTypeVariable().asTypeParameter().getBounds()) { 123 if (bound.isExtends()) { 124 if (this.isAssignableBy(bound.getType())) { 125 return true; 126 } 127 } 128 } 129 return false; 130 } else if (other.isConstraint()){ 131 return isAssignableBy(other.asConstraintType().getBound()); 132 } else if (other.isWildcard()) { 133 if (this.getQualifiedName().equals(Object.class.getCanonicalName())) { 134 return true; 135 } else if (other.asWildcard().isExtends()) { 136 return isAssignableBy(other.asWildcard().getBoundedType()); 137 } else { 138 return false; 139 } 140 } else { 141 return false; 142 } 143 } 144 145 @Override 146 public Set<MethodUsage> getDeclaredMethods() { 147 // TODO replace variables 148 Set<MethodUsage> methods = new HashSet<>(); 149 for (ResolvedMethodDeclaration methodDeclaration : getTypeDeclaration().getDeclaredMethods()) { 150 MethodUsage methodUsage = new MethodUsage(methodDeclaration); 151 methods.add(methodUsage); 152 } 153 return methods; 154 } 155 156 @Override 157 public ResolvedType toRawType() { 158 if (this.isRawType()) { 159 return this; 160 } else { 161 return new ReferenceTypeImpl(typeDeclaration, typeSolver); 162 } 163 } 164 165 @Override 166 public boolean mention(List<ResolvedTypeParameterDeclaration> typeParameters) { 167 return typeParametersValues().stream().anyMatch(tp -> tp.mention(typeParameters)); 168 } 169 170 /** 171 * Execute a transformation on all the type parameters of this element. 172 */ 173 @Override 174 public ResolvedType transformTypeParameters(ResolvedTypeTransformer transformer) { 175 ResolvedType result = this; 176 int i = 0; 177 for (ResolvedType tp : this.typeParametersValues()) { 178 ResolvedType transformedTp = transformer.transform(tp); 179 // Identity comparison on purpose 180 if (transformedTp != tp) { 181 List<ResolvedType> typeParametersCorrected = result.asReferenceType().typeParametersValues(); 182 typeParametersCorrected.set(i, transformedTp); 183 result = create(typeDeclaration, typeParametersCorrected); 184 } 185 i++; 186 } 187 return result; 188 } 189 190 public List<ResolvedReferenceType> getAllAncestors() { 191 // We need to go through the inheritance line and propagate the type parametes 192 193 List<ResolvedReferenceType> ancestors = typeDeclaration.getAllAncestors(); 194 195 ancestors = ancestors.stream() 196 .map(a -> typeParametersMap().replaceAll(a).asReferenceType()) 197 .collect(Collectors.toList()); 198 199 // Avoid repetitions of Object 200 ancestors.removeIf(a -> a.getQualifiedName().equals(Object.class.getCanonicalName())); 201 ResolvedReferenceTypeDeclaration objectType = typeSolver.solveType(Object.class.getCanonicalName()); 202 ResolvedReferenceType objectRef = create(objectType); 203 ancestors.add(objectRef); 204 return ancestors; 205 } 206 207 public ResolvedReferenceType deriveTypeParameters(ResolvedTypeParametersMap typeParametersMap) { 208 return create(typeDeclaration, typeParametersMap); 209 } 210 211 } 212