All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.codemodder.ast.NameResolver Maven / Gradle / Ivy
package io.codemodder.ast;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import java.util.Optional;
import org.javatuples.Pair;
import org.javatuples.Triplet;
/** Find sources of names in JavaParser ASTs. */
final class NameResolver {
private NameResolver() {}
private static Optional isLocalNameSource(final Node n, final String name) {
final Optional maybe =
ASTs.isExpressionStmtDeclarationOf(n, name).map(Triplet::getValue2);
// Possible returns:
return maybe
.or(() -> ASTs.isResourceOf(n, name).map(Triplet::getValue2))
.or(() -> ASTs.isForVariableDeclarationOf(n, name).map(Triplet::getValue2))
.or(() -> ASTs.isForEachVariableDeclarationOf(n, name).map(Triplet::getValue2))
.or(() -> ASTs.isLambdaExprParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isExceptionParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isMethodFormalParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isMethodTypeParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isConstructorFormalParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isConstructorTypeParameterOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isLocalTypeDeclarationOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isLocalRecordDeclarationOf(n, name).map(Pair::getValue1))
.or(() -> ASTs.isPatternExprDeclarationOf(n, name).map(t -> t));
}
private static Optional findLocalNameSource(Node current, final String name) {
// Traverse the tree in reverse pre-order until it hits a declaration
final var it = ASTs.reversePreOrderIterator(current);
while (!(current instanceof TypeDeclaration) && it.hasNext()) {
current = it.next();
final var maybeFound = isLocalNameSource(current, name);
if (maybeFound.isPresent()) return maybeFound;
}
return Optional.empty();
}
private static Optional isFieldOfClass(
final ClassOrInterfaceDeclaration classDeclaration, final String name) {
return classDeclaration.getFields().stream()
.flatMap(field -> ASTs.isFieldDeclarationOf(field, name).stream())
.findAny()
.map(Pair::getValue1);
}
private static Optional isNamedMemberOfClass(
final ClassOrInterfaceDeclaration classDeclaration, final String name) {
return classDeclaration.getMembers().stream()
.flatMap(bodyDecl -> ASTs.isNamedMemberOf(bodyDecl, name).stream())
.findAny()
.map(n -> (Node) n);
}
private static Optional isNameOfClass(
final ClassOrInterfaceDeclaration classDeclaration, final String name) {
if (classDeclaration.getNameAsString().equals(name)) {
return Optional.of(classDeclaration);
}
return Optional.empty();
}
private static Optional findClassLevelNameSource(
final ClassOrInterfaceDeclaration classDeclaration, final String name) {
return isFieldOfClass(classDeclaration, name)
.or(() -> isNamedMemberOfClass(classDeclaration, name))
.or(() -> ASTs.isClassTypeParameterOf(classDeclaration, name).map(Pair::getValue1))
.or(() -> isNameOfClass(classDeclaration, name));
}
static Optional resolveSimpleName(final Node start, final String name) {
// Callable names need more context like signatures to be found. Also, can be overloaded
Node current = start;
// Alternate its search from local (i.e. method level) to class level. It may happen because of
// local type declarations.
while (current.hasParentNode()) {
current = current.getParentNode().get();
// try locally first
final Optional maybeDeclaration = findLocalNameSource(current, name);
if (maybeDeclaration.isPresent()) {
return maybeDeclaration;
}
// No local declaration. Either hit root or a TypeDeclaration after its search
// TypeDeclaration: ClassOrInterfaceDeclaration, EnumDeclaration, RecordDeclaration
if (current instanceof ClassOrInterfaceDeclaration) {
final var classDeclaration = (ClassOrInterfaceDeclaration) current;
final Optional maybeClassMember = findClassLevelNameSource(classDeclaration, name);
if (maybeClassMember.isPresent()) {
return maybeClassMember;
}
}
}
// reached CompilationUnit check for top level classes
final var topLevelTypes = current.findCompilationUnit().get().getTypes();
final var maybeDecl =
topLevelTypes.stream().filter(t -> t.getNameAsString().equals(name)).findFirst();
if (maybeDecl.isPresent()) return maybeDecl.map(n -> n);
// it's either wildcard imported, inherited, or in the package namespace
return Optional.empty();
}
/** Finds the {@link ClassOrInterfaceDeclaration} that is referenced by a {@link ThisExpr}. */
static ClassOrInterfaceDeclaration findThisDeclaration(final ThisExpr thisExpr) {
Node current = thisExpr;
while (current.hasParentNode() && !(current instanceof ClassOrInterfaceDeclaration)) {
current = current.getParentNode().get();
}
return (ClassOrInterfaceDeclaration) current;
}
static Optional findLocalDeclarationOf(final Node start, final String name) {
final var maybeSource = resolveSimpleName(start, name);
if (maybeSource.isPresent()) {
final var source = maybeSource.get();
if (source instanceof Parameter) {
return Optional.of(new ParameterDeclaration((Parameter) source));
}
if (source instanceof VariableDeclarator) {
final var vd = (VariableDeclarator) source;
return ASTs.isVariableOfLocalDeclarationStmt(vd)
.map(
t ->
(LocalDeclaration)
new ExpressionStmtVariableDeclaration(
t.getValue0(), t.getValue1(), t.getValue2()))
.or(
() ->
ASTs.isResource(vd)
.map(p -> new TryResourceDeclaration(p.getValue0(), p.getValue1(), vd)))
.or(
() ->
ASTs.isForInitVariable(vd)
.map(p -> new ForInitDeclaration(p.getValue0(), p.getValue1(), vd)))
.or(
() ->
ASTs.isForEachVariable(vd)
.map(p -> new ForEachDeclaration(p.getValue0(), p.getValue1(), vd)));
}
}
return Optional.empty();
}
static Optional findLocalVariableDeclarationOf(
final Node start, final String name) {
final var maybeSource =
resolveSimpleName(start, name)
.map(n -> n instanceof VariableDeclarator ? (VariableDeclarator) n : null);
if (maybeSource.isPresent()) {
final var vd = maybeSource.get();
return ASTs.isVariableOfLocalDeclarationStmt(vd)
.map(
t ->
(LocalVariableDeclaration)
new ExpressionStmtVariableDeclaration(
t.getValue0(), t.getValue1(), t.getValue2()))
.or(
() ->
ASTs.isResource(vd)
.map(p -> new TryResourceDeclaration(p.getValue0(), p.getValue1(), vd)))
.or(
() ->
ASTs.isForInitVariable(vd)
.map(p -> new ForInitDeclaration(p.getValue0(), p.getValue1(), vd)))
.or(
() ->
ASTs.isForEachVariable(vd)
.map(p -> new ForEachDeclaration(p.getValue0(), p.getValue1(), vd)));
}
return Optional.empty();
}
}