Home | History | Annotate | Download | only in declarations
      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.ClassOrInterfaceDeclaration;
     23 import com.github.javaparser.ast.expr.AnnotationExpr;
     24 import com.github.javaparser.ast.type.ClassOrInterfaceType;
     25 import com.github.javaparser.resolution.UnsolvedSymbolException;
     26 import com.github.javaparser.resolution.declarations.*;
     27 import com.github.javaparser.resolution.types.ResolvedReferenceType;
     28 import com.github.javaparser.resolution.types.ResolvedType;
     29 import com.github.javaparser.symbolsolver.core.resolution.Context;
     30 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
     31 import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFactory;
     32 import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration;
     33 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
     34 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
     35 import com.github.javaparser.symbolsolver.model.typesystem.LazyType;
     36 import com.github.javaparser.symbolsolver.model.typesystem.ReferenceTypeImpl;
     37 import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
     38 
     39 import java.util.*;
     40 import java.util.stream.Collectors;
     41 
     42 /**
     43  * @author Federico Tomassetti
     44  */
     45 public class JavaParserInterfaceDeclaration extends AbstractTypeDeclaration implements ResolvedInterfaceDeclaration {
     46 
     47     private TypeSolver typeSolver;
     48     private ClassOrInterfaceDeclaration wrappedNode;
     49     private JavaParserTypeAdapter<ClassOrInterfaceDeclaration> javaParserTypeAdapter;
     50 
     51     public JavaParserInterfaceDeclaration(ClassOrInterfaceDeclaration wrappedNode, TypeSolver typeSolver) {
     52         if (!wrappedNode.isInterface()) {
     53             throw new IllegalArgumentException();
     54         }
     55         this.wrappedNode = wrappedNode;
     56         this.typeSolver = typeSolver;
     57         this.javaParserTypeAdapter = new JavaParserTypeAdapter<>(wrappedNode, typeSolver);
     58     }
     59 
     60     @Override
     61     public Set<ResolvedMethodDeclaration> getDeclaredMethods() {
     62         Set<ResolvedMethodDeclaration> methods = new HashSet<>();
     63         for (BodyDeclaration<?> member : wrappedNode.getMembers()) {
     64             if (member instanceof com.github.javaparser.ast.body.MethodDeclaration) {
     65                 methods.add(new JavaParserMethodDeclaration((com.github.javaparser.ast.body.MethodDeclaration) member, typeSolver));
     66             }
     67         }
     68         return methods;
     69     }
     70 
     71     public Context getContext() {
     72         return JavaParserFactory.getContext(wrappedNode, typeSolver);
     73     }
     74 
     75     public ResolvedType getUsage(Node node) {
     76         throw new UnsupportedOperationException();
     77     }
     78 
     79     @Override
     80     public boolean equals(Object o) {
     81         if (this == o) return true;
     82         if (o == null || getClass() != o.getClass()) return false;
     83 
     84         JavaParserInterfaceDeclaration that = (JavaParserInterfaceDeclaration) o;
     85 
     86         if (!wrappedNode.equals(that.wrappedNode)) return false;
     87 
     88         return true;
     89     }
     90 
     91     @Override
     92     public int hashCode() {
     93         return wrappedNode.hashCode();
     94     }
     95 
     96     @Override
     97     public String getName() {
     98         return wrappedNode.getName().getId();
     99     }
    100 
    101     @Override
    102     public ResolvedInterfaceDeclaration asInterface() {
    103         return this;
    104     }
    105 
    106     @Override
    107     public boolean hasDirectlyAnnotation(String canonicalName) {
    108         for (AnnotationExpr annotationExpr : wrappedNode.getAnnotations()) {
    109             if (solveType(annotationExpr.getName().getId(), typeSolver).getCorrespondingDeclaration().getQualifiedName().equals(canonicalName)) {
    110                 return true;
    111             }
    112         }
    113         return false;
    114     }
    115 
    116     @Override
    117     public boolean isInterface() {
    118         return true;
    119     }
    120 
    121     @Override
    122     public List<ResolvedReferenceType> getInterfacesExtended() {
    123         List<ResolvedReferenceType> interfaces = new ArrayList<>();
    124         if (wrappedNode.getImplementedTypes() != null) {
    125             for (ClassOrInterfaceType t : wrappedNode.getImplementedTypes()) {
    126                 interfaces.add(new ReferenceTypeImpl(solveType(t.getName().getId(), typeSolver).getCorrespondingDeclaration().asInterface(), typeSolver));
    127             }
    128         }
    129         return interfaces;
    130     }
    131 
    132     @Override
    133     public String getPackageName() {
    134         return javaParserTypeAdapter.getPackageName();
    135     }
    136 
    137     @Override
    138     public String getClassName() {
    139         return javaParserTypeAdapter.getClassName();
    140     }
    141 
    142     @Override
    143     public String getQualifiedName() {
    144         return javaParserTypeAdapter.getQualifiedName();
    145     }
    146 
    147     @Override
    148     public boolean isAssignableBy(ResolvedReferenceTypeDeclaration other) {
    149         return javaParserTypeAdapter.isAssignableBy(other);
    150     }
    151 
    152     @Override
    153     public boolean isAssignableBy(ResolvedType type) {
    154         return javaParserTypeAdapter.isAssignableBy(type);
    155     }
    156 
    157     @Override
    158     public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) {
    159         // TODO consider generic types
    160         if (this.getQualifiedName().equals(other.getQualifiedName())) {
    161             return true;
    162         }
    163         if (this.wrappedNode.getExtendedTypes() != null) {
    164             for (ClassOrInterfaceType type : wrappedNode.getExtendedTypes()) {
    165                 ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type);
    166                 if (ancestor.canBeAssignedTo(other)) {
    167                     return true;
    168                 }
    169             }
    170         }
    171 
    172         if (this.wrappedNode.getImplementedTypes() != null) {
    173             for (ClassOrInterfaceType type : wrappedNode.getImplementedTypes()) {
    174                 ResolvedReferenceTypeDeclaration ancestor = (ResolvedReferenceTypeDeclaration) new SymbolSolver(typeSolver).solveType(type);
    175                 if (ancestor.canBeAssignedTo(other)) {
    176                     return true;
    177                 }
    178             }
    179         }
    180 
    181         return false;
    182     }
    183 
    184     @Override
    185     public boolean isTypeParameter() {
    186         return false;
    187     }
    188 
    189     @Override
    190     public List<ResolvedFieldDeclaration> getAllFields() {
    191         List<ResolvedFieldDeclaration> fields = javaParserTypeAdapter.getFieldsForDeclaredVariables();
    192 
    193         getAncestors().forEach(ancestor -> ancestor.getTypeDeclaration().getAllFields().forEach(f -> {
    194             fields.add(new ResolvedFieldDeclaration() {
    195 
    196                 @Override
    197                 public AccessSpecifier accessSpecifier() {
    198                     return f.accessSpecifier();
    199                 }
    200 
    201                 @Override
    202                 public String getName() {
    203                     return f.getName();
    204                 }
    205 
    206                 @Override
    207                 public ResolvedType getType() {
    208                     return ancestor.useThisTypeParametersOnTheGivenType(f.getType());
    209                 }
    210 
    211                 @Override
    212                 public boolean isStatic() {
    213                     return f.isStatic();
    214                 }
    215 
    216                 @Override
    217                 public ResolvedTypeDeclaration declaringType() {
    218                     return f.declaringType();
    219                 }
    220             });
    221         }));
    222 
    223         return fields;
    224     }
    225 
    226 
    227     @Override
    228     public String toString() {
    229         return "JavaParserInterfaceDeclaration{" +
    230                 "wrappedNode=" + wrappedNode +
    231                 '}';
    232     }
    233 
    234     @Deprecated
    235     public SymbolReference<ResolvedTypeDeclaration> solveType(String name, TypeSolver typeSolver) {
    236         if (this.wrappedNode.getName().getId().equals(name)) {
    237             return SymbolReference.solved(this);
    238         }
    239         SymbolReference<ResolvedTypeDeclaration> ref = javaParserTypeAdapter.solveType(name, typeSolver);
    240         if (ref.isSolved()) {
    241             return ref;
    242         }
    243 
    244         String prefix = wrappedNode.getName() + ".";
    245         if (name.startsWith(prefix) && name.length() > prefix.length()) {
    246             return new JavaParserInterfaceDeclaration(this.wrappedNode, typeSolver).solveType(name.substring(prefix.length()), typeSolver);
    247         }
    248 
    249         return getContext().getParent().solveType(name, typeSolver);
    250     }
    251 
    252     @Override
    253     public List<ResolvedReferenceType> getAncestors() {
    254         List<ResolvedReferenceType> ancestors = new ArrayList<>();
    255         if (wrappedNode.getExtendedTypes() != null) {
    256             for (ClassOrInterfaceType extended : wrappedNode.getExtendedTypes()) {
    257                 ancestors.add(toReferenceType(extended));
    258             }
    259         }
    260         if (wrappedNode.getImplementedTypes() != null) {
    261             for (ClassOrInterfaceType implemented : wrappedNode.getImplementedTypes()) {
    262                 ancestors.add(toReferenceType(implemented));
    263             }
    264         }
    265         return ancestors;
    266     }
    267 
    268     @Override
    269     public List<ResolvedTypeParameterDeclaration> getTypeParameters() {
    270         if (this.wrappedNode.getTypeParameters() == null) {
    271             return Collections.emptyList();
    272         } else {
    273             return this.wrappedNode.getTypeParameters().stream().map(
    274                     (tp) -> new JavaParserTypeParameter(tp, typeSolver)
    275             ).collect(Collectors.toList());
    276         }
    277     }
    278 
    279     /**
    280      * Returns the JavaParser node associated with this JavaParserInterfaceDeclaration.
    281      *
    282      * @return A visitable JavaParser node wrapped by this object.
    283      */
    284     public ClassOrInterfaceDeclaration getWrappedNode() {
    285         return wrappedNode;
    286     }
    287 
    288     @Override
    289     public AccessSpecifier accessSpecifier() {
    290         return Helper.toAccessLevel(wrappedNode.getModifiers());
    291     }
    292 
    293     @Override
    294     public Set<ResolvedReferenceTypeDeclaration> internalTypes() {
    295         Set<ResolvedReferenceTypeDeclaration> res = new HashSet<>();
    296         for (BodyDeclaration<?> member : this.wrappedNode.getMembers()) {
    297             if (member instanceof com.github.javaparser.ast.body.TypeDeclaration) {
    298                 res.add(JavaParserFacade.get(typeSolver).getTypeDeclaration((com.github.javaparser.ast.body.TypeDeclaration)member));
    299             }
    300         }
    301         return res;
    302     }
    303 
    304     @Override
    305     public Optional<ResolvedReferenceTypeDeclaration> containerType() {
    306         return javaParserTypeAdapter.containerType();
    307     }
    308 
    309     ///
    310     /// Private methods
    311     ///
    312 
    313     private ResolvedReferenceType toReferenceType(ClassOrInterfaceType classOrInterfaceType) {
    314         SymbolReference<? extends ResolvedTypeDeclaration> ref = null;
    315         if (classOrInterfaceType.toString().indexOf('.') > -1) {
    316             ref = typeSolver.tryToSolveType(classOrInterfaceType.toString());
    317         }
    318         if (ref == null || !ref.isSolved()) {
    319             ref = solveType(classOrInterfaceType.toString(), typeSolver);
    320         }
    321         if (!ref.isSolved()) {
    322             ref = solveType(classOrInterfaceType.getName().getId(), typeSolver);
    323         }
    324         if (!ref.isSolved()) {
    325             throw new UnsolvedSymbolException(classOrInterfaceType.getName().getId());
    326         }
    327         if (!classOrInterfaceType.getTypeArguments().isPresent()) {
    328             return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), typeSolver);
    329         }
    330         List<ResolvedType> superClassTypeParameters = classOrInterfaceType.getTypeArguments().get()
    331                 .stream().map(ta -> new LazyType(v -> JavaParserFacade.get(typeSolver).convert(ta, ta)))
    332                 .collect(Collectors.toList());
    333         return new ReferenceTypeImpl(ref.getCorrespondingDeclaration().asReferenceType(), superClassTypeParameters, typeSolver);
    334     }
    335 }
    336