All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.codemodder.javaparser.ASTExpectations Maven / Gradle / Ivy

package io.codemodder.javaparser;

import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.FieldAccessExpr;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import io.codemodder.ast.ASTs;
import io.codemodder.ast.LocalVariableDeclaration;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * A utility for validating the shape of ASTs and filtering them to retrieve. It only exposes one
 * endpoint, {@link #expect(Node)}, which allows folks to filter and telescope a further down an AST
 * subgraph.
 *
 * 

The notable weakness of this API is use cases where you need to retrieve multiple parts of the * AST, but we have not run into that much as of yet. */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public final class ASTExpectations { private ASTExpectations() {} /** A producer of an AST subgraph. */ interface ASTExpectationProducer { Optional result(); } /** The starting point for validating the shape of an AST and returning a subgraph. */ public static NodeExpectation expect(final Node node) { return new NodeExpectation(node); } /** A type for querying and filtering generic AST nodes. */ public static class NodeExpectation implements ASTExpectationProducer { private Optional nodeRef; public NodeExpectation(final Node node) { this.nodeRef = Optional.of(node); } /** Return an expectation that asserts the parent node is a {@link BlockStmt}. */ public NodeExpectation withBlockParent() { if (nodeRef.isEmpty()) { return this; } nodeRef = nodeRef.filter( n -> n.getParentNode().filter(parent -> parent instanceof BlockStmt).isPresent()); return this; } /** * Return an expectation that asserts the node is an {@link ExpressionStmt} with a {@link * VariableDeclarationExpr} for its expression. */ public VariableDeclarationExprExpectation toBeVariableDeclarationStatement() { Optional vde = nodeRef .map(n -> n instanceof ExpressionStmt ? (ExpressionStmt) n : null) .map(ExpressionStmt::getExpression) .map( expr -> expr.isVariableDeclarationExpr() ? expr.asVariableDeclarationExpr() : null); return new VariableDeclarationExprExpectation(vde); } /** Return an expectation that asserts the node is a {@link MethodCallExpr}. */ public MethodCallExpectation toBeMethodCallExpression() { if (nodeRef.isEmpty() || !(nodeRef.get() instanceof MethodCallExpr)) { return new MethodCallExpectation(Optional.empty()); } return new MethodCallExpectation(Optional.of((MethodCallExpr) nodeRef.get())); } /** Return an expectation that asserts the node is a {@link ExpressionStmt}. */ public ExpressionStatementExpectation toBeExpressionStatement() { if (nodeRef.isEmpty() || !(nodeRef.get() instanceof ExpressionStmt)) { return new ExpressionStatementExpectation(Optional.empty()); } return new ExpressionStatementExpectation(Optional.of((ExpressionStmt) nodeRef.get())); } /** Return an expectation that asserts the node is a {@link NameExpr}. */ public NameExpressionExpectation toBeNameExpression() { if (nodeRef.isEmpty() || !(nodeRef.get() instanceof NameExpr)) { return new NameExpressionExpectation(Optional.empty()); } return new NameExpressionExpectation(Optional.of((NameExpr) nodeRef.get())); } /** Return an expectation that asserts the node is a {@link FieldAccessExpr}. */ public FieldAccessExpectation toBeFieldAccessExpression() { if (nodeRef.isEmpty() || !(nodeRef.get() instanceof FieldAccessExpr)) { return new FieldAccessExpectation(Optional.empty()); } return new FieldAccessExpectation(Optional.of((FieldAccessExpr) nodeRef.get())); } public StringLiteralExpectation toBeStringLiteral() { if (nodeRef.isEmpty() || !(nodeRef.get() instanceof StringLiteralExpr)) { return new StringLiteralExpectation(Optional.empty()); } return new StringLiteralExpectation(Optional.of((StringLiteralExpr) nodeRef.get())); } @Override public Optional result() { return nodeRef; } } /** A type for querying and filtering name expressions. */ public static class FieldAccessExpectation implements ASTExpectationProducer { private final Optional name; private FieldAccessExpectation(final Optional name) { this.name = Objects.requireNonNull(name); } @Override public Optional result() { return name; } } /** A type for querying and filtering name expressions. */ public static class NameExpressionExpectation implements ASTExpectationProducer { private final Optional name; private NameExpressionExpectation(final Optional name) { this.name = Objects.requireNonNull(name); } @Override public Optional result() { return name; } } /** A type for querying and filtering string literals. */ public static class StringLiteralExpectation implements ASTExpectationProducer { private final Optional stringLiteralExpr; public StringLiteralExpectation(final Optional stringLiteralExpr) { this.stringLiteralExpr = stringLiteralExpr; } @Override public Optional result() { return stringLiteralExpr; } } /** A type for querying and filtering expression statements. */ public static class ExpressionStatementExpectation implements ASTExpectationProducer { private final Optional expressionStmtRef; private ExpressionStatementExpectation(final Optional expr) { this.expressionStmtRef = expr; } @Override public Optional result() { return expressionStmtRef; } public LocalVariableDeclaratorExpectation withSingleVariableDeclarationExpression() { if (expressionStmtRef.isEmpty()) { return new LocalVariableDeclaratorExpectation(Optional.empty()); } ExpressionStmt expressionStmt = expressionStmtRef.get(); if (expressionStmt.getExpression() instanceof VariableDeclarationExpr) { VariableDeclarationExpr declarationExpr = expressionStmt.getExpression().asVariableDeclarationExpr(); if (declarationExpr.getVariables().size() == 1) { return new LocalVariableDeclaratorExpectation( Optional.of(declarationExpr.getVariable(0))); } } return new LocalVariableDeclaratorExpectation(Optional.empty()); } public MethodCallExpectation withMethodCallExpression() { if (expressionStmtRef.isPresent()) { ExpressionStmt expressionStmt = expressionStmtRef.get(); if (expressionStmt.getExpression() instanceof MethodCallExpr) { return new MethodCallExpectation( Optional.of(expressionStmt.getExpression().asMethodCallExpr())); } } return new MethodCallExpectation(Optional.empty()); } } /** A type for querying and filtering variable declaration(s). */ public static class VariableDeclarationExprExpectation implements ASTExpectationProducer { private Optional varDefExprRef; private VariableDeclarationExprExpectation(final Optional expr) { this.varDefExprRef = expr; } /** * Return an expectation that asserts the local variable declaration has only a single variable. */ public LocalVariableDeclaratorExpectation toBeSingleLocalVariableDefinition() { if (varDefExprRef.isEmpty()) { return new LocalVariableDeclaratorExpectation(Optional.empty()); } VariableDeclarationExpr variableDeclarationExpr = varDefExprRef.get(); if (variableDeclarationExpr.getVariables().size() != 1) { varDefExprRef = Optional.empty(); return new LocalVariableDeclaratorExpectation(Optional.empty()); } Optional localVariableDeclaration = LocalVariableDeclaration.fromVariableDeclarator(variableDeclarationExpr.getVariable(0)); if (localVariableDeclaration.isPresent()) { return new LocalVariableDeclaratorExpectation( Optional.of(variableDeclarationExpr.getVariables().get(0))); } return new LocalVariableDeclaratorExpectation(Optional.empty()); } @Override public Optional result() { return varDefExprRef; } } /** A type for querying and filtering a single variable declaration. */ public static class LocalVariableDeclaratorExpectation implements ASTExpectationProducer { private Optional varRef; public LocalVariableDeclaratorExpectation( final Optional variableDeclarator) { this.varRef = Objects.requireNonNull(variableDeclarator); } /** Return an expectation that asserts the variable declaration has only a single variable. */ public LocalVariableDeclaratorExpectation withDirectReferenceCount(final int count) { if (varRef.isEmpty()) { return this; } Optional localVariableDeclaration = LocalVariableDeclaration.fromVariableDeclarator(varRef.get()); if (localVariableDeclaration.isEmpty()) { varRef = Optional.empty(); return this; } List allReferences = ASTs.findAllReferences(localVariableDeclaration.get()); if (allReferences.size() != count) { varRef = Optional.empty(); } return this; } /** Return an expectation that asserts that the initializer is a {@link MethodCallExpr}. */ public MethodCallExpectation toBeInitializedByMethodCall() { if (varRef.isEmpty()) { return new MethodCallExpectation(Optional.empty()); } Optional mc = varRef .flatMap(VariableDeclarator::getInitializer) .filter(MethodCallExpr.class::isInstance) .map(MethodCallExpr.class::cast); if (mc.isEmpty()) { varRef = Optional.empty(); } return new MethodCallExpectation(mc); } @Override public Optional result() { return varRef; } } /** A type for querying and filtering method call expressions. */ public static class MethodCallExpectation implements ASTExpectationProducer { private Optional methodCallExpr; public MethodCallExpectation(final Optional methodCallExpr) { this.methodCallExpr = Objects.requireNonNull(methodCallExpr); } @Override public Optional result() { return methodCallExpr; } /** Return an expectation that asserts the method call has a specific number of arguments. */ public MethodCallExpectation withArgumentsSize(final int expectedSize) { if (methodCallExpr.isEmpty()) { return this; } MethodCallExpr callExpr = methodCallExpr.get(); if (callExpr.getArguments().size() != expectedSize) { methodCallExpr = Optional.empty(); } return this; } /** Return an expectation that asserts the method call has a specific name. */ public MethodCallExpectation withName(final String expectedName) { if (methodCallExpr.isEmpty()) { return this; } MethodCallExpr callExpr = methodCallExpr.get(); if (!expectedName.equals(callExpr.getNameAsString())) { methodCallExpr = Optional.empty(); } return this; } /** Return an expectation that asserts the method call has 1+ arguments. */ public MethodCallExpectation withArguments() { if (methodCallExpr.isEmpty()) { return this; } MethodCallExpr callExpr = methodCallExpr.get(); if (callExpr.getArguments().isEmpty()) { methodCallExpr = Optional.empty(); } return this; } /** Return an expectation that asserts the method call is initializing a variable value. */ public LocalVariableDeclaratorExpectation initializingVariable() { if (methodCallExpr.isEmpty()) { return new LocalVariableDeclaratorExpectation(Optional.empty()); } MethodCallExpr call = methodCallExpr.get(); if (call.getParentNode().isEmpty()) { return new LocalVariableDeclaratorExpectation(Optional.empty()); } Optional initExpr = ASTs.isInitExpr(call); if (initExpr.isEmpty()) { return new LocalVariableDeclaratorExpectation(Optional.empty()); } return new LocalVariableDeclaratorExpectation(initExpr); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy