blob: 18dcc72e43ae8e6308002045be4ecc63484828b8 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 20038 Technical University Berlin, Germany.
*
* 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
* $Id: Sorting.java 23417 2010-02-03 20:13:55Z stephan $
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.util;
import java.util.Arrays;
import java.util.Comparator;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
/**
* Sorting utilities.
*
* @author stephan
* @since 1.2.1
*/
public class Sorting {
/**
* Topological sort for member types with depth first search.
* Guarantee: supertypes come before subtypes.
*/
public static void sortMemberTypes(SourceTypeBinding enclosing) {
int len = enclosing.memberTypes.length;
ReferenceBinding[] unsorted = new ReferenceBinding[len];
ReferenceBinding[] sorted = new ReferenceBinding[len];
System.arraycopy(enclosing.memberTypes, 0, unsorted, 0, len);
int o = 0;
for(int i=0; i<len; i++)
o = sort(enclosing, unsorted, i, sorted, o);
enclosing.memberTypes = sorted;
}
// Transfer input[i] and all its supers into output[o] ff.
private static int sort(ReferenceBinding enclosing,
ReferenceBinding[] input, int i,
ReferenceBinding[] output, int o)
{
if (input[i] == null)
return o;
ReferenceBinding superclass = input[i].superclass();
o = sortSuper(enclosing, superclass, input, output, o);
for (ReferenceBinding superIfc : input[i].superInterfaces())
o = sortSuper(enclosing, superIfc, input, output, o);
// done with supers, now input[i] can safely be transferred:
output[o++] = input[i];
input[i] = null;
return o;
}
// if superclass is within the set of member types to sort,
// transfer it and all its supers to output[o] ff.
private static int sortSuper(ReferenceBinding enclosing,
ReferenceBinding superclass,
ReferenceBinding[] input,
ReferenceBinding[] output, int o)
{
if ( superclass != null // inspecting super of Confined?
&& superclass.id != TypeIds.T_JavaLangObject
&& TypeBinding.equalsEquals(superclass.enclosingType(), enclosing)) // is super within scope?
{
// search superclass within input:
int j = 0;
for(j=0; j<input.length; j++)
if (TypeBinding.equalsEquals(input[j], superclass))
break;
if (j < input.length)
// depth first traversal:
o = sort(enclosing, input, j, output, o);
// otherwise assume super was already transferred.
}
return o;
}
// --- similar for role models:
public static RoleModel[] sortRoles(RoleModel[] unsorted) {
int len = unsorted.length;
RoleModel[] sorted = new RoleModel[len];
int o = 0;
for(int i=0; i<len; i++)
o = sort(unsorted, i, sorted, o);
// also consider the base hierarchy, but for roles bound to
// the same base keep the existing order.
Arrays.sort(sorted, new Comparator<RoleModel>() {
@Override
public int compare(RoleModel o1, RoleModel o2) {
ReferenceBinding b1 = o1.getBaseTypeBinding();
ReferenceBinding b2 = o2.getBaseTypeBinding();
if (TypeBinding.equalsEquals(b1, b2))
return 0;
if (b1 != null && b1.id != TypeIds.T_JavaLangObject) {
if (b2 == null || b2.id == TypeIds.T_JavaLangObject)
return 1;
if (b1.isCompatibleWith(b2))
return 1;
if (b2.isCompatibleWith(b1))
return -1;
} else {
if (b2 != null && b2.id != TypeIds.T_JavaLangObject)
return -1;
}
return 0;
}
});
return sorted;
}
// Transfer input[i] and all its supers into output[o] ff.
private static int sort(RoleModel[] input, int i,
RoleModel[] output, int o)
{
if (input[i] == null || input[i].getBinding() == null)
return o;
ReferenceBinding inBinding = input[i].getBinding();
ReferenceBinding superclass = inBinding.superclass();
o = sortSuper(superclass, input, output, o);
for (ReferenceBinding superIfc : inBinding.superInterfaces())
o = sortSuper(superIfc, input, output, o);
// done with supers, now input[i] can safely be transferred:
output[o++] = input[i];
input[i] = null;
return o;
}
// if superclass is within the set of member types to sort,
// transfer it and all its supers to output[o] ff.
private static int sortSuper(ReferenceBinding superclass,
RoleModel[] input,
RoleModel[] output, int o)
{
if ( superclass != null // inspecting super of Confined?
&& superclass.id != TypeIds.T_JavaLangObject) // is super within scope?
{
boolean inScope = false;
for (RoleModel rm : input)
if (rm != null && TypeBinding.equalsEquals(rm.getBinding(), superclass)) {
inScope = true;
break;
}
if (inScope) {
// search superclass within input:
int j = 0;
for(j=0; j<input.length; j++)
if (input[j] != null && TypeBinding.equalsEquals(input[j].getBinding(), superclass))
break;
if (j < input.length)
// depth first traversal:
o = sort(input, j, output, o);
// otherwise assume super was already transferred.
}
}
return o;
}
/** Apply the sorting from member type bindings to their ASTs, too. */
public static void sortMemberTypes(TypeDeclaration typeDeclaration) {
if (typeDeclaration.memberTypes == null) return;
ReferenceBinding[] bindings = typeDeclaration.binding.memberTypes;
TypeDeclaration[] unsorted = typeDeclaration.memberTypes;
TypeDeclaration[] newMembers = new TypeDeclaration[unsorted.length];
int l = 0;
allMembers: for (int i=0; i<bindings.length; i++) {
ReferenceBinding current = bindings[i];
if (current.isBinaryBinding())
continue; // no AST: phantom or reused rofi
// find corresponding AST
for (int j=0; j<unsorted.length; j++) {
if (TypeBinding.equalsEquals(unsorted[j].binding, current)) {
newMembers[l++] = unsorted[j];
continue allMembers;
}
}
throw new InternalCompilerError("Unmatched member type "+String.valueOf(current.readableName())); //$NON-NLS-1$
}
if (l<newMembers.length)
throw new InternalCompilerError("Not all member types matched: "+l); //$NON-NLS-1$
typeDeclaration.memberTypes = newMembers;
}
}