package com.github.javaparser.ast.visitor;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.TypeParameter;
import com.github.javaparser.ast.body.AnnotationDeclaration;
import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
import com.github.javaparser.ast.body.BaseParameter;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.EmptyMemberDeclaration;
import com.github.javaparser.ast.body.EmptyTypeDeclaration;
import com.github.javaparser.ast.body.EnumConstantDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.InitializerDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.MultiTypeParameter;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.body.VariableDeclaratorId;
import com.github.javaparser.ast.comments.BlockComment;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.AssertStmt;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.BreakStmt;
import com.github.javaparser.ast.stmt.CatchClause;
import com.github.javaparser.ast.stmt.ContinueStmt;
import com.github.javaparser.ast.stmt.DoStmt;
import com.github.javaparser.ast.stmt.EmptyStmt;
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.stmt.ForStmt;
import com.github.javaparser.ast.stmt.ForeachStmt;
import com.github.javaparser.ast.stmt.IfStmt;
import com.github.javaparser.ast.stmt.LabeledStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
import com.github.javaparser.ast.stmt.SwitchEntryStmt;
import com.github.javaparser.ast.stmt.SwitchStmt;
import com.github.javaparser.ast.stmt.SynchronizedStmt;
import com.github.javaparser.ast.stmt.ThrowStmt;
import com.github.javaparser.ast.stmt.TryStmt;
import com.github.javaparser.ast.stmt.TypeDeclarationStmt;
import com.github.javaparser.ast.stmt.WhileStmt;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.IntersectionType;
import com.github.javaparser.ast.type.PrimitiveType;
import com.github.javaparser.ast.type.ReferenceType;
import com.github.javaparser.ast.type.UnionType;
import com.github.javaparser.ast.type.UnknownType;
import com.github.javaparser.ast.type.VoidType;
import com.github.javaparser.ast.type.WildcardType;
import xapi.fu.Out1;
import static xapi.util.X_String.join;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* For cases when you want to collect a set of modifications,
* then apply them all in a single traversal of the node graph,
* this class allows you to supply an IdentityHashMap of nodes
* in the graph with new nodes you want to insert.
*
* This visitor overrides all the methods to check this map for
* supplied replacements. This is simpler in many cases than
* creating highly specific adapters, especially when you want
* to expose a generic API for arbitrary replacements that may
* not actually be aware of what nodes are to be replaced.
*
* Created by James X. Nelson (james@wetheinter.net) on 6/22/16.
*/
public class ConcreteModifierVisitor extends ModifierVisitorAdapter <Map<Node, Node>> {
public static void replaceResolved(Map<Node, Out1<Node>> replacements) {
Map<Node, Node> copy = new IdentityHashMap<>();
replacements.forEach((k, v)->copy.put(k, v.out1()));
replaceAll(copy);
}
public static void replaceAll(Map<Node, Node> replacements) {
// find the lowest common ancestor of all nodes;
// for very large graphs, this will be faster than traversing a potentially very large
// number on uninteresting nodes (and given that we do map lookups on every node,
// we prefer reducing the search size as graphs with low height won't take much of a hit,
// and graphs of large height or breadth can save a substantial amount of time)
final Node ancestor = findAncestor(replacements.keySet());
// traverse only from the common ancestor down.
if (ancestor != null) {
ancestor.accept(new ConcreteModifierVisitor(), replacements);
}
}
private ConcreteModifierVisitor() {
}
private static Node findAncestor(Set<Node> nodes) {
if (nodes.isEmpty()) {
return null;
}
final Iterator<Node> itr = nodes.iterator();
final Node first = itr.next();
if (nodes.size() == 1) {
return first.getParentNode();
}
// with more than one item, we need to paint a map of candidates.
// matches will store a chain of parents of the first node;
// an identity hashmap is used for fast querying of whether the item was seen or not
IdentityHashMap<Node, Boolean> matches = new IdentityHashMap<>();
// the chain of parents is stored in this linked list,
// which we use for fast addition/removal at either end of the list.
LinkedList<Node> possible = new LinkedList<>();
// traverse up from the first node, marking all parents as candidates
Node node, candidate = node = first;
while (node.getParentNode() != null) {
candidate = node;
node = node.getParentNode();
matches.put(node, false);
possible.addFirst(node);
}
// Now, all ancestors of the first node are candidates,
// and the candidate pointer is pointing at the root of the graph
// lets check all remaining nodes for their intersection points.
loop:
while (itr.hasNext()) {
node = itr.next();
while (node.getParentNode() != null) {
Boolean seen = matches.get(node = node.getParentNode());
if (seen != null) {
// if we've seen this parent before, lets determine if this is a new best ancestor
if (seen) {
// if the state is anything other than false, we have already resolved this node.
continue loop;
}
// if we encountered an unseen ancestor, then it must be the next best
matches.put(candidate = node, true);
// now remove all dangling descendants who are no longer ancestor candidates
while (possible.getLast() != node) {
// mark children of the best candidate so we don't consider them again
matches.put(possible.removeLast(), true);
}
continue loop;
}
}
assert false : "Malformed graph structure; at least two nodes do not share a common ancestor in:\n" + join("\n", nodes);
}
// The last item in the possible list is the common ancestor
assert possible.isEmpty() || candidate == possible.removeLast() : "Malformed graph structure; best candidate did not match tail of possible list";
return candidate;
}
@Override
protected Node visit(
BaseParameter n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
AnnotationDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
AnnotationMemberDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ArrayAccessExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ArrayCreationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ArrayInitializerExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
AssertStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
AssignExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
BinaryExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
BlockStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
BooleanLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
BreakStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
CastExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
CatchClause n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
CharLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ClassExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ClassOrInterfaceDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ClassOrInterfaceType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
CompilationUnit n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ConditionalExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ConstructorDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ContinueStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
DoStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
DoubleLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EmptyMemberDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EmptyStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EmptyTypeDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EnclosedExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EnumConstantDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
EnumDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ExplicitConstructorInvocationStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ExpressionStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
FieldAccessExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
FieldDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ForeachStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ForStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
IfStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ImportDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
InitializerDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
InstanceOfExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
IntegerLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
IntegerLiteralMinValueExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
JavadocComment n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
LabeledStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
LongLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
LongLiteralMinValueExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MarkerAnnotationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MemberValuePair n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MethodCallExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MethodDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
NameExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
NormalAnnotationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
NullLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ObjectCreationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
PackageDeclaration n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
Parameter n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MultiTypeParameter n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
PrimitiveType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
QualifiedNameExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ReferenceType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ReturnStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
SingleMemberAnnotationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
StringLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
TemplateLiteralExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
SuperExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
SwitchEntryStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
SwitchStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
SynchronizedStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ThisExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
ThrowStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
TryStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
TypeDeclarationStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
TypeParameter n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UnaryExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UnknownType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
VariableDeclarationExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
VariableDeclarator n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
VariableDeclaratorId n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
VoidType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
WhileStmt n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
WildcardType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
LambdaExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
MethodReferenceExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
TypeExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
BlockComment n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
LineComment n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
IntersectionType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UnionType n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UiBodyExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UiAttrExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
@Override
public Node visit(
UiContainerExpr n, Map<Node, Node> arg
) {
if (arg.containsKey(n)) {
return arg.get(n);
}
return super.visit(n, arg);
}
}