aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java
diff options
context:
space:
mode:
Diffstat (limited to 'javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java')
-rw-r--r--javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java275
1 files changed, 275 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java
new file mode 100644
index 000000000..9a54a09e0
--- /dev/null
+++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java
@@ -0,0 +1,275 @@
+/*
+ * 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.javassistmodel;
+
+import com.github.javaparser.ast.AccessSpecifier;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.resolution.MethodUsage;
+import com.github.javaparser.resolution.UnsolvedSymbolException;
+import com.github.javaparser.resolution.declarations.*;
+import com.github.javaparser.resolution.types.ResolvedReferenceType;
+import com.github.javaparser.resolution.types.ResolvedType;
+import com.github.javaparser.symbolsolver.core.resolution.Context;
+import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
+import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
+import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
+import com.github.javaparser.symbolsolver.resolution.MethodResolutionLogic;
+import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+import javassist.bytecode.AccessFlag;
+import javassist.bytecode.SyntheticAttribute;
+
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * @author Federico Tomassetti
+ */
+public class JavassistEnumDeclaration extends AbstractTypeDeclaration implements ResolvedEnumDeclaration {
+
+ private CtClass ctClass;
+ private TypeSolver typeSolver;
+ private JavassistTypeDeclarationAdapter javassistTypeDeclarationAdapter;
+
+ public JavassistEnumDeclaration(CtClass ctClass, TypeSolver typeSolver) {
+ if (ctClass == null) {
+ throw new IllegalArgumentException();
+ }
+ if (!ctClass.isEnum()) {
+ throw new IllegalArgumentException("Trying to instantiate a JavassistEnumDeclaration with something which is not an enum: " + ctClass.toString());
+ }
+ this.ctClass = ctClass;
+ this.typeSolver = typeSolver;
+ this.javassistTypeDeclarationAdapter = new JavassistTypeDeclarationAdapter(ctClass, typeSolver);
+ }
+
+ @Override
+ public AccessSpecifier accessSpecifier() {
+ return JavassistFactory.modifiersToAccessLevel(ctClass.getModifiers());
+ }
+
+ @Override
+ public String getPackageName() {
+ return ctClass.getPackageName();
+ }
+
+ @Override
+ public String getClassName() {
+ String name = ctClass.getName().replace('$', '.');
+ if (getPackageName() != null) {
+ return name.substring(getPackageName().length() + 1, name.length());
+ }
+ return name;
+ }
+
+ @Override
+ public String getQualifiedName() {
+ return ctClass.getName().replace('$', '.');
+ }
+
+ @Override
+ public List<ResolvedReferenceType> getAncestors() {
+ // Direct ancestors of an enum are java.lang.Enum and interfaces
+ List<ResolvedReferenceType> ancestors = new LinkedList<>();
+
+ try {
+ CtClass superClass = ctClass.getSuperclass();
+
+ if (superClass != null) {
+ ResolvedType superClassTypeUsage = JavassistFactory.typeUsageFor(superClass, typeSolver);
+
+ if (superClassTypeUsage.isReferenceType()) {
+ ancestors.add(superClassTypeUsage.asReferenceType());
+ }
+ }
+
+ for (CtClass interfaze : ctClass.getInterfaces()) {
+ ResolvedType interfazeTypeUsage = JavassistFactory.typeUsageFor(interfaze, typeSolver);
+
+ if (interfazeTypeUsage.isReferenceType()) {
+ ancestors.add(interfazeTypeUsage.asReferenceType());
+ }
+ }
+ } catch (NotFoundException e) {
+ throw new RuntimeException("Ancestor not found for " + ctClass.getName() + ".", e);
+ }
+
+ return ancestors;
+ }
+
+ @Override
+ public ResolvedFieldDeclaration getField(String name) {
+ Optional<ResolvedFieldDeclaration> field = javassistTypeDeclarationAdapter.getDeclaredFields().stream().filter(f -> f.getName().equals(name)).findFirst();
+
+ return field.orElseThrow(() -> new RuntimeException("Field " + name + " does not exist in " + ctClass.getName() + "."));
+ }
+
+ @Override
+ public boolean hasField(String name) {
+ return javassistTypeDeclarationAdapter.getDeclaredFields().stream().anyMatch(f -> f.getName().equals(name));
+ }
+
+ @Override
+ public List<ResolvedFieldDeclaration> getAllFields() {
+ return javassistTypeDeclarationAdapter.getDeclaredFields();
+ }
+
+ @Override
+ public Set<ResolvedMethodDeclaration> getDeclaredMethods() {
+ return javassistTypeDeclarationAdapter.getDeclaredMethods();
+ }
+
+ @Override
+ public boolean isAssignableBy(ResolvedType type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hasDirectlyAnnotation(String canonicalName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getName() {
+ String[] nameElements = ctClass.getSimpleName().replace('$', '.').split("\\.");
+ return nameElements[nameElements.length - 1];
+ }
+
+ @Override
+ public List<ResolvedTypeParameterDeclaration> getTypeParameters() {
+ return javassistTypeDeclarationAdapter.getTypeParameters();
+ }
+
+ @Override
+ public Optional<ResolvedReferenceTypeDeclaration> containerType() {
+ return javassistTypeDeclarationAdapter.containerType();
+ }
+
+ public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> argumentsTypes, boolean staticOnly) {
+ List<ResolvedMethodDeclaration> candidates = new ArrayList<>();
+ Predicate<CtMethod> staticOnlyCheck = m -> !staticOnly || (staticOnly && Modifier.isStatic(m.getModifiers()));
+ for (CtMethod method : ctClass.getDeclaredMethods()) {
+ boolean isSynthetic = method.getMethodInfo().getAttribute(SyntheticAttribute.tag) != null;
+ boolean isNotBridge = (method.getMethodInfo().getAccessFlags() & AccessFlag.BRIDGE) == 0;
+ if (method.getName().equals(name) && !isSynthetic && isNotBridge && staticOnlyCheck.test(method)) {
+ candidates.add(new JavassistMethodDeclaration(method, typeSolver));
+ }
+ }
+
+ try {
+ CtClass superClass = ctClass.getSuperclass();
+ if (superClass != null) {
+ SymbolReference<ResolvedMethodDeclaration> ref = new JavassistClassDeclaration(superClass, typeSolver).solveMethod(name, argumentsTypes, staticOnly);
+ if (ref.isSolved()) {
+ candidates.add(ref.getCorrespondingDeclaration());
+ }
+ }
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ return MethodResolutionLogic.findMostApplicable(candidates, name, argumentsTypes, typeSolver);
+ }
+
+ public Optional<MethodUsage> solveMethodAsUsage(String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver,
+ Context invokationContext, List<ResolvedType> typeParameterValues) {
+ return JavassistUtils.getMethodUsage(ctClass, name, argumentsTypes, typeSolver, invokationContext);
+ }
+
+ @Override
+ public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
+ try {
+ /*
+ Get all internal types of the current class and get their corresponding ReferenceTypeDeclaration.
+ Finally, return them in a Set.
+ */
+ return Arrays.stream(ctClass.getDeclaredClasses()).map(itype -> JavassistFactory.toTypeDeclaration(itype, typeSolver)).collect(Collectors.toSet());
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public ResolvedReferenceTypeDeclaration getInternalType(String name) {
+ /*
+ The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
+ In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
+ */
+ Optional<ResolvedReferenceTypeDeclaration> type =
+ this.internalTypes().stream().filter(f -> f.getName().endsWith(name)).findFirst();
+ return type.orElseThrow(() ->
+ new UnsolvedSymbolException("Internal type not found: " + name));
+ }
+
+ @Override
+ public boolean hasInternalType(String name) {
+ /*
+ The name of the ReferenceTypeDeclaration could be composed on the internal class and the outer class, e.g. A$B. That's why we search the internal type in the ending part.
+ In case the name is composed of the internal type only, i.e. f.getName() returns B, it will also works.
+ */
+ return this.internalTypes().stream().anyMatch(f -> f.getName().endsWith(name));
+ }
+
+ public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
+ for (CtField field : ctClass.getDeclaredFields()) {
+ if (field.getName().equals(name)) {
+ return SymbolReference.solved(new JavassistFieldDeclaration(field, typeSolver));
+ }
+ }
+
+ String[] interfaceFQNs = getInterfaceFQNs();
+ for (String interfaceFQN : interfaceFQNs) {
+ SymbolReference<? extends ResolvedValueDeclaration> interfaceRef = solveSymbolForFQN(name, typeSolver, interfaceFQN);
+ if (interfaceRef.isSolved()) {
+ return interfaceRef;
+ }
+ }
+
+ return SymbolReference.unsolved(ResolvedValueDeclaration.class);
+ }
+
+ private SymbolReference<? extends ResolvedValueDeclaration> solveSymbolForFQN(String symbolName, TypeSolver typeSolver, String fqn) {
+ if (fqn == null) {
+ return SymbolReference.unsolved(ResolvedValueDeclaration.class);
+ }
+
+ ResolvedReferenceTypeDeclaration fqnTypeDeclaration = typeSolver.solveType(fqn);
+ return new SymbolSolver(typeSolver).solveSymbolInType(fqnTypeDeclaration, symbolName);
+ }
+
+ private String[] getInterfaceFQNs() {
+ return ctClass.getClassFile().getInterfaces();
+ }
+
+ @Override
+ public List<ResolvedEnumConstantDeclaration> getEnumConstants() {
+ return Arrays.stream(ctClass.getFields())
+ .filter(f -> (f.getFieldInfo2().getAccessFlags() & AccessFlag.ENUM) != 0)
+ .map(f -> new JavassistEnumConstantDeclaration(f, typeSolver))
+ .collect(Collectors.toList());
+ }
+}