/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.core.tests.model; import java.util.Comparator; import java.util.List; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.util.CompilationUnitSorter; import com.ibm.icu.text.Collator; /** * The class <code>DefaultJavaElementComparator</code> is a standard * implementation of a comparator. * <p> * <ul> * <li>static fields, arranged alphabetically by name and access modifier * (public, protected, private, default)</li> * <li>static initializers in order of appearance</li> * <li>instance fields, arranged alphabetically by name and access modifier * (public, protected, private, default)</li> * <li>instance initializers in order of appearance</li> * <li>type declarations, arranged alphabetically by name and access modifier * (public, protected, private, default)</li> * <li>constructors, arranged by parameter order and access modifier * (public, protected, private, default)</li> * <li>methods, arranged by alphabetically by name and parameter order and * access modifier (public, protected, private, default)</li> * </p> */ @SuppressWarnings("rawtypes") class DefaultJavaElementComparator implements Comparator { private static final int STATIC_TYPE_CATEGORY = 0; private static final int STATIC_FIELD_CATEGORY = 1; private static final int STATIC_INITIALIZER_CATEGORY = 2; private static final int STATIC_METHOD_CATEGORY = 3; private static final int TYPE_CATEGORY = 4; private static final int FIELD_CATEGORY = 5; private static final int INITIALIZER_CATEGORY = 6; private static final int CONSTRUCTOR_CATEGORY = 7; private static final int METHOD_CATEGORY = 8; private Collator collator; private int[] categories; /** * Creates an instance that sorts the various categories of body * declarations in the following order: * <ol> * <li>static types</li> * <li>static fields </li> * <li>static initializers</li> * <li>non-static fields</li> * <li>instance initializers</li> * <li>types</li> * <li>static methods</li> * <li>constructors</li> * <li>non-static methods</li> * </ol> */ public DefaultJavaElementComparator() { // initialize default categories this.categories = new int[] { 1, // static type 2, // static field 3, // static initializer 7, // static method 6, // type 4, // field 5, // initializer 8, // constructor 9 // method }; this.collator = Collator.getInstance(); } /** * Creates an instance that arranges the various categories of body * declarations. * This constructor is used to specify customized values for the different categories. * They are a convinient way to distinguish AST nodes. * The lower a value is, the higher the node will appear in the sorted * compilation unit. * <p> * There are nine categories with theirs default values: * <ol> * <li>static types (1)</li> * <li>static fields (2)</li> * <li>static initializers (3)</li> * <li>fields (4) </li> * <li>initializers (5)</li> * <li>types (6)</li> * <li>static methods (7)</li> * <li>constructors (8)</li> * <li>methods (9)</li> * </ol> * </p> * * @param staticTypeCategory the given value for the static type category * @param staticFieldCategory the given value for the static field category * @param staticInitializerCategory the given value for the static initializer category * @param staticMethodCategory the given value for static the method category * @param typeCategory the given value for the type category * @param fieldCategory the given value for field category * @param initializerCategory the given value for initializer category * @param constructorCategory the given value for constructor category * @param methodCategory the given value for method category */ public DefaultJavaElementComparator( int staticTypeCategory, int staticFieldCategory, int staticInitializerCategory, int staticMethodCategory, int typeCategory, int fieldCategory, int initializerCategory, int constructorCategory, int methodCategory) { this.categories = new int[] { staticTypeCategory, staticFieldCategory, staticInitializerCategory, staticMethodCategory, typeCategory, fieldCategory, initializerCategory, constructorCategory, methodCategory }; this.collator = Collator.getInstance(); } /** * This method is used to retrieve the category for a body declaration node according to the * preferences passed at the creation of the comparator. * * @param node the given node * @return the category corresponding to the given node * * @since 2.1 */ private int getCategory(BodyDeclaration node) { switch(node.getNodeType()) { case ASTNode.METHOD_DECLARATION : MethodDeclaration methodDeclaration = (MethodDeclaration) node; if (methodDeclaration.isConstructor()) { return this.categories[CONSTRUCTOR_CATEGORY]; } if (Flags.isStatic(methodDeclaration.getModifiers())) { return this.categories[STATIC_METHOD_CATEGORY]; } return this.categories[METHOD_CATEGORY]; case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION : if (Flags.isStatic(node.getModifiers())) { return this.categories[STATIC_METHOD_CATEGORY]; } return this.categories[METHOD_CATEGORY]; case ASTNode.FIELD_DECLARATION : FieldDeclaration fieldDeclaration = (FieldDeclaration) node; if (Flags.isStatic(fieldDeclaration.getModifiers())) { return this.categories[STATIC_FIELD_CATEGORY]; } return this.categories[FIELD_CATEGORY]; case ASTNode.ENUM_CONSTANT_DECLARATION : return this.categories[STATIC_FIELD_CATEGORY]; case ASTNode.TYPE_DECLARATION : case ASTNode.ENUM_DECLARATION : case ASTNode.ANNOTATION_TYPE_DECLARATION : AbstractTypeDeclaration abstractTypeDeclaration = (AbstractTypeDeclaration) node; if (Flags.isStatic(abstractTypeDeclaration.getModifiers())) { return this.categories[STATIC_TYPE_CATEGORY]; } return this.categories[TYPE_CATEGORY]; case ASTNode.INITIALIZER : Initializer initializer = (Initializer) node; if (Flags.isStatic(initializer.getModifiers())) { return this.categories[STATIC_INITIALIZER_CATEGORY]; } return this.categories[INITIALIZER_CATEGORY]; } return 0; } /** * The <code>DefaultJavaElementComparator</code> implementation of this * <code>java.util.Comparator</code> method can only be used to compare * instances of <code>org.eclipse.jdt.core.dom.BodyDeclaration</code>. * <p> * The categories of each body declaration are compared. If they are * in different categories, they are ordered based on their category. * Body declarations within the same category are ordered by signature * string. Body declarations with the same signature string are ordered * by their original relative positions. * </p> */ public int compare(Object o1, Object o2) { if (!(o1 instanceof BodyDeclaration) && !(o2 instanceof BodyDeclaration)) { throw new ClassCastException(); } BodyDeclaration node1 = (BodyDeclaration) o1; BodyDeclaration node2 = (BodyDeclaration) o2; int category1 = getCategory(node1); int category2 = getCategory(node2); if (category1 != category2) { return category1 - category2; } if (o1 == o2) { return 0; } String node1Signature = buildSignature(node1); String node2Signature = buildSignature(node2); if (node1Signature.length() != 0 && node2Signature.length() != 0) { int compare = this.collator.compare(node1Signature, node2Signature); if (compare != 0) { return compare; } } int sourceStart1 = ((Integer) node1.getProperty(CompilationUnitSorter.RELATIVE_ORDER)).intValue(); int sourceStart2 = ((Integer) node2.getProperty(CompilationUnitSorter.RELATIVE_ORDER)).intValue(); return sourceStart1 - sourceStart2; } private String buildSignature(BodyDeclaration node) { switch(node.getNodeType()) { case ASTNode.METHOD_DECLARATION : MethodDeclaration methodDeclaration = (MethodDeclaration) node; StringBuffer buffer = new StringBuffer(); buffer.append(methodDeclaration.getName().getIdentifier()); final List parameters = methodDeclaration.parameters(); int length1 = parameters.size(); for (int i = 0; i < length1; i++) { SingleVariableDeclaration parameter = (SingleVariableDeclaration) parameters.get(i); buffer.append(parameter.getName().getIdentifier()); Type type = parameter.getType(); buffer.append(buildSignature(type)); } return String.valueOf(buffer); case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION : AnnotationTypeMemberDeclaration annotationTypeMemberDeclaration = (AnnotationTypeMemberDeclaration) node; return annotationTypeMemberDeclaration.getName().getIdentifier(); case ASTNode.FIELD_DECLARATION : FieldDeclaration fieldDeclaration = (FieldDeclaration) node; return ((VariableDeclarationFragment) fieldDeclaration.fragments().get(0)).getName().getIdentifier(); case ASTNode.ENUM_CONSTANT_DECLARATION : EnumConstantDeclaration enumConstantDeclaration = (EnumConstantDeclaration) node; return enumConstantDeclaration.getName().getIdentifier(); case ASTNode.INITIALIZER : return ((Integer) node.getProperty(CompilationUnitSorter.RELATIVE_ORDER)).toString(); case ASTNode.TYPE_DECLARATION : case ASTNode.ENUM_DECLARATION : case ASTNode.ANNOTATION_TYPE_DECLARATION : AbstractTypeDeclaration abstractTypeDeclaration = (AbstractTypeDeclaration) node; return abstractTypeDeclaration.getName().getIdentifier(); } return null; } private String buildSignature(Type type) { switch(type.getNodeType()) { case ASTNode.PRIMITIVE_TYPE : PrimitiveType.Code code = ((PrimitiveType) type).getPrimitiveTypeCode(); return code.toString(); case ASTNode.ARRAY_TYPE : ArrayType arrayType = (ArrayType) type; StringBuffer buffer = new StringBuffer(); buffer.append(buildSignature(arrayType.getElementType())); int dimensions = arrayType.getDimensions(); for (int j = 0; j < dimensions; j++) { buffer.append("[]"); //$NON-NLS-1$ } return buffer.toString(); case ASTNode.SIMPLE_TYPE : SimpleType simpleType = (SimpleType) type; return buildSignature(simpleType.getName()); } return null; // should never happen } private String buildSignature(Name name) { if (name.isSimpleName()) { return ((SimpleName) name).getIdentifier(); } QualifiedName qualifiedName = (QualifiedName) name; return buildSignature(qualifiedName.getQualifier()) + "." + buildSignature(qualifiedName.getName()); //$NON-NLS-1$ } }