blob: dc3ea62e816cc5466f2c535fc6d54f03ece4e3d3 [file] [log] [blame]
/*
* 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.javaparser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.SimpleName;
import com.github.javaparser.ast.stmt.ReturnStmt;
import com.github.javaparser.ast.stmt.SwitchStmt;
import java.util.List;
import java.util.Optional;
/**
* This class can be used to easily retrieve nodes from a JavaParser AST.
*
* @author Federico Tomassetti
*/
public final class Navigator {
private Navigator() {
// prevent instantiation
}
/**
* @deprecated use Node.getParentNode
*/
@Deprecated
public static Node getParentNode(Node node) {
return node.getParentNode().orElse(null);
}
public static Node requireParentNode(Node node) {
return node.getParentNode().orElseThrow(() -> new IllegalStateException("Parent not found, the node does not appear to be inserted in a correct AST"));
}
public static Optional<TypeDeclaration<?>> findType(CompilationUnit cu, String qualifiedName) {
if (cu.getTypes().isEmpty()) {
return Optional.empty();
}
final String typeName = getOuterTypeName(qualifiedName);
Optional<TypeDeclaration<?>> type = cu.getTypes().stream().filter((t) -> t.getName().getId().equals(typeName)).findFirst();
final String innerTypeName = getInnerTypeName(qualifiedName);
if (type.isPresent() && !innerTypeName.isEmpty()) {
return findType(type.get(), innerTypeName);
}
return type;
}
public static Optional<TypeDeclaration<?>> findType(TypeDeclaration<?> td, String qualifiedName) {
final String typeName = getOuterTypeName(qualifiedName);
Optional<TypeDeclaration<?>> type = Optional.empty();
for (Node n : td.getMembers()) {
if (n instanceof TypeDeclaration && ((TypeDeclaration<?>) n).getName().getId().equals(typeName)) {
type = Optional.of((TypeDeclaration<?>) n);
break;
}
}
final String innerTypeName = getInnerTypeName(qualifiedName);
if (type.isPresent() && !innerTypeName.isEmpty()) {
return findType(type.get(), innerTypeName);
}
return type;
}
public static ClassOrInterfaceDeclaration demandClass(CompilationUnit cu, String qualifiedName) {
ClassOrInterfaceDeclaration cd = demandClassOrInterface(cu, qualifiedName);
if (cd.isInterface()) {
throw new IllegalStateException("Type is not a class");
}
return cd;
}
public static EnumDeclaration demandEnum(CompilationUnit cu, String qualifiedName) {
Optional<TypeDeclaration<?>> res = findType(cu, qualifiedName);
if (!res.isPresent()) {
throw new IllegalStateException("No type found");
}
if (!(res.get() instanceof EnumDeclaration)) {
throw new IllegalStateException("Type is not an enum");
}
return (EnumDeclaration) res.get();
}
public static MethodDeclaration demandMethod(TypeDeclaration<?> cd, String name) {
MethodDeclaration found = null;
for (BodyDeclaration<?> bd : cd.getMembers()) {
if (bd instanceof MethodDeclaration) {
MethodDeclaration md = (MethodDeclaration) bd;
if (md.getNameAsString().equals(name)) {
if (found != null) {
throw new IllegalStateException("Ambiguous getName");
}
found = md;
}
}
}
if (found == null) {
throw new IllegalStateException("No method called " + name);
}
return found;
}
public static VariableDeclarator demandField(ClassOrInterfaceDeclaration cd, String name) {
for (BodyDeclaration<?> bd : cd.getMembers()) {
if (bd instanceof FieldDeclaration) {
FieldDeclaration fd = (FieldDeclaration) bd;
for (VariableDeclarator vd : fd.getVariables()) {
if (vd.getName().getId().equals(name)) {
return vd;
}
}
}
}
throw new IllegalStateException("No field with given name");
}
public static Optional<NameExpr> findNameExpression(Node node, String name) {
return node.findFirst(NameExpr.class, n -> n.getNameAsString().equals(name));
}
public static Optional<SimpleName> findSimpleName(Node node, String name) {
return node.findFirst(SimpleName.class, n -> n.asString().equals(name));
}
public static Optional<MethodCallExpr> findMethodCall(Node node, String methodName) {
return node.findFirst(MethodCallExpr.class, n -> n.getNameAsString().equals(methodName));
}
public static Optional<VariableDeclarator> demandVariableDeclaration(Node node, String name) {
return node.findFirst(VariableDeclarator.class, n -> n.getNameAsString().equals(name));
}
public static ClassOrInterfaceDeclaration demandClassOrInterface(CompilationUnit compilationUnit, String qualifiedName) {
return findType(compilationUnit, qualifiedName)
.map(res -> res.toClassOrInterfaceDeclaration().orElseThrow(() -> new IllegalStateException("Type is not a class or an interface, it is " + res.getClass().getCanonicalName())))
.orElseThrow(() -> new IllegalStateException("No type named '" + qualifiedName + "'found"));
}
// TODO should be demand or requireSwitch
public static SwitchStmt findSwitch(Node node) {
return findSwitchHelper(node).orElseThrow(IllegalArgumentException::new);
}
public static <N extends Node> N findNodeOfGivenClass(Node node, Class<N> clazz) {
return node.findFirst(clazz).orElseThrow(IllegalArgumentException::new);
}
/**
* @deprecated use Node.findAll instead
*/
@Deprecated
public static <N extends Node> List<N> findAllNodesOfGivenClass(Node node, Class<N> clazz) {
return node.findAll(clazz);
}
// TODO should be demand or require...
public static ReturnStmt findReturnStmt(MethodDeclaration method) {
return findNodeOfGivenClass(method, ReturnStmt.class);
}
/**
* @deprecated use Node.findParent instead
*/
@Deprecated
public static <N extends Node> Optional<N> findAncestor(Node node, Class<N> clazz) {
return node.findParent(clazz);
}
///
/// Private methods
///
private static String getOuterTypeName(String qualifiedName) {
return qualifiedName.split("\\.", 2)[0];
}
private static String getInnerTypeName(String qualifiedName) {
if (qualifiedName.contains(".")) {
return qualifiedName.split("\\.", 2)[1];
}
return "";
}
private static Optional<SwitchStmt> findSwitchHelper(Node node) {
// TODO can be replaced by findFirst with the correct algorithm.
if (node instanceof SwitchStmt) {
return Optional.of((SwitchStmt) node);
}
for (Node child : node.getChildNodes()) {
Optional<SwitchStmt> resChild = findSwitchHelper(child);
if (resChild.isPresent()) {
return resChild;
}
}
return Optional.empty();
}
}