blob: 5dcb1a2c8721ae57c1be26b220ccaf473eb878bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Mateusz Wenus <mateusz.wenus@gmail.com> - [override method] generate in declaration order [code generation] - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140971
* IBM Corporation - bug fixes
* Red Hat Inc. - refactored to jdt.core.manipulation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.util;
import java.util.Comparator;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.SourceRange;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
/**
* A comparator which sorts methods (IMethodBinding) of a type passed as constructor argument,
* according to their order in source files. More formally, if <code>m1</code> and <code>m2</code>
* are methods of type <code>T</code> then according to this comparator <code>m1</code> is less than
* <code>m2</code> iff one of following holds:
* <ul>
* <li><code>m1</code> and <code>m2</code> are defined in the same type (<code>T</code> or any
* supertype of <code>T</code>), that type has a source attachment and <code>m1</code> appears
* before <code>m2</code> in source of that type</li>
* <li><code>m1</code> and <code>m2</code> are defined in the same type (<code>T</code> or any
* supertype of <code>T</code>), that type doesn't have a source attachment and name of
* <code>m1</code> alphabetically precedes name of <code>m2</code></li>
*
* <li><code>m2</code> is defined in <code>T</code> and <code>m1</code> is defined in any supertype
* of <code>T</code></li>
* <li><code>m2</code> is defined in a superclass of <code>T</code> and <code>m1</code> is defined
* in a superinterface of <code>T</code></li>
* <li><code>m1</code> and <code>m2</code> are defined in different superclasses of <code>T</code>
* and a class which defines <code>m1</code> extends class which defines <code>m2</code>
* <li><code>m1</code> and <code>m2</code> are defined in different superinterfaces of
* <code>T</code> and an interface which defines <code>m2</code> appears before an interface which
* defines <code>m1</code> in <code>implements</code> clause of declaration of type <code>T</code></li>
* </ul>
*/
public class MethodsSourcePositionComparator implements Comparator<IMethodBinding> {
private final ITypeBinding fTypeBinding;
public MethodsSourcePositionComparator(ITypeBinding typeBinding) {
if (typeBinding == null) {
throw new IllegalArgumentException();
}
fTypeBinding= typeBinding;
}
@Override
public int compare(IMethodBinding firstMethodBinding, IMethodBinding secondMethodBinding) {
if (firstMethodBinding == null || secondMethodBinding == null) {
return 0;
}
ITypeBinding firstMethodType= firstMethodBinding.getDeclaringClass();
ITypeBinding secondMethodType= secondMethodBinding.getDeclaringClass();
if (firstMethodType.equals(secondMethodType)) {
return compareInTheSameType(firstMethodBinding, secondMethodBinding);
}
if (firstMethodType.equals(fTypeBinding)) {
return 1;
}
if (secondMethodType.equals(fTypeBinding)) {
return -1;
}
ITypeBinding type= fTypeBinding;
int count= 0, firstCount= -1, secondCount= -1;
while ((type= type.getSuperclass()) != null) {
if (firstMethodType.equals(type)) {
firstCount= count;
}
if (secondMethodType.equals(type)) {
secondCount= count;
}
count++;
}
if (firstCount != -1 && secondCount != -1) {
return (firstCount - secondCount);
}
if (firstCount != -1 && secondCount == -1) {
return 1;
}
if (firstCount == -1 && secondCount != -1) {
return -1;
}
ITypeBinding[] interfaces= fTypeBinding.getInterfaces();
for (int i= 0; i < interfaces.length; i++) {
if (firstMethodType.equals(interfaces[i])) {
return 1;
}
if (secondMethodType.equals(interfaces[i])) {
return -1;
}
}
return 0;
}
private int compareInTheSameType(IMethodBinding firstMethodBinding, IMethodBinding secondMethodBinding) {
try {
IMethod firstMethod= (IMethod)firstMethodBinding.getJavaElement();
IMethod secondMethod= (IMethod)secondMethodBinding.getJavaElement();
if (firstMethod == null || secondMethod == null) {
return 0;
}
ISourceRange firstSourceRange= firstMethod.getSourceRange();
ISourceRange secondSourceRange= secondMethod.getSourceRange();
if (!SourceRange.isAvailable(firstSourceRange) || !SourceRange.isAvailable(secondSourceRange)) {
return firstMethod.getElementName().compareTo(secondMethod.getElementName());
} else {
return firstSourceRange.getOffset() - secondSourceRange.getOffset();
}
} catch (JavaModelException e) {
return 0;
}
}
}