Home | History | Annotate | Download | only in javaparser
      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.javaparser;
     18 
     19 import com.github.javaparser.ast.CompilationUnit;
     20 import com.github.javaparser.ast.Node;
     21 import com.github.javaparser.ast.body.*;
     22 import com.github.javaparser.ast.expr.MethodCallExpr;
     23 import com.github.javaparser.ast.expr.NameExpr;
     24 import com.github.javaparser.ast.expr.SimpleName;
     25 import com.github.javaparser.ast.stmt.ReturnStmt;
     26 import com.github.javaparser.ast.stmt.SwitchStmt;
     27 
     28 import java.util.List;
     29 import java.util.Optional;
     30 
     31 /**
     32  * This class can be used to easily retrieve nodes from a JavaParser AST.
     33  *
     34  * @author Federico Tomassetti
     35  */
     36 public final class Navigator {
     37 
     38     private Navigator() {
     39         // prevent instantiation
     40     }
     41 
     42     /**
     43      * @deprecated use Node.getParentNode
     44      */
     45     @Deprecated
     46     public static Node getParentNode(Node node) {
     47         return node.getParentNode().orElse(null);
     48     }
     49 
     50     public static Node requireParentNode(Node node) {
     51         return node.getParentNode().orElseThrow(() -> new IllegalStateException("Parent not found, the node does not appear to be inserted in a correct AST"));
     52     }
     53 
     54     public static Optional<TypeDeclaration<?>> findType(CompilationUnit cu, String qualifiedName) {
     55         if (cu.getTypes().isEmpty()) {
     56             return Optional.empty();
     57         }
     58 
     59         final String typeName = getOuterTypeName(qualifiedName);
     60         Optional<TypeDeclaration<?>> type = cu.getTypes().stream().filter((t) -> t.getName().getId().equals(typeName)).findFirst();
     61 
     62         final String innerTypeName = getInnerTypeName(qualifiedName);
     63         if (type.isPresent() && !innerTypeName.isEmpty()) {
     64             return findType(type.get(), innerTypeName);
     65         }
     66         return type;
     67     }
     68 
     69     public static Optional<TypeDeclaration<?>> findType(TypeDeclaration<?> td, String qualifiedName) {
     70         final String typeName = getOuterTypeName(qualifiedName);
     71 
     72         Optional<TypeDeclaration<?>> type = Optional.empty();
     73         for (Node n : td.getMembers()) {
     74             if (n instanceof TypeDeclaration && ((TypeDeclaration<?>) n).getName().getId().equals(typeName)) {
     75                 type = Optional.of((TypeDeclaration<?>) n);
     76                 break;
     77             }
     78         }
     79         final String innerTypeName = getInnerTypeName(qualifiedName);
     80         if (type.isPresent() && !innerTypeName.isEmpty()) {
     81             return findType(type.get(), innerTypeName);
     82         }
     83         return type;
     84     }
     85 
     86     public static ClassOrInterfaceDeclaration demandClass(CompilationUnit cu, String qualifiedName) {
     87         ClassOrInterfaceDeclaration cd = demandClassOrInterface(cu, qualifiedName);
     88         if (cd.isInterface()) {
     89             throw new IllegalStateException("Type is not a class");
     90         }
     91         return cd;
     92     }
     93 
     94     public static EnumDeclaration demandEnum(CompilationUnit cu, String qualifiedName) {
     95         Optional<TypeDeclaration<?>> res = findType(cu, qualifiedName);
     96         if (!res.isPresent()) {
     97             throw new IllegalStateException("No type found");
     98         }
     99         if (!(res.get() instanceof EnumDeclaration)) {
    100             throw new IllegalStateException("Type is not an enum");
    101         }
    102         return (EnumDeclaration) res.get();
    103     }
    104 
    105     public static MethodDeclaration demandMethod(TypeDeclaration<?> cd, String name) {
    106         MethodDeclaration found = null;
    107         for (BodyDeclaration<?> bd : cd.getMembers()) {
    108             if (bd instanceof MethodDeclaration) {
    109                 MethodDeclaration md = (MethodDeclaration) bd;
    110                 if (md.getNameAsString().equals(name)) {
    111                     if (found != null) {
    112                         throw new IllegalStateException("Ambiguous getName");
    113                     }
    114                     found = md;
    115                 }
    116             }
    117         }
    118         if (found == null) {
    119             throw new IllegalStateException("No method called " + name);
    120         }
    121         return found;
    122     }
    123 
    124     public static VariableDeclarator demandField(ClassOrInterfaceDeclaration cd, String name) {
    125         for (BodyDeclaration<?> bd : cd.getMembers()) {
    126             if (bd instanceof FieldDeclaration) {
    127                 FieldDeclaration fd = (FieldDeclaration) bd;
    128                 for (VariableDeclarator vd : fd.getVariables()) {
    129                     if (vd.getName().getId().equals(name)) {
    130                         return vd;
    131                     }
    132                 }
    133             }
    134         }
    135         throw new IllegalStateException("No field with given name");
    136     }
    137 
    138     public static Optional<NameExpr> findNameExpression(Node node, String name) {
    139         return node.findFirst(NameExpr.class, n -> n.getNameAsString().equals(name));
    140     }
    141 
    142     public static Optional<SimpleName> findSimpleName(Node node, String name) {
    143         return node.findFirst(SimpleName.class, n -> n.asString().equals(name));
    144     }
    145 
    146 
    147     public static Optional<MethodCallExpr> findMethodCall(Node node, String methodName) {
    148         return node.findFirst(MethodCallExpr.class, n -> n.getNameAsString().equals(methodName));
    149     }
    150 
    151     public static Optional<VariableDeclarator> demandVariableDeclaration(Node node, String name) {
    152         return node.findFirst(VariableDeclarator.class, n -> n.getNameAsString().equals(name));
    153     }
    154 
    155     public static ClassOrInterfaceDeclaration demandClassOrInterface(CompilationUnit compilationUnit, String qualifiedName) {
    156         return findType(compilationUnit, qualifiedName)
    157                 .map(res -> res.toClassOrInterfaceDeclaration().orElseThrow(() -> new IllegalStateException("Type is not a class or an interface, it is " + res.getClass().getCanonicalName())))
    158                 .orElseThrow(() -> new IllegalStateException("No type named '" + qualifiedName + "'found"));
    159     }
    160 
    161     // TODO should be demand or requireSwitch
    162     public static SwitchStmt findSwitch(Node node) {
    163         return findSwitchHelper(node).orElseThrow(IllegalArgumentException::new);
    164     }
    165 
    166     public static <N extends Node> N findNodeOfGivenClass(Node node, Class<N> clazz) {
    167         return node.findFirst(clazz).orElseThrow(IllegalArgumentException::new);
    168     }
    169 
    170     /**
    171      * @deprecated use Node.findAll instead
    172      */
    173     @Deprecated
    174     public static <N extends Node> List<N> findAllNodesOfGivenClass(Node node, Class<N> clazz) {
    175         return node.findAll(clazz);
    176     }
    177 
    178     // TODO should be demand or require...
    179     public static ReturnStmt findReturnStmt(MethodDeclaration method) {
    180         return findNodeOfGivenClass(method, ReturnStmt.class);
    181     }
    182 
    183     /**
    184      * @deprecated use Node.findParent instead
    185      */
    186     @Deprecated
    187     public static <N extends Node> Optional<N> findAncestor(Node node, Class<N> clazz) {
    188         return node.findParent(clazz);
    189     }
    190 
    191     ///
    192     /// Private methods
    193     ///
    194 
    195     private static String getOuterTypeName(String qualifiedName) {
    196         return qualifiedName.split("\\.", 2)[0];
    197     }
    198 
    199     private static String getInnerTypeName(String qualifiedName) {
    200         if (qualifiedName.contains(".")) {
    201             return qualifiedName.split("\\.", 2)[1];
    202         }
    203         return "";
    204     }
    205 
    206     private static Optional<SwitchStmt> findSwitchHelper(Node node) {
    207         // TODO can be replaced by findFirst with the correct algorithm.
    208         if (node instanceof SwitchStmt) {
    209             return Optional.of((SwitchStmt) node);
    210         }
    211         for (Node child : node.getChildNodes()) {
    212             Optional<SwitchStmt> resChild = findSwitchHelper(child);
    213             if (resChild.isPresent()) {
    214                 return resChild;
    215             }
    216         }
    217         return Optional.empty();
    218     }
    219 }
    220