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 - [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
/*******************************************************************************
* 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 m1
and m2
are methods of type T
then according to this comparator m1
is less than
m2
iff one of following holds:
m1
and m2
are defined in the same type (T
or any
supertype of T
), that type has a source attachment and m1
appears
before m2
in source of that type
m1
and m2
are defined in the same type (T
or any
supertype of T
), that type doesn't have a source attachment and name of
m1
alphabetically precedes name of m2
m2
is defined in T
and m1
is defined in any supertype
of T
m2
is defined in a superclass of T
and m1
is defined
in a superinterface of T
m1
and m2
are defined in different superclasses of T
and a class which defines m1
extends class which defines m2
m1
and m2
are defined in different superinterfaces of
T
and an interface which defines m2
appears before an interface which
defines m1
in implements
clause of declaration of type T
/**
* 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;
}
}
}