package ru.naumen.gintonic.project.source.builder; import java.util.List; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.IPackageBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import ru.naumen.gintonic.utils.ListUtils; import ru.naumen.gintonic.utils.Preconditions; public class ImportStatemenentCalculator { private IType targetType; private List<SingleVariableDeclaration> variableDecl; public void setTargetType(IType targetType) { this.targetType = targetType; } public void setVariableDecl(List<SingleVariableDeclaration> variableDecl) { this.variableDecl = variableDecl; } /** * Calculates the import statements based on a list of variable * declarations. We do also filter anything from * java.lang as the language spec tells us that we do not have to import * these. * * It is assumed that the import statements should be included * in the given target type, which implies that we filter any references in * the same package as the target class. The target class can also be null, * which means we do not filter. * * @return a list of type bindings which the target type has to import. */ public List<ITypeBinding> calculate() { List<ITypeBinding> importBindings = ListUtils.newArrayListWithCapacity(variableDecl.size()); for (SingleVariableDeclaration singleVariableDeclaration : variableDecl) { Type type = singleVariableDeclaration.getType(); Preconditions.checkNotNull(type); final ITypeBinding typeBinding = type.resolveBinding(); Preconditions.checkNotNull( typeBinding, "No type binding available! Maybe you forgot to " + "enable the binding-resolving in the ASTParser?"); filterBindingsThatNeedToBeImported(typeBinding, importBindings); } List<ITypeBinding> filteredImportBindings = applyFilter(importBindings); return filteredImportBindings; } private void filterBindingsThatNeedToBeImported( final ITypeBinding typeBinding, List<ITypeBinding> importBindings) { /* e.g Dog[] */ if (typeBinding.isArray()) { /* The component type for Dog[] is Dog */ ITypeBinding componentTypeBinding = typeBinding.getComponentType(); /* The component type may be another type => Recursion */ filterBindingsThatNeedToBeImported( componentTypeBinding, importBindings); } /* e.g Map<String, Dog>. */ else if (typeBinding.isParameterizedType()) { /* Type Declaration of Map<String, Dog> is Map */ ITypeBinding typeDeclaration = typeBinding.getTypeDeclaration(); importBindings.add(typeDeclaration); /* * Recursion is needed to handle the nested case (e.g., * Vector<Vector<String>>). */ ITypeBinding[] typeArguments = typeBinding.getTypeArguments(); for (ITypeBinding typeArgument : typeArguments) { filterBindingsThatNeedToBeImported(typeArgument, importBindings); } } else if (typeBinding.isPrimitive()) { /* * Not important for import statement calculation as primitives * don't require to be imported */ } else if (typeBinding.isWildcardType()) { ITypeBinding erasureBinding = typeBinding.getErasure(); filterBindingsThatNeedToBeImported(erasureBinding, importBindings); } else if (typeBinding.isCapture()) { throw new RuntimeException("Capture type unsupported"); } else { importBindings.add(typeBinding); } } protected List<ITypeBinding> applyFilter(List<ITypeBinding> typeBindings) { List<ITypeBinding> filteredTypeBindings = ListUtils.newArrayListWithCapacity(typeBindings.size()); for (ITypeBinding typeBinding : typeBindings) { IPackageBinding packageBinding = typeBinding.getPackage(); Preconditions.checkNotNull(packageBinding); String packageQualifiedName = packageBinding.getName(); /* Ignore anything in java.lang */ if (!packageQualifiedName.equals("java.lang")) { if(targetType != null){ /* * and any class which is in the same package as the target * class */ IPackageFragment packageFragment = targetType.getPackageFragment(); String packageOfTargetClass = packageFragment.getElementName(); if (!packageQualifiedName.equals(packageOfTargetClass)) { filteredTypeBindings.add(typeBinding); } }else{ filteredTypeBindings.add(typeBinding); } } } return filteredTypeBindings; } }