diff options
Diffstat (limited to 'javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java')
-rw-r--r-- | javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java new file mode 100644 index 000000000..bb9f91cc6 --- /dev/null +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserClassDeclaration.java @@ -0,0 +1,397 @@ +/* + * 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.javaparsermodel.declarations; + +import com.github.javaparser.ast.AccessSpecifier; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.*; +import com.github.javaparser.ast.expr.AnnotationExpr; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +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.javaparsermodel.JavaParserFacade; +import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory; +import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration; +import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.model.typesystem.LazyType; +import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.symbolsolver.resolution.SymbolSolver; +import com.google.common.collect.ImmutableList; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Federico Tomassetti + */ +public class JavaParserClassDeclaration extends AbstractClassDeclaration { + + /// + /// Fields + /// + + private TypeSolver typeSolver; + private com.github.javaparser.ast.body.ClassOrInterfaceDeclaration wrappedNode; + private JavaParserTypeAdapter<ClassOrInterfaceDeclaration> javaParserTypeAdapter; + + /// + /// Constructors + /// + + public JavaParserClassDeclaration(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration wrappedNode, + TypeSolver typeSolver) { + if (wrappedNode.isInterface()) { + throw new IllegalArgumentException("Interface given"); + } + this.wrappedNode = wrappedNode; + this.typeSolver = typeSolver; + this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver); + } + + /// + /// Public methods: from Object + /// + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaParserClassDeclaration that = (JavaParserClassDeclaration) o; + + if (!wrappedNode.equals(that.wrappedNode)) return false; + + return true; + } + + @Override + public int hashCode() { + return wrappedNode.hashCode(); + } + + @Override + public String toString() { + return "JavaParserClassDeclaration{" + + "wrappedNode=" + wrappedNode + + '}'; + } + + /// + /// Public methods: fields + /// + + @Override + public List<ResolvedFieldDeclaration> getAllFields() { + List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables(); + + getAncestors().forEach(ancestor -> ancestor.getTypeDeclaration().getAllFields().forEach(f -> { + fields.add(new ResolvedFieldDeclaration() { + + @Override + public AccessSpecifier accessSpecifier() { + return f.accessSpecifier(); + } + + @Override + public String getName() { + return f.getName(); + } + + @Override + public ResolvedType getType() { + return ancestor.useThisTypeParametersOnTheGivenType(f.getType()); + } + + @Override + public boolean isStatic() { + return f.isStatic(); + } + + @Override + public ResolvedTypeDeclaration declaringType() { + return f.declaringType(); + } + }); + })); + + return fields; + } + + /// + /// Public methods + /// + + public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<ResolvedType> parameterTypes) { + Context ctx = getContext(); + return ctx.solveMethod(name, parameterTypes, false, typeSolver); + } + + @Deprecated + public Context getContext() { + return JavaParserFactory.getContext(wrappedNode, typeSolver); + } + + public ResolvedType getUsage(Node node) { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return wrappedNode.getName().getId(); + } + + @Override + public ResolvedReferenceType getSuperClass() { + if (wrappedNode.getExtendedTypes().isEmpty()) { + return object(); + } else { + return toReferenceType(wrappedNode.getExtendedTypes().get(0)); + } + } + + @Override + public List<ResolvedReferenceType> getInterfaces() { + List<ResolvedReferenceType> interfaces = new ArrayList<>(); + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) { + interfaces.add(toReferenceType(t)); + } + } + return interfaces; + } + + @Override + public List<ResolvedConstructorDeclaration> getConstructors() { + List<ResolvedConstructorDeclaration> declared = new LinkedList<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.ConstructorDeclaration) { + com.github.javaparser.ast.body.ConstructorDeclaration constructorDeclaration = (com.github.javaparser.ast.body.ConstructorDeclaration) member; + declared.add(new JavaParserConstructorDeclaration(this, constructorDeclaration, typeSolver)); + } + } + if (declared.isEmpty()) { + // If there are no constructors insert the default constructor + return ImmutableList.of(new DefaultConstructorDeclaration(this)); + } else { + return declared; + } + } + + @Override + public boolean hasDirectlyAnnotation(String canonicalName) { + for (AnnotationExpr annotationExpr : wrappedNode.getAnnotations()) { + if (solveType(annotationExpr.getName().getId(), typeSolver).getCorrespondingDeclaration().getQualifiedName().equals(canonicalName)) { + return true; + } + } + return false; + } + + @Override + public boolean isInterface() { + return wrappedNode.isInterface(); + } + + @Override + public String getPackageName() { + return javaParserTypeAdapter.getPackageName(); + } + + @Override + public String getClassName() { + return javaParserTypeAdapter.getClassName(); + } + + @Override + public String getQualifiedName() { + return javaParserTypeAdapter.getQualifiedName(); + } + + @Override + public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) { + return javaParserTypeAdapter.isAssignableBy(other); + } + + @Override + public boolean isAssignableBy(ResolvedType type) { + return javaParserTypeAdapter.isAssignableBy(type); + } + + @Override + public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { + // TODO consider generic types + if (this.getQualifiedName().equals(other.getQualifiedName())) { + return true; + } + ResolvedClassDeclaration superclass = (ResolvedClassDeclaration) getSuperClass().getTypeDeclaration(); + if (superclass != null) { + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (Object.class.getCanonicalName().equals(superclass.getQualifiedName())) { + return true; + } + if (superclass.canBeAssignedTo(other)) { + return true; + } + } + + if (this.wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) { + ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type); + if (ancestor.canBeAssignedTo(other)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isTypeParameter() { + return false; + } + + @Deprecated + public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) { + if (this.wrappedNode.getName().getId().equals(name)) { + return SymbolReference.solved(this); + } + SymbolReference<ResolvedTypeDeclaration> ref = javaParserTypeAdapter.solveType(name, typeSolver); + if (ref.isSolved()) { + return ref; + } + + String prefix = wrappedNode.getName() + "."; + if (name.startsWith(prefix) && name.length() > prefix.length()) { + return new JavaParserClassDeclaration(this.wrappedNode, typeSolver).solveType(name.substring(prefix.length()), typeSolver); + } + + return getContext().getParent().solveType(name, typeSolver); + } + + @Override + public List<ResolvedReferenceType> getAncestors() { + List<ResolvedReferenceType> ancestors = new ArrayList<>(); + + // We want to avoid infinite recursion in case of Object having Object as ancestor + if (!(Object.class.getCanonicalName().equals(getQualifiedName()))) { + ResolvedReferenceType superclass = getSuperClass(); + if (superclass != null) { + ancestors.add(superclass); + } + if (wrappedNode.getImplementedTypes() != null) { + for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) { + ResolvedReferenceType ancestor = toReferenceType(implemented); + ancestors.add(ancestor); + } + } + } + + return ancestors; + } + + @Override + public Set<ResolvedMethodDeclaration> getDeclaredMethods() { + Set<ResolvedMethodDeclaration> methods = new HashSet<>(); + for (BodyDeclaration<?> member : wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) { + methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver)); + } + } + return methods; + } + + @Override + public List<ResolvedTypeParameterDeclaration> getTypeParameters() { + return this.wrappedNode.getTypeParameters().stream().map( + (tp) -> new JavaParserTypeParameter(tp, typeSolver) + ).collect(Collectors.toList()); + } + + /** + * Returns the JavaParser node associated with this JavaParserClassDeclaration. + * + * @return A visitable JavaParser node wrapped by this object. + */ + public com.github.javaparser.ast.body.ClassOrInterfaceDeclaration getWrappedNode() { + return wrappedNode; + } + + @Override + public AccessSpecifier accessSpecifier() { + return Helper.toAccessLevel(wrappedNode.getModifiers()); + } + + /// + /// Protected methods + /// + + @Override + protected ResolvedReferenceType object() { + return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver); + } + + @Override + public Set<ResolvedReferenceTypeDeclaration> internalTypes() { + Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>(); + for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) { + if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) { + res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member)); + } + } + return res; + } + + @Override + public Optional<ResolvedReferenceTypeDeclaration> containerType() { + return javaParserTypeAdapter.containerType(); + } + + /// + /// Private methods + /// + + private ResolvedReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) { + String className = classOrInterfaceType.getName().getId(); + if (classOrInterfaceType.getScope().isPresent()) { + // look for the qualified name (for example class of type Rectangle2D.Double) + className = classOrInterfaceType.getScope().get().toString() + "." + className; + } + SymbolReference<ResolvedTypeDeclaration> ref = solveType(className, typeSolver); + if (!ref.isSolved()) { + Optional<ClassOrInterfaceType> localScope = classOrInterfaceType.getScope(); + if (localScope.isPresent()) { + String localName = localScope.get().getName().getId() + "." + classOrInterfaceType.getName().getId(); + ref = solveType(localName, typeSolver); + } + } + if (!ref.isSolved()) { + throw new UnsolvedSymbolException(classOrInterfaceType.getName().getId()); + } + if (!classOrInterfaceType.getTypeArguments().isPresent()) { + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), typeSolver); + } + List<ResolvedType> superClassTypeParameters = classOrInterfaceType.getTypeArguments().get() + .stream().map(ta -> new LazyType(v -> JavaParserFacade.get(typeSolver).convert(ta, ta))) + .collect(Collectors.toList()); + return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), superClassTypeParameters, typeSolver); + } +} |