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.javaparsermodel.declarations; 18 19 import com.github.javaparser.ast.AccessSpecifier; 20 import com.github.javaparser.ast.Node; 21 import com.github.javaparser.ast.body.BodyDeclaration; 22 import com.github.javaparser.ast.body.EnumConstantDeclaration; 23 import com.github.javaparser.ast.type.ClassOrInterfaceType; 24 import com.github.javaparser.resolution.MethodUsage; 25 import com.github.javaparser.resolution.UnsolvedSymbolException; 26 import com.github.javaparser.resolution.declarations.*; 27 import com.github.javaparser.resolution.types.ResolvedArrayType; 28 import com.github.javaparser.resolution.types.ResolvedReferenceType; 29 import com.github.javaparser.resolution.types.ResolvedType; 30 import com.github.javaparser.resolution.types.parametrization.ResolvedTypeParametersMap; 31 import com.github.javaparser.symbolsolver.core.resolution.Context; 32 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; 33 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; 34 import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; 35 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; 36 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; 37 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; 38 import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionFactory; 39 import com.github.javaparser.symbolsolver.resolution.SymbolSolver; 40 41 import java.io.Serializable; 42 import java.util.*; 43 import java.util.stream.Collectors; 44 45 /** 46 * @author Federico Tomassetti 47 */ 48 public class JavaParserEnumDeclaration extends AbstractTypeDeclaration implements ResolvedEnumDeclaration { 49 50 private TypeSolver typeSolver; 51 private com.github.javaparser.ast.body.EnumDeclaration wrappedNode; 52 private JavaParserTypeAdapter<com.github.javaparser.ast.body.EnumDeclaration> javaParserTypeAdapter; 53 54 public JavaParserEnumDeclaration(com.github.javaparser.ast.body.EnumDeclaration wrappedNode, TypeSolver typeSolver) { 55 this.wrappedNode = wrappedNode; 56 this.typeSolver = typeSolver; 57 this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); 58 } 59 60 @Override 61 public String toString() { 62 return "JavaParserEnumDeclaration{" + 63 "wrappedNode=" + wrappedNode + 64 '}'; 65 } 66 67 @Override 68 public Set<ResolvedMethodDeclaration> getDeclaredMethods() { 69 Set<ResolvedMethodDeclaration> methods = new HashSet<>(); 70 for (BodyDeclaration<?> member : wrappedNode.getMembers()) { 71 if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { 72 methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); 73 } 74 } 75 return methods; 76 } 77 78 public Context getContext() { 79 return JavaParserFactory.getContext(wrappedNode, typeSolver); 80 } 81 82 @Override 83 public String getName() { 84 return wrappedNode.getName().getId(); 85 } 86 87 @Override 88 public boolean isField() { 89 return false; 90 } 91 92 @Override 93 public boolean isParameter() { 94 return false; 95 } 96 97 @Override 98 public boolean isType() { 99 return true; 100 } 101 102 @Override 103 public boolean hasDirectlyAnnotation(String canonicalName) { 104 throw new UnsupportedOperationException(); 105 } 106 107 @Override 108 public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { 109 String otherName = other.getQualifiedName(); 110 // Enums cannot be extended 111 if (otherName.equals(this.getQualifiedName())) { 112 return true; 113 } 114 if (otherName.equals(Enum.class.getCanonicalName())) { 115 return true; 116 } 117 // Enum implements Comparable and Serializable 118 if (otherName.equals(Comparable.class.getCanonicalName())) { 119 return true; 120 } 121 if (otherName.equals(Serializable.class.getCanonicalName())) { 122 return true; 123 } 124 if (otherName.equals(Object.class.getCanonicalName())) { 125 return true; 126 } 127 return false; 128 } 129 130 @Override 131 public boolean isClass() { 132 return false; 133 } 134 135 @Override 136 public boolean isInterface() { 137 return false; 138 } 139 140 @Override 141 public String getPackageName() { 142 return javaParserTypeAdapter.getPackageName(); 143 } 144 145 @Override 146 public String getClassName() { 147 return javaParserTypeAdapter.getClassName(); 148 } 149 150 @Override 151 public String getQualifiedName() { 152 return javaParserTypeAdapter.getQualifiedName(); 153 } 154 155 @Override 156 public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { 157 return javaParserTypeAdapter.isAssignableBy(other); 158 } 159 160 @Override 161 public boolean isAssignableBy(ResolvedType type) { 162 return javaParserTypeAdapter.isAssignableBy(type); 163 } 164 165 @Override 166 public boolean isTypeParameter() { 167 return false; 168 } 169 170 @Override 171 public boolean equals(Object o) { 172 if (this == o) return true; 173 if (o == null || getClass() != o.getClass()) return false; 174 175 JavaParserEnumDeclaration that = (JavaParserEnumDeclaration) o; 176 177 if (!wrappedNode.equals(that.wrappedNode)) return false; 178 179 return true; 180 } 181 182 @Override 183 public int hashCode() { 184 return wrappedNode.hashCode(); 185 } 186 187 @Deprecated 188 public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> parameterTypes, 189 TypeSolver typeSolver, Context invokationContext, List<ResolvedType> typeParameterValues) { 190 if (name.equals("values") && parameterTypes.isEmpty()) { 191 return Optional.of(new ValuesMethod(this, typeSolver).getUsage(null)); 192 } 193 // TODO add methods inherited from Enum 194 return getContext().solveMethodAsUsage(name, parameterTypes, typeSolver); 195 } 196 197 @Override 198 public List<ResolvedFieldDeclaration> getAllFields() { 199 List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); 200 201 if (this.wrappedNode.getEntries() != null) { 202 for (EnumConstantDeclaration member : this.wrappedNode.getEntries()) { 203 fields.add(new JavaParserFieldDeclaration(member, typeSolver)); 204 } 205 } 206 207 return fields; 208 } 209 210 @Override 211 public List<ResolvedReferenceType> getAncestors() { 212 List<ResolvedReferenceType> ancestors = new ArrayList<>(); 213 ResolvedReferenceType enumClass = ReflectionFactory.typeUsageFor(Enum.class, typeSolver).asReferenceType(); 214 ResolvedTypeParameterDeclaration eTypeParameter = enumClass.getTypeDeclaration().getTypeParameters().get(0); 215 enumClass = enumClass.deriveTypeParameters(new ResolvedTypeParametersMap.Builder().setValue(eTypeParameter, new ReferenceTypeImpl(this, typeSolver)).build()); 216 ancestors.add(enumClass); 217 if (wrappedNode.getImplementedTypes() != null) { 218 for (ClassOrInterfaceType implementedType : wrappedNode.getImplementedTypes()) { 219 SymbolReference<ResolvedTypeDeclaration> implementedDeclRef = new SymbolSolver(typeSolver).solveTypeInType(this, implementedType.getName().getId()); 220 if (!implementedDeclRef.isSolved()) { 221 throw new UnsolvedSymbolException(implementedType.getName().getId()); 222 } 223 ancestors.add(new ReferenceTypeImpl((ResolvedReferenceTypeDeclaration) implementedDeclRef.getCorrespondingDeclaration(), typeSolver)); 224 } 225 } 226 return ancestors; 227 } 228 229 @Override 230 public List<ResolvedTypeParameterDeclaration> getTypeParameters() { 231 return Collections.emptyList(); 232 } 233 234 /** 235 * Returns the JavaParser node associated with this JavaParserEnumDeclaration. 236 * 237 * @return A visitable JavaParser node wrapped by this object. 238 */ 239 public com.github.javaparser.ast.body.EnumDeclaration getWrappedNode() { 240 return wrappedNode; 241 } 242 243 @Override 244 public List<ResolvedEnumConstantDeclaration> getEnumConstants() { 245 return wrappedNode.getEntries().stream() 246 .map(entry -> new JavaParserEnumConstantDeclaration(entry, typeSolver)) 247 .collect(Collectors.toList()); 248 } 249 250 // Needed by ContextHelper 251 public static class ValuesMethod implements ResolvedMethodDeclaration { 252 253 private JavaParserEnumDeclaration enumDeclaration; 254 private TypeSolver typeSolver; 255 256 public ValuesMethod(JavaParserEnumDeclaration enumDeclaration, TypeSolver typeSolver) { 257 this.enumDeclaration = enumDeclaration; 258 this.typeSolver = typeSolver; 259 } 260 261 @Override 262 public ResolvedReferenceTypeDeclaration declaringType() { 263 return enumDeclaration; 264 } 265 266 @Override 267 public ResolvedType getReturnType() { 268 return new ResolvedArrayType(new ReferenceTypeImpl(enumDeclaration, typeSolver)); 269 } 270 271 @Override 272 public int getNumberOfParams() { 273 return 0; 274 } 275 276 @Override 277 public ResolvedParameterDeclaration getParam(int i) { 278 throw new UnsupportedOperationException(); 279 } 280 281 public MethodUsage getUsage(Node node) { 282 throw new UnsupportedOperationException(); 283 } 284 285 public MethodUsage resolveTypeVariables(Context context, List<ResolvedType> parameterTypes) { 286 return new MethodUsage(this); 287 } 288 289 @Override 290 public boolean isAbstract() { 291 throw new UnsupportedOperationException(); 292 } 293 294 @Override 295 public boolean isDefaultMethod() { 296 return false; 297 } 298 299 @Override 300 public boolean isStatic() { 301 return false; 302 } 303 304 @Override 305 public String getName() { 306 return "values"; 307 } 308 309 @Override 310 public List<ResolvedTypeParameterDeclaration> getTypeParameters() { 311 return Collections.emptyList(); 312 } 313 314 @Override 315 public AccessSpecifier accessSpecifier() { 316 return Helper.toAccessLevel(enumDeclaration.getWrappedNode().getModifiers()); 317 } 318 319 @Override 320 public int getNumberOfSpecifiedExceptions() { 321 return 0; 322 } 323 324 @Override 325 public ResolvedType getSpecifiedException(int index) { 326 throw new UnsupportedOperationException("The values method of an enum does not throw any exception"); 327 } 328 } 329 330 @Override 331 public AccessSpecifier accessSpecifier() { 332 throw new UnsupportedOperationException(); 333 } 334 335 @Override 336 public Set<ResolvedReferenceTypeDeclaration> internalTypes() { 337 Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); 338 for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { 339 if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { 340 res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); 341 } 342 } 343 return res; 344 } 345 346 @Override 347 public Optional<ResolvedReferenceTypeDeclaration> containerType() { 348 return javaParserTypeAdapter.containerType(); 349 } 350 } 351