CheckNodeForValidReferences.java

package org.sandbox.jdt.internal.corext.fix.helper;

import java.util.Iterator;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.internal.corext.dom.AbortSearchException;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;

class CheckNodeForValidReferences {
	private static final String ITERATOR_NAME= Iterator.class.getCanonicalName();

	private final ASTNode fASTNode;
	private final boolean fLocalVarsOnly;

	public CheckNodeForValidReferences(ASTNode node, boolean localVarsOnly) {
		fASTNode= node;
		fLocalVarsOnly= localVarsOnly;
	}

	public boolean isValid() {
		ASTVisitor visitor= new ASTVisitor() {

			@Override
			public boolean visit(FieldAccess visitedField) {
				IVariableBinding binding= visitedField.resolveFieldBinding();
				if (binding == null) {
					throw new AbortSearchException();
				}
				if (fLocalVarsOnly && visitedField.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY) {
					MethodInvocation methodInvocation= ASTNodes.getParent(visitedField, MethodInvocation.class);
					IMethodBinding methodInvocationBinding= methodInvocation.resolveMethodBinding();
					if (methodInvocationBinding == null) {
						throw new AbortSearchException();
					}
					ITypeBinding methodTypeBinding= methodInvocationBinding.getReturnType();
					if (AbstractTool.isOfType(methodTypeBinding, ITERATOR_NAME)) {
						throw new AbortSearchException();
					}
				}
				return true;
			}

			@Override
			public boolean visit(SuperFieldAccess visitedField) {
				IVariableBinding binding= visitedField.resolveFieldBinding();
				if (binding == null) {
					throw new AbortSearchException();
				}
				if (fLocalVarsOnly && visitedField.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY) {
					MethodInvocation methodInvocation= ASTNodes.getParent(visitedField, MethodInvocation.class);
					IMethodBinding methodInvocationBinding= methodInvocation.resolveMethodBinding();
					if (methodInvocationBinding == null) {
						throw new AbortSearchException();
					}
					ITypeBinding methodTypeBinding= methodInvocationBinding.getReturnType();
					if (AbstractTool.isOfType(methodTypeBinding, ITERATOR_NAME)) {
						throw new AbortSearchException();
					}
				}
				return true;
			}

			@Override
			public boolean visit(MethodInvocation methodInvocation) {
				if (fLocalVarsOnly) {
					IMethodBinding methodInvocationBinding= methodInvocation.resolveMethodBinding();
					if (methodInvocationBinding == null) {
						throw new AbortSearchException();
					}
					ITypeBinding methodTypeBinding= methodInvocationBinding.getReturnType();
					if (AbstractTool.isOfType(methodTypeBinding, ITERATOR_NAME)) {
						Expression exp= methodInvocation.getExpression();
						if (exp instanceof SimpleName) {
							IBinding binding= ((SimpleName) exp).resolveBinding();
							if (binding instanceof IVariableBinding && !((IVariableBinding) binding).isField()
									&& !((IVariableBinding) binding).isParameter()
									&& !((IVariableBinding) binding).isRecordComponent()) {
								ITypeBinding typeBinding= ((IVariableBinding) binding).getType();
								if (AbstractTool.isOfType(typeBinding, ITERATOR_NAME)) {
									return true;
								}
							}
						}
						throw new AbortSearchException();
					}
				}
				return true;
			}

			@Override
			public boolean visit(CastExpression castExpression) {
				Type castType= castExpression.getType();
				ITypeBinding typeBinding= castType.resolveBinding();
				if (AbstractTool.isOfType(typeBinding, ITERATOR_NAME)) {
					Expression exp= castExpression.getExpression();
					if (exp instanceof Name) {
						IBinding binding= ((Name) exp).resolveBinding();
						if (binding instanceof IVariableBinding simpleNameVarBinding) {
							if (!fLocalVarsOnly) {
								if (!simpleNameVarBinding.isField() && !simpleNameVarBinding.isParameter()
										&& !simpleNameVarBinding.isRecordComponent()) {
									throw new AbortSearchException();
								}
							} else {
								if (simpleNameVarBinding.isField() || simpleNameVarBinding.isParameter()
										|| simpleNameVarBinding.isRecordComponent()) {
									throw new AbortSearchException();
								}
							}
						}
					}
					throw new AbortSearchException();
				}
				return true;
			}

			@Override
			public boolean visit(SimpleName simpleName) {
				IBinding simpleNameBinding= simpleName.resolveBinding();
				if (simpleNameBinding == null) {
					throw new AbortSearchException();
				}
				if (simpleNameBinding instanceof IVariableBinding simpleNameVarBinding) {
					ITypeBinding simpleNameTypeBinding= simpleNameVarBinding.getType();
					if (AbstractTool.isOfType(simpleNameTypeBinding, ITERATOR_NAME)) {
						if (simpleName.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY) {
							MethodInvocation methodInvocation= ASTNodes.getParent(simpleName, MethodInvocation.class);
							IMethodBinding methodInvocationBinding= methodInvocation.resolveMethodBinding();
							if (methodInvocationBinding == null) {
								throw new AbortSearchException();
							}
							ITypeBinding methodInvocationReturnType= methodInvocationBinding.getReturnType();
							if (!AbstractTool.isOfType(methodInvocationReturnType, ITERATOR_NAME)) {
								return true;
							}
						}
						if (!fLocalVarsOnly) {
							if (!simpleNameVarBinding.isField() && !simpleNameVarBinding.isParameter()
									&& !simpleNameVarBinding.isRecordComponent()) {
								throw new AbortSearchException();
							}
						} else if (simpleNameVarBinding.isField() || simpleNameVarBinding.isParameter()
								|| simpleNameVarBinding.isRecordComponent()) {
							throw new AbortSearchException();
						}
					}
				}
				return true;
			}
		};
		try {
			fASTNode.accept(visitor);
			return true;
		} catch (AbortSearchException e) {
			// do nothing and fall through
		}
		return false;
	}

}