/******************************************************************************* * 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 <jogl@google.com> - import group sorting is broken - https://bugs.eclipse.org/430303 *******************************************************************************/ package org.eclipse.jdt.internal.core.dom.rewrite.imports; import java.util.Comparator; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.internal.core.JavaProject; /** * Sorts imports according to a lexicographic comparison of their containing package names. * <p> * This requires use of the JavaProject to look up packages and/or types by name in order to * distinguish segments of the import's container name as containing package name vs. containing * type name. * <p> * The alternative is {@link PackageAndContainingTypeImportComparator}. See * https://bugs.eclipse.org/194358. */ final class PackageImportComparator implements Comparator<ImportName> { private final JavaProject javaProject; PackageImportComparator(JavaProject javaProject) { this.javaProject = javaProject; } @Override public int compare(ImportName o1, ImportName o2) { return determinePackageName(o1).compareTo(determinePackageName(o2)); } private String determinePackageName(ImportName importName) { String containerName = importName.containerName; try { // Loop from longest to shortest prefix (of dot-separated name segments) of the // container name until a package name is found. String containerNamePrefix = containerName; while (true) { // Try to find a package named with this prefix. if (this.javaProject.findPackageFragment(containerNamePrefix) != null) { return containerNamePrefix; } int lastSegmentStart = containerNamePrefix.lastIndexOf(Signature.C_DOT) + 1; // Use the heuristic that a prefix whose last segment starts with a lowercase letter // is a package name, if we don't recognize the prefix as the name of a type. if (this.javaProject.findType(containerNamePrefix) == null) { if (Character.isLowerCase(containerNamePrefix.charAt(lastSegmentStart))) { return containerNamePrefix; } } if (lastSegmentStart == 0) { // No prefix of containerName could be resolved to a package name. break; } containerNamePrefix = containerNamePrefix.substring(0, lastSegmentStart - 1); } } catch (JavaModelException e) { // An error occurred when we asked the JavaProject to resolve a name, // so there is no point in proceeding with the loop. } return containerName; } }