| /******************************************************************************* |
| * Copyright (c) 2000, 2008 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.wst.jsdt.core.tests.model; |
| |
| import java.util.Comparator; |
| import java.util.List; |
| |
| import org.eclipse.wst.jsdt.core.Flags; |
| import org.eclipse.wst.jsdt.core.dom.ASTNode; |
| import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.ArrayType; |
| import org.eclipse.wst.jsdt.core.dom.BodyDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.FieldDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.Initializer; |
| import org.eclipse.wst.jsdt.core.dom.Name; |
| import org.eclipse.wst.jsdt.core.dom.PrimitiveType; |
| import org.eclipse.wst.jsdt.core.dom.QualifiedName; |
| import org.eclipse.wst.jsdt.core.dom.SimpleName; |
| import org.eclipse.wst.jsdt.core.dom.SimpleType; |
| import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.wst.jsdt.core.dom.Type; |
| import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.wst.jsdt.core.util.JavaScriptUnitSorter; |
| |
| 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> |
| */ |
| 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.FUNCTION_DECLARATION : |
| FunctionDeclaration methodDeclaration = (FunctionDeclaration) 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.FIELD_DECLARATION : |
| FieldDeclaration fieldDeclaration = (FieldDeclaration) node; |
| if (Flags.isStatic(fieldDeclaration.getModifiers())) { |
| return this.categories[STATIC_FIELD_CATEGORY]; |
| } |
| return this.categories[FIELD_CATEGORY]; |
| case ASTNode.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.wst.jsdt.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(JavaScriptUnitSorter.RELATIVE_ORDER)).intValue(); |
| int sourceStart2 = ((Integer) node2.getProperty(JavaScriptUnitSorter.RELATIVE_ORDER)).intValue(); |
| return sourceStart1 - sourceStart2; |
| } |
| |
| private String buildSignature(BodyDeclaration node) { |
| switch(node.getNodeType()) { |
| case ASTNode.FUNCTION_DECLARATION : |
| FunctionDeclaration methodDeclaration = (FunctionDeclaration) 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.FIELD_DECLARATION : |
| FieldDeclaration fieldDeclaration = (FieldDeclaration) node; |
| return ((VariableDeclarationFragment) fieldDeclaration.fragments().get(0)).getName().getIdentifier(); |
| case ASTNode.INITIALIZER : |
| return ((Integer) node.getProperty(JavaScriptUnitSorter.RELATIVE_ORDER)).toString(); |
| case ASTNode.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$ |
| } |
| } |