org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteConfiguration Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2015 Google Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* John Glassmyer - import group sorting is broken - https://bugs.eclipse.org/430303
*******************************************************************************/
package org.eclipse.jdt.internal.core.dom.rewrite.imports;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageDeclaration;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaProject;
/**
* Used as a constructor parameter to ImportRewriteAnalyzer to configure its behavior.
*
* The starting points are the two static factory methods of {@link Builder}.
*/
public final class ImportRewriteConfiguration {
public enum OriginalImportHandling {
/**
* Specifies to discard original imports and totally sort all new imports, as in the case of
* the "Organize Imports" operation.
*/
DISCARD {
@Override
boolean shouldRemoveOriginalImports() {
return true;
}
@Override
boolean shouldFixAllLineDelimiters() {
return true;
}
@Override
ImportAdder createImportAdder(Comparator importComparator) {
return new ReorderingImportAdder(importComparator);
}
},
/**
* Specifies to keep original imports in their original order, placing each newly added
* import adjacent to the original import that it most closely matches.
*/
PRESERVE_IN_ORDER {
@Override
boolean shouldRemoveOriginalImports() {
return false;
}
@Override
boolean shouldFixAllLineDelimiters() {
return false;
}
@Override
ImportAdder createImportAdder(Comparator importComparator) {
return new OrderPreservingImportAdder(importComparator);
}
},
;
/**
* If true, ImportRewriteAnalyzer will, during its initialization, mark all original imports
* for removal.
*/
abstract boolean shouldRemoveOriginalImports();
/**
* If true, line delimiters will be standardized between every pair of adjacent imports.
* Otherwise, line delimiters will be corrected only between pairs of adjacent imports that
* were not adjacent originally.
*/
abstract boolean shouldFixAllLineDelimiters();
/**
* Creates the {@link ImportAdder} which will combine and order new and existing imports
* together.
*/
abstract ImportAdder createImportAdder(Comparator importComparator);
}
/**
* Specifies how to sort import declarations by their packages and/or containing types.
*/
public enum ImportContainerSorting {
/**
* Sorts imports by each import's package and any containing types, in lexicographic order.
* For example (assuming that all of the imports belong to the same import group):
*
* import java.net.Socket;
* import java.util.Map;
* import java.util.Set;
* import java.util.Map.Entry;
*
*/
BY_PACKAGE_AND_CONTAINING_TYPE {
@Override
Comparator createContainerComparator(JavaProject javaProject) {
return new PackageAndContainingTypeImportComparator();
}
},
/**
* Sorts imports by each import's package, in lexicographic order. For example (assuming all
* of the imports belong to the same import group):
*
* import java.net.Socket;
* import java.util.Map;
* import java.util.Map.Entry;
* import java.util.Set;
*
*/
BY_PACKAGE {
@Override
Comparator createContainerComparator(JavaProject javaProject) {
return new PackageImportComparator(javaProject);
}
},
;
abstract Comparator createContainerComparator(JavaProject javaProject);
}
/**
* Specifies which types are considered to be implicitly imported.
*
* An import declaration of such a type will not be added to the compilation unit unless it is
* needed to resolve a conflict with an on-demand imports, or the type's simple name has been
* specified with {@link ImportRewriteAnalyzer#requireExplicitImport}.
*
* Also, implicitly imported types will be considered for conflicts when deciding which types
* from other packages can be reduced into on-demand imports. E.g. if java.lang.Integer were
* considered to be implicitly imported, that would prevent an import of com.example.Integer
* from being reduced into an on-demand import of com.example.*.
*/
public enum ImplicitImportIdentification {
/**
* Specifies that types from the following packages are considered to be implicitly
* imported:
*
* - java.lang
* - the package of the compilation unit being rewritten
*
*/
JAVA_LANG_AND_CU_PACKAGE {
@Override
Set determineImplicitImportContainers(ICompilationUnit compilationUnit) {
Set implicitImportContainerNames = new HashSet();
implicitImportContainerNames.add("java.lang"); //$NON-NLS-1$
IJavaElement packageFragment = compilationUnit.getParent();
String compilationUnitPackageName = packageFragment.getElementName();
if (compilationUnitPackageName.isEmpty() && !packageFragment.exists() && compilationUnit.exists()) {
/*
* For a file outside of the build path, JavaCore#create(IFile) creates an
* ICompilationUnit with the file's parent folder as package fragment root, and a default package.
* That "wrong" package is problematic for the ImportRewrite, since it doesn't get filtered
* and eventually leads to unused import statements.
*/
try {
IPackageDeclaration[] packageDeclarations = compilationUnit.getPackageDeclarations();
if (packageDeclarations.length > 0) {
implicitImportContainerNames.add(packageDeclarations[0].getElementName());
return implicitImportContainerNames;
}
} catch (JavaModelException e) {
// continue
}
}
implicitImportContainerNames.add(compilationUnitPackageName);
return implicitImportContainerNames;
}
},
/**
* Specifies that no types are considered to be implicitly imported.
*/
NONE {
@Override
Set determineImplicitImportContainers(ICompilationUnit compilationUnit) {
return Collections.emptySet();
}
},
;
abstract Set determineImplicitImportContainers(ICompilationUnit compilationUnit);
}
public static class Builder {
public static Builder discardingOriginalImports() {
return new Builder(OriginalImportHandling.DISCARD);
}
public static Builder preservingOriginalImports() {
return new Builder(OriginalImportHandling.PRESERVE_IN_ORDER);
}
final OriginalImportHandling originalImportHandling;
ImportContainerSorting typeContainerSorting;
ImportContainerSorting staticContainerSorting;
ImplicitImportIdentification implicitImportIdentification;
List importOrder;
Integer typeOnDemandThreshold;
Integer staticOnDemandThreshold;
private Builder(OriginalImportHandling originalImportHandling) {
this.originalImportHandling = originalImportHandling;
this.typeContainerSorting = ImportContainerSorting.BY_PACKAGE;
this.staticContainerSorting = ImportContainerSorting.BY_PACKAGE_AND_CONTAINING_TYPE;
this.implicitImportIdentification = ImplicitImportIdentification.JAVA_LANG_AND_CU_PACKAGE;
this.importOrder = Collections.emptyList();
this.typeOnDemandThreshold = null;
this.staticOnDemandThreshold = null;
}
public Builder setTypeContainerSorting(ImportContainerSorting typeContainerSorting) {
this.typeContainerSorting = typeContainerSorting;
return this;
}
public Builder setStaticContainerSorting(ImportContainerSorting staticContainerSorting) {
this.staticContainerSorting = staticContainerSorting;
return this;
}
public Builder setImplicitImportIdentification(ImplicitImportIdentification implicitImportIdentification) {
this.implicitImportIdentification = implicitImportIdentification;
return this;
}
public Builder setImportOrder(List importOrder) {
this.importOrder = Collections.unmodifiableList(new ArrayList(importOrder));
return this;
}
public Builder setTypeOnDemandThreshold(int typeOnDemandThreshold) {
this.typeOnDemandThreshold = typeOnDemandThreshold;
return this;
}
public Builder setStaticOnDemandThreshold(int staticOnDemandThreshold) {
this.staticOnDemandThreshold = staticOnDemandThreshold;
return this;
}
public ImportRewriteConfiguration build() {
return new ImportRewriteConfiguration(this);
}
}
final OriginalImportHandling originalImportHandling;
final ImportContainerSorting typeContainerSorting;
final ImportContainerSorting staticContainerSorting;
final ImplicitImportIdentification implicitImportIdentification;
final List importOrder;
final int typeOnDemandThreshold;
final int staticOnDemandThreshold;
ImportRewriteConfiguration(Builder builder) {
this.originalImportHandling = builder.originalImportHandling;
this.typeContainerSorting = builder.typeContainerSorting;
this.staticContainerSorting = builder.staticContainerSorting;
this.implicitImportIdentification = builder.implicitImportIdentification;
this.importOrder = builder.importOrder;
this.typeOnDemandThreshold = builder.typeOnDemandThreshold;
this.staticOnDemandThreshold = builder.staticOnDemandThreshold;
}
}