Skip to content

HelperVisitor more simple samples

Carsten Hammer edited this page Nov 4, 2021 · 2 revisions

Simple MethodInvocation

Old way to use visitor

	private boolean handleMethodInvocation(MethodInvocation assignment) {
		System.out.println(assignment);
		return true;
	}

	...
	ASTVisitor astvisitor=new ASTVisitor() {
		@Override
		public boolean visit(MethodInvocation node) {
			return VisitorTest.this.handleMethodInvocation(node);
		}
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
	private boolean handleMethodInvocation(MethodInvocation assignment, ReferenceHolder<String,NodeFound> holder) {
		System.out.println(assignment);
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	hv.addMethodInvocation(this::handleMethodInvocation);
	hv.build(cunit1);

MethodInvocation on method with the given name "add"

Old way to use visitor

	private boolean handleMethodInvocation(MethodInvocation assignment) {
		System.out.println(assignment);
		return true;
	}

	...
	String name ="add";
	ASTVisitor astvisitor=new ASTVisitor() {
		@Override
		public boolean visit(MethodInvocation node) {
			if(!node.getName().getIdentifier().equals(name))
				return true;
			return VisitorTest.this.handleMethodInvocation(node);
		}
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. When adding the method reference we can give parameter for method name "add"
	private boolean handleMethodInvocation(MethodInvocation assignment, ReferenceHolder<String,NodeFound> holder) {
		System.out.println(assignment);
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	hv.addMethodInvocation("add", this::handleMethodInvocation);
	hv.build(cunit1);

MethodInvocation on method with the given name "add" - run two handlers explicitly

Old way to use visitor

This code is not really the same as what is shown in the sample for the new way. It is here just to illustrate that code gets more complex without the new API. To be the same it needs even more code.

	private boolean handleMethodInvocation(MethodInvocation assignment) {
		System.out.println(assignment);
		return true;
	}

	...
	String name ="add";
	ASTVisitor astvisitor=new ASTVisitor() {
		@Override
		public boolean visit(MethodInvocation node) {
			if(!node.getName().getIdentifier().equals(name))
				return true;
			return VisitorTest.this.handleMethodInvocation(node,null);
		}
	};
	ASTVisitor astvisitor2=new ASTVisitor() {
		@Override
		public boolean visit(MethodInvocation node) {
			if(!node.getName().getIdentifier().equals(name))
				return true;
			return true;
		}
	};
	cunit1.accept(astvisitor);
	cunit1.accept(astvisitor2);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. When adding the method reference we can give parameter for method name "add"
	private boolean handleMethodInvocation(MethodInvocation assignment, ReferenceHolder<String,NodeFound> holder) {
		System.out.println(assignment);
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	BiPredicate<MethodInvocation, ReferenceHolder<String, NodeFound>> bs = this::handleMethodInvocation; // First Handler
	BiPredicate<MethodInvocation, ReferenceHolder<String, NodeFound>> after = (mi,rh)->{ // Second Handler
		return true;
	};
	BiPredicate<MethodInvocation, ReferenceHolder<String, NodeFound>> bs2= bs.or(after); // Combine Handlers
	hv.addMethodInvocation("add", bs2);
	hv.build(cunit1);

ASTVisitor for all kinds of nodes

Old way to use visitor

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}

	...
	ASTVisitor astvisitor=new ASTVisitor() {
		
		@Override
		public void endVisit(AnnotationTypeDeclaration node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}

		@Override
		public boolean visit(AnnotationTypeDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}
			
		@Override
		public void endVisit(AnonymousClassDeclaration node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}
			
		@Override
		public boolean visit(AnonymousClassDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}

		...
		// <List of n overwritten visitor stubs>
			
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. VisitorEnum is an enum containing all possible kinds of nodes. You can iterate on it to add visitors for all possible nodetypes.

Using method references

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	VisitorEnum.stream().forEach(ve -> {
		hv.add(ve, this::astnodeprocesser);
	});
	VisitorEnum.stream().forEach(ve -> {
		hv.addEnd(ve, this::astnodeprocessorend);
	});
	hv.build(cunit1);

Using lambda expressions

Instead of method references you can of course use lambda expressions

	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<String, NodeFound>());
	VisitorEnum.stream().forEach(ve -> {
		hv.add(ve, (node, holder) -> {
			String x = "Start "+node.getNodeType() + " :" + node;
			System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
			return true;
		});
	});
	VisitorEnum.stream().forEach(ve -> {
		hv.addEnd(ve, (node, holder) -> {
			String x = "End   "+node.getNodeType() + " :" + node;
			System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		});
	});
	hv.build(cunit1);

ASTVisitor for all kinds of nodes (simplified version)

Old way to use visitor

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}

	...
	ASTVisitor astvisitor=new ASTVisitor() {
		
		@Override
		public void endVisit(AnnotationTypeDeclaration node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}

		@Override
		public boolean visit(AnnotationTypeDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}
			
		@Override
		public void endVisit(AnonymousClassDeclaration node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}
			
		@Override
		public boolean visit(AnonymousClassDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}

		...
		// <List of n overwritten visitor stubs>
			
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. VisitorEnum is an enum containing all possible kinds of nodes. You can iterate on it to add visitors for all possible nodetypes.

In this variant, we use the method of HelperVisitor that has one parameter for visitand one for visitend.

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	VisitorEnum.stream().forEach(ve -> {
		hv.add(ve, this::astnodeprocessor,this::astnodeprocessorend);
	});
	hv.build(cunit2);

ASTVisitor for all kinds of nodes (further simplified version)

Old way to use visitor

	private Boolean astnodeprocesser(ASTNode node) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}

	...
	ASTVisitor astvisitor=new ASTVisitor() {
		
		@Override
		public void endVisit(AnnotationTypeDeclaration node) {
			VisitorTest.this.astnodeprocessor(node);
		}

		@Override
		public boolean visit(AnnotationTypeDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node);
		}
			
		@Override
		public void endVisit(AnonymousClassDeclaration node) {
			VisitorTest.this.astnodeprocessor(node);
		}
			
		@Override
		public boolean visit(AnonymousClassDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node);
		}

		...
		// <List of n overwritten visitor stubs>
			
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. VisitorEnum is an enum containing all possible kinds of nodes. You can iterate on it to add visitors for all possible nodetypes.

In this variant, we use the method of HelperVisitor that has one parameter for visitand one for visitend.

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	VisitorEnum.stream().forEach(ve -> {
		hv.add(ve, this::astnodeprocessor,this::astnodeprocessor);
	});
	hv.build(cunit2);

ASTVisitor for a specific collection of nodes

Old way to use visitor

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}

	...
	ASTVisitor astvisitor=new ASTVisitor() {
		
		@Override
		public void endVisit(SingleVariableDeclaration node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}

		@Override
		public boolean visit(SingleVariableDeclaration node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}
			
		@Override
		public void endVisit(VariableDeclarationExpression node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}
			
		@Override
		public boolean visit(VariableDeclarationExpression node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}

		@Override
		public void endVisit(VariableDeclarationStatement node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}

		@Override
		public boolean visit(VariableDeclarationStatement node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}
			
		@Override
		public void endVisit(VariableDeclarationFragment node) {
			VisitorTest.this.astnodeprocessorend(node,null);
		}
			
		@Override
		public boolean visit(VariableDeclarationFragment node) {
			return VisitorTest.this.astnodeprocessor(node,null);
		}
			
	};
	cunit1.accept(astvisitor);

New way to use visitor

The central class here is HelperVisitor. Because of some new features, the number of parameters changed.

  1. ReferenceHolder is a working object to hold information that is needed while visiting the nodes in the tree. You can use it to collect information or to share information.
  2. Set<ASTNode> nodesprocessed is to make sure that processing (changing) a node is not done twice. For cleanups/quickfixes you should not apply two different cleanups at the same time to the same node. This data structure is responsible to remember a node has already got a change and is not processed twice.
  3. VisitorEnum is an enum containing all possible kinds of nodes. You can iterate on it to add visitors for all possible nodetypes.

Using method references

	private void astnodeprocessorend(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "End   "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
	}

	private Boolean astnodeprocesser(ASTNode node, ReferenceHolder<String,NodeFound> holder) {
		String x = "Start "+node.getNodeType() + " :" + node;
		System.out.printf("%-40s %s%n",x,ASTNode.nodeClassForType(node.getNodeType()));
		return true;
	}
	
	...
	Set<ASTNode> nodesprocessed = null;
	HelperVisitor<ReferenceHolder<String,NodeFound>,String,NodeFound> hv = new HelperVisitor<>(nodesprocessed, new ReferenceHolder<>());
	EnumSet<VisitorEnum> myset = EnumSet.of(
			VisitorEnum.SingleVariableDeclaration,
			VisitorEnum.VariableDeclarationExpression,
			VisitorEnum.VariableDeclarationStatement,
			VisitorEnum.VariableDeclarationFragment);
	myset.forEach(ve -> {
		hv.add(ve, this::astnodeprocessor,this::astnodeprocessorend);
	});
	hv.build(cunit1);

Using lambda expressions

	EnumSet<VisitorEnum> myset = EnumSet.of(
			VisitorEnum.SingleVariableDeclaration,
			VisitorEnum.VariableDeclarationExpression,
			VisitorEnum.VariableDeclarationStatement,
			VisitorEnum.VariableDeclarationFragment);
	ReferenceHolder<ASTNode, String> dataholder = new ReferenceHolder<>();
	BiPredicate<ASTNode, ReferenceHolder<ASTNode, String>> bs =(node,holder)->{
		System.out.printf("%-40s %s%n","Start "+node.getNodeType() + " :" + node,ASTNode.nodeClassForType(node.getNodeType()));
		return false;
	};
	BiConsumer<ASTNode, ReferenceHolder<ASTNode, String>> bc = (node,holder)->{
		System.out.printf("%-40s %s%n","End   "+node.getNodeType() + " :" + node,ASTNode.nodeClassForType(node.getNodeType()));
	};
	HelperVisitor.callVisitor(cunit1, myset, dataholder,null, bs, bc);

Sample Plugins

Clone this wiki locally