blob: 31233ccbdb9675d3459a439773135839491439e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import java.util.Comparator;
import java.util.Stack;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
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.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.util.CompilationUnitSorter;
import org.eclipse.jdt.internal.compiler.SourceElementRequestorAdapter;
import org.eclipse.jdt.internal.compiler.env.IConstants;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
/**
*
* @since 2.1
*/
public class SortElementBuilder extends SourceElementRequestorAdapter {
abstract class SortElement extends SortJavaElement {
SortElement(int sourceStart, int modifiers) {
super(SortElementBuilder.this);
this.sourceStart = normalizeSourceStart(sourceStart);
modifiers &= ~IConstants.AccInterface; // remove AccInterface flags
modifiers &= CompilerModifiers.AccJustFlag;
this.modifiers = modifiers;
this.children_count = 0;
}
protected void setParameters(MethodDeclaration methodDeclaration, String[] parameterNames, String[] parameterTypes) {
for (int i = 0, max = parameterNames.length; i < max; i++) {
String paramType = parameterTypes[i];
SingleVariableDeclaration singleVariableDeclaration = ast.newSingleVariableDeclaration();
singleVariableDeclaration.setName(ast.newSimpleName(parameterNames[i]));
int indexOfArrayBrace;
if (paramType.indexOf('.') != -1) {
String[] typeParts = splitOn('.', paramType);
int length = typeParts.length;
indexOfArrayBrace = typeParts[length - 1].indexOf('[');
if (indexOfArrayBrace != -1) {
int dimensions = occurencesOf('[', typeParts[length - 1]);
typeParts[length - 1] = typeParts[length - 1].substring(0, indexOfArrayBrace);
String[] typeSubstrings = new String[length];
for (int j = 0; j < length; j++) {
typeSubstrings[j] = typeParts[j];
}
singleVariableDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newName(typeSubstrings)), dimensions));
} else {
String[] typeSubstrings = new String[length];
for (int j = 0; j < length; j++) {
typeSubstrings[j] = new String(typeParts[j]);
}
singleVariableDeclaration.setType(ast.newSimpleType(ast.newName(typeSubstrings)));
}
} else if ((indexOfArrayBrace = paramType.indexOf('[')) != -1) {
int dimensions = occurencesOf('[', paramType);
paramType = paramType.substring(0, indexOfArrayBrace);
singleVariableDeclaration.setType(ast.newArrayType(newType(paramType), dimensions));
} else {
singleVariableDeclaration.setType(newType(paramType));
}
methodDeclaration.parameters().add(singleVariableDeclaration);
}
}
protected String[] splitOn(char divider, String stringToSplit) {
int length = stringToSplit == null ? 0 : stringToSplit.length();
if (length == 0)
return new String[] { stringToSplit };
int wordCount = 1;
for (int i = 0; i < length; i++)
if (stringToSplit.charAt(i) == divider)
wordCount++;
String[] split = new String[wordCount];
int last = 0, currentWord = 0;
for (int i = 0; i < length; i++) {
if (stringToSplit.charAt(i) == divider) {
split[currentWord++] = stringToSplit.substring(last, i);
last = i + 1;
}
}
split[currentWord] = stringToSplit.substring(last, length);
return split;
}
protected int occurencesOf(char toBeFound, String s) {
if (s == null) return 0;
int count = 0;
for (int i = 0, max = s.length(); i < max; i++)
if (toBeFound == s.charAt(i))
count++;
return count;
}
protected Type newType(String typeSource) {
// check if type is a primitive type
scanner.setSource(typeSource.toCharArray());
scanner.resetTo(0, typeSource.length());
int token = 0;
try {
token = scanner.getNextToken();
} catch(InvalidInputException e) {
return null;
}
if (token == TerminalTokens.TokenNameIdentifier) {
return ast.newSimpleType(ast.newSimpleName(typeSource));
} else {
switch(token) {
case TerminalTokens.TokenNameint :
return ast.newPrimitiveType(PrimitiveType.INT);
case TerminalTokens.TokenNamebyte :
return ast.newPrimitiveType(PrimitiveType.BYTE);
case TerminalTokens.TokenNameboolean :
return ast.newPrimitiveType(PrimitiveType.BOOLEAN);
case TerminalTokens.TokenNamechar :
return ast.newPrimitiveType(PrimitiveType.CHAR);
case TerminalTokens.TokenNamedouble :
return ast.newPrimitiveType(PrimitiveType.DOUBLE);
case TerminalTokens.TokenNamefloat :
return ast.newPrimitiveType(PrimitiveType.FLOAT);
case TerminalTokens.TokenNamelong :
return ast.newPrimitiveType(PrimitiveType.LONG);
case TerminalTokens.TokenNameshort :
return ast.newPrimitiveType(PrimitiveType.SHORT);
case TerminalTokens.TokenNamevoid :
return ast.newPrimitiveType(PrimitiveType.VOID);
}
}
return null;
}
abstract ASTNode convert();
}
abstract class SortAbstractMethodDeclaration extends SortElement {
SortAbstractMethodDeclaration(int sourceStart, int modifiers, char[] name, char[][] parametersNames, char[][] parametersTypes, char[][] thrownExceptions) {
super(sourceStart, modifiers);
this.name = new String(name);
if (parametersNames != null) {
int length = parametersNames.length;
this.parametersNames = new String[length];
this.parametersTypes = new String[length];
for (int i = 0; i < length; i++) {
this.parametersNames[i] = new String(parametersNames[i]);
this.parametersTypes[i] = new String(parametersTypes[i]);
}
}
if (thrownExceptions != null) {
int length = thrownExceptions.length;
this.thrownExceptions = new String[length];
for (int i = 0; i < length; i++) {
this.thrownExceptions[i] = new String(thrownExceptions[i]);
}
}
}
public String decodeSignature() {
StringBuffer buffer = new StringBuffer();
buffer.append("("); //$NON-NLS-1$
if (this.parametersNames != null) {
int length = parametersNames.length;
for (int i = 0; i < length - 1; i++) {
buffer.append(parametersTypes[i] + " " + parametersNames[i] + ", "); //$NON-NLS-1$ //$NON-NLS-2$
}
buffer.append(parametersTypes[length - 1] + " " + parametersNames[length - 1]); //$NON-NLS-1$
}
buffer.append(")"); //$NON-NLS-1$
return buffer.toString();
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
this.children[i].generateSource(buffer);
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
} else {
buffer.append(SortElementBuilder.this.source, this.sourceStart, this.sourceEnd - this.sourceStart + 1);
}
}
protected void mapPositions() {
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
mapNextPosition(this, start, end);
this.children[i].mapPositions();
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
mapNextPosition(this, start, end);
} else {
mapNextPosition(this, this.sourceStart, this.sourceEnd);
}
}
}
class SortMethodDeclaration extends SortAbstractMethodDeclaration {
SortMethodDeclaration(int sourceStart, int modifiers, char[] name, char[][] parametersNames, char[][] parametersTypes, char[][] thrownExceptions, char[] returnType) {
super(sourceStart, modifiers, name, parametersNames, parametersTypes, thrownExceptions);
this.id = METHOD;
if (returnType != null) {
this.returnType = new String(returnType);
}
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("method ") //$NON-NLS-1$
.append(name)
.append(decodeSignature());
if (returnType != null) {
buffer.append(" " + returnType + LINE_SEPARATOR); //$NON-NLS-1$
} else {
buffer.append(LINE_SEPARATOR); //$NON-NLS-1$
}
}
ASTNode convert() {
MethodDeclaration methodDeclaration = ast.newMethodDeclaration();
methodDeclaration.setConstructor(false);
methodDeclaration.setModifiers(this.modifiers);
methodDeclaration.setName(ast.newSimpleName(this.name));
methodDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
// set parameter names and types
if (this.parametersNames != null) {
setParameters(methodDeclaration, this.parametersNames, this.parametersTypes);
}
// set thrown exceptions
if (this.thrownExceptions != null) {
for (int j = 0, max2 = this.thrownExceptions.length; j < max2; j++) {
String currentException = this.thrownExceptions[j];
Name exceptionName;
if (currentException.indexOf('.') == -1) {
exceptionName = ast.newSimpleName(currentException);
} else {
exceptionName = ast.newName(splitOn('.', currentException));
}
methodDeclaration.thrownExceptions().add(exceptionName);
}
}
// set return type
int indexOfArrayBrace;
String currentReturnType = this.returnType;
if (currentReturnType != null) {
if (currentReturnType.indexOf('.') != -1) {
String[] returnTypeSubstrings = splitOn('.', currentReturnType);
int length = returnTypeSubstrings.length;
indexOfArrayBrace = returnTypeSubstrings[length - 1].indexOf('[');
if (indexOfArrayBrace != -1) {
int dimensions = occurencesOf('[', returnTypeSubstrings[length - 1]);
returnTypeSubstrings[length - 1] = returnTypeSubstrings[length - 1].substring(0, indexOfArrayBrace);
methodDeclaration.setReturnType(ast.newArrayType(ast.newSimpleType(ast.newName(returnTypeSubstrings)), dimensions));
} else {
methodDeclaration.setReturnType(ast.newSimpleType(ast.newName(returnTypeSubstrings)));
}
} else if ((indexOfArrayBrace = currentReturnType.indexOf('[')) != -1) {
int dimensions = occurencesOf('[', currentReturnType);
currentReturnType = currentReturnType.substring(0, indexOfArrayBrace);
methodDeclaration.setReturnType(ast.newArrayType(newType(currentReturnType), dimensions));
} else {
methodDeclaration.setReturnType(newType(currentReturnType));
}
}
return methodDeclaration;
}
}
class SortConstructorDeclaration extends SortAbstractMethodDeclaration {
SortConstructorDeclaration(int sourceStart, int modifiers, char[] name, char[][] parametersNames, char[][] parametersTypes, char[][] thrownExceptions) {
super(sourceStart, modifiers, name, parametersNames, parametersTypes, thrownExceptions);
this.id = CONSTRUCTOR;
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("constructor ") //$NON-NLS-1$
.append(decodeSignature() + LINE_SEPARATOR);
}
ASTNode convert() {
MethodDeclaration methodDeclaration = ast.newMethodDeclaration();
methodDeclaration.setConstructor(true);
methodDeclaration.setModifiers(this.modifiers);
methodDeclaration.setName(ast.newSimpleName(this.name));
methodDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
// set parameter names and types
if (this.parametersNames != null) {
setParameters(methodDeclaration, this.parametersNames, this.parametersTypes);
}
// set thrown exceptions
if (this.thrownExceptions != null) {
for (int j = 0, max2 = this.thrownExceptions.length; j < max2; j++) {
String currentException = this.thrownExceptions[j];
Name exceptionName;
if (currentException.indexOf('.') == -1) {
exceptionName = ast.newSimpleName(currentException);
} else {
exceptionName = ast.newName(splitOn('.', currentException));
}
methodDeclaration.thrownExceptions().add(exceptionName);
}
}
return methodDeclaration;
}
}
public class SortFieldDeclaration extends SortElement {
int previousSourceEnd;
SortFieldDeclaration(int sourceStart, int modifiers, char[] type, char[] name, int nameSourceStart) {
super(sourceStart, modifiers);
this.declarationStart = sourceStart;
this.id = FIELD;
this.type = new String(type);
this.name = new String(name);
this.nameSourceStart = nameSourceStart;
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("field ") //$NON-NLS-1$
.append(type + " " + name + LINE_SEPARATOR); //$NON-NLS-1$
}
ASTNode convert() {
VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
variableDeclarationFragment.setName(ast.newSimpleName(this.name));
FieldDeclaration fieldDeclaration = ast.newFieldDeclaration(variableDeclarationFragment);
String currentFieldType = this.type;
int indexOfArrayBrace;
if (currentFieldType.indexOf('.') != -1) {
String[] typeParts = splitOn('.', currentFieldType);
int length = typeParts.length;
indexOfArrayBrace = typeParts[length - 1].indexOf('[');
if (indexOfArrayBrace != -1) {
int dimensions = occurencesOf('[', typeParts[length - 1]);
typeParts[length - 1] = typeParts[length - 1].substring(0, indexOfArrayBrace);
fieldDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newName(typeParts)), dimensions));
} else {
fieldDeclaration.setType(ast.newSimpleType(ast.newName(typeParts)));
}
} else if ((indexOfArrayBrace = currentFieldType.indexOf('[')) != -1) {
int dimensions = occurencesOf('[', currentFieldType);
currentFieldType = currentFieldType.substring(0, indexOfArrayBrace);
fieldDeclaration.setType(ast.newArrayType(newType(currentFieldType), dimensions));
} else {
fieldDeclaration.setType(newType(currentFieldType));
}
fieldDeclaration.setModifiers(this.modifiers);
fieldDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
return fieldDeclaration;
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
this.children[i].generateSource(buffer);
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.declarationSourceEnd;
}
}
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
} else {
buffer.append(SortElementBuilder.this.source, this.sourceStart, this.declarationSourceEnd - this.sourceStart + 1);
}
}
protected void generateReduceSource(StringBuffer buffer) {
int length = this.children_count;
if (length != 0) {
int start = this.nameSourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
this.children[i].generateSource(buffer);
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
} else {
buffer.append(SortElementBuilder.this.source, this.nameSourceStart, this.sourceEnd - this.nameSourceStart + 1);
}
}
protected void mapReducedPositions() {
int length = this.children_count;
if (length != 0) {
int start = this.nameSourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
mapNextPosition(this, start, end);
for (int i = 0; i < length; i++) {
this.children[i].mapPositions();
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
mapNextPosition(this, start, end);
} else {
mapNextPosition(this, this.nameSourceStart, this.sourceEnd);
}
}
protected void mapPositions() {
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
mapNextPosition(this, start, end);
this.children[i].mapPositions();
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.declarationSourceEnd;
}
}
mapNextPosition(this, start, end);
} else {
mapNextPosition(this, this.sourceStart, this.declarationSourceEnd);
}
}
}
class SortMultipleFieldDeclaration extends SortElement {
SortMultipleFieldDeclaration(SortFieldDeclaration fieldDeclaration) {
super(fieldDeclaration.declarationStart, fieldDeclaration.modifiers);
this.declarationStart = fieldDeclaration.declarationStart;
this.id = MULTIPLE_FIELD;
this.innerFields = new SortFieldDeclaration[1];
this.fieldCounter = 0;
this.innerFields[this.fieldCounter++] = fieldDeclaration;
this.type = fieldDeclaration.type;
this.sourceStart = fieldDeclaration.sourceStart;
fieldDeclaration.sourceEnd = fieldDeclaration.previousSourceEnd;
}
void addField(SortFieldDeclaration fieldDeclaration) {
System.arraycopy(this.innerFields, 0, this.innerFields = new SortFieldDeclaration[this.fieldCounter + 1], 0, this.fieldCounter);
this.innerFields[this.fieldCounter++] = fieldDeclaration;
fieldDeclaration.sourceEnd = fieldDeclaration.previousSourceEnd;
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("multiple fields ") //$NON-NLS-1$
.append(LINE_SEPARATOR);
if (this.innerFields != null) {
buffer
.append(tab(tab + 1))
.append("INNER FIELDS ------------------------------" + LINE_SEPARATOR); //$NON-NLS-1$
for (int i = 0; i < this.fieldCounter; i++) {
buffer.append(this.innerFields[i].toString(tab + 2));
buffer.append(LINE_SEPARATOR);
}
}
}
ASTNode convert() {
VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
variableDeclarationFragment.setName(ast.newSimpleName(this.innerFields[0].name));
FieldDeclaration fieldDeclaration = ast.newFieldDeclaration(variableDeclarationFragment);
for (int j = 1, max2 = this.innerFields.length; j < max2; j++) {
VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
fragment.setName(ast.newSimpleName(new String(this.innerFields[j].name)));
}
String currentFieldType = this.type;
int indexOfArrayBrace;
if (currentFieldType.indexOf('.') != -1) {
String[] typeParts = splitOn('.', currentFieldType);
int length = typeParts.length;
indexOfArrayBrace = typeParts[length - 1].indexOf('[');
if (indexOfArrayBrace != -1) {
int dimensions = occurencesOf('[', typeParts[length - 1]);
typeParts[length - 1] = typeParts[length - 1].substring(0, indexOfArrayBrace);
fieldDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newName(typeParts)), dimensions));
} else {
fieldDeclaration.setType(ast.newSimpleType(ast.newName(typeParts)));
}
} else if ((indexOfArrayBrace = currentFieldType.indexOf('[')) != -1) {
int dimensions = occurencesOf('[', currentFieldType);
currentFieldType = currentFieldType.substring(0, indexOfArrayBrace);
fieldDeclaration.setType(ast.newArrayType(newType(currentFieldType), dimensions));
} else {
fieldDeclaration.setType(newType(currentFieldType));
}
fieldDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
fieldDeclaration.setModifiers(this.modifiers);
return fieldDeclaration;
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.fieldCounter;
int start = this.innerFields[0].sourceStart;
int end = this.innerFields[0].nameSourceStart - 1;
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
for (int i = 0; i < length; i++) {
this.innerFields[i].newSourceStart = this.newSourceStart;
this.innerFields[i].generateReduceSource(buffer);
if (i < length - 1) {
start = this.innerFields[i].sourceEnd + 1;
end = this.innerFields[i + 1].nameSourceStart - 1;
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
}
}
start = this.innerFields[length - 1].sourceEnd + 1;
end = this.innerFields[length - 1].declarationSourceEnd;
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
}
protected void mapPositions() {
int length = this.fieldCounter;
int start = this.innerFields[0].sourceStart;
int end = this.innerFields[0].nameSourceStart - 1;
mapNextPosition(this, start, end);
for (int i = 0; i < length; i++) {
this.innerFields[i].newSourceStart = this.newSourceStart;
this.innerFields[i].mapReducedPositions();
if (i < length - 1) {
start = this.innerFields[i].sourceEnd + 1;
end = this.innerFields[i + 1].nameSourceStart - 1;
mapNextPosition(this, start, end);
}
}
start = this.innerFields[length - 1].sourceEnd + 1;
end = this.innerFields[length - 1].declarationSourceEnd;
mapNextPosition(this, start, end);
}
protected void sort() {
for (int i = 0, max = this.fieldCounter; i < max; i++) {
this.innerFields[i].sort();
}
}
}
class SortInitializer extends SortElement {
SortInitializer(int sourceStart, int modifiers) {
super(sourceStart, modifiers);
this.id = INITIALIZER;
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("initializer " + LINE_SEPARATOR); //$NON-NLS-1$
}
ASTNode convert() {
Initializer initializer = ast.newInitializer();
initializer.setModifiers(this.modifiers);
initializer.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
return initializer;
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
this.children[i].generateSource(buffer);
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
buffer.append(SortElementBuilder.this.source, start, end - start + 1);
} else {
buffer.append(SortElementBuilder.this.source, this.sourceStart, this.sourceEnd - this.sourceStart + 1);
}
}
protected void mapPositions() {
int length = this.children_count;
if (length != 0) {
int start = this.sourceStart;
int end = this.firstChildBeforeSorting.sourceStart - 1;
for (int i = 0; i < length; i++) {
mapNextPosition(this, start, end);
this.children[i].mapPositions();
if (i < length - 1) {
start = this.children[i].sourceEnd + 1;
} else {
start = this.lastChildBeforeSorting.sourceEnd + 1;
}
if (i < length - 1) {
end = this.children[i + 1].sourceStart - 1;
} else {
end = this.sourceEnd;
}
}
mapNextPosition(this, start, end);
} else {
mapNextPosition(this, this.sourceStart, this.sourceEnd);
}
}
}
class SortClassDeclaration extends SortType {
SortClassDeclaration(int sourceStart, int modifiers, char[] name, char[] superclass, char[][] superinterfaces) {
super(sourceStart, modifiers, name, superinterfaces);
this.id = CLASS | TYPE;
if (superclass != null) {
this.superclass = new String(superclass);
}
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("class ") //$NON-NLS-1$
.append(this.name);
if (this.superclass != null) {
buffer.append(" extends " + this.superclass); //$NON-NLS-1$
}
if (this.superInterfaces != null) {
int length = this.superInterfaces.length;
buffer.append(" implements "); //$NON-NLS-1$
for (int i = 0; i < length - 1; i++) {
buffer.append(this.superInterfaces[i] + ", "); //$NON-NLS-1$
}
buffer.append(this.superInterfaces[length - 1]);
}
buffer.append(LINE_SEPARATOR);
}
ASTNode convert() {
TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
typeDeclaration.setInterface(false);
typeDeclaration.setModifiers(this.modifiers);
typeDeclaration.setName(ast.newSimpleName(this.name));
// set superclass
if (this.superclass != null) {
if (this.superclass.indexOf('.') == -1) {
// the superclass is a simple name
typeDeclaration.setSuperclass(ast.newSimpleName(this.superclass));
} else {
// the superclass is a qualified name
String[] superclassNames = splitOn('.', this.superclass);
typeDeclaration.setSuperclass(ast.newName(superclassNames));
}
}
// set superinterfaces
if (this.superInterfaces != null) {
for (int j = 0, max2 = this.superInterfaces.length; j < max2; j++) {
String currentInterfaceName = this.superInterfaces[j];
Name interfaceName;
if (currentInterfaceName.indexOf('.') == -1) {
// the superclass is a simple name
interfaceName = ast.newSimpleName(currentInterfaceName);
} else {
// the superclass is a qualified name
String[] interfaceNames = splitOn('.', currentInterfaceName);
interfaceName = ast.newName(interfaceNames);
}
typeDeclaration.superInterfaces().add(interfaceName);
}
}
typeDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
return typeDeclaration;
}
}
abstract class SortType extends SortElement {
SortType(int sourceStart, int modifier, char[] name, char[][] superinterfaces) {
super(sourceStart, modifier);
this.name = new String(name);
if (superinterfaces != null) {
int length = superinterfaces.length;
this.superInterfaces = new String[length];
for (int i = 0; i < length; i++) {
this.superInterfaces[i] = new String(superinterfaces[i]);
}
}
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.children_count;
int start = this.sourceStart;
if (length != 0) {
int end = this.firstChildBeforeSorting.sourceStart;
buffer.append(SortElementBuilder.this.source, start, end - start);
for (int i = 0; i < length; i++) {
((SortElementBuilder.SortElement)this.astNodes[i].getProperty(CORRESPONDING_ELEMENT)).generateSource(buffer);
}
start = this.lastChildBeforeSorting.sourceEnd + 1;
buffer.append(SortElementBuilder.this.source, start, this.sourceEnd - start + 1);
} else {
buffer.append(SortElementBuilder.this.source, start, this.sourceEnd - start + 1);
}
}
protected void mapPositions() {
int length = this.children_count;
int start = this.sourceStart;
if (length != 0) {
int end = this.firstChildBeforeSorting.sourceStart - 1;
mapNextPosition(this, start, end);
for (int i = 0; i < length; i++) {
children[i].mapPositions();
}
start = this.lastChildBeforeSorting.sourceEnd + 1;
mapNextPosition(this, start, this.sourceEnd);
} else {
mapNextPosition(this, start, this.sourceEnd);
}
}
}
class SortInterfaceDeclaration extends SortType {
SortInterfaceDeclaration(int sourceStart, int modifiers, char[] name, char[][] superinterfaces) {
super(sourceStart, modifiers, name, superinterfaces);
this.id = TYPE | INTERFACE;
}
void display(StringBuffer buffer, int tab) {
buffer
.append(tab(tab))
.append("interface ") //$NON-NLS-1$
.append(this.name);
if (this.superInterfaces != null) {
int length = this.superInterfaces.length;
buffer.append(" implements "); //$NON-NLS-1$
for (int i = 0; i < length - 1; i++) {
buffer.append(this.superInterfaces[i] + ", "); //$NON-NLS-1$
}
buffer.append(this.superInterfaces[length - 1]);
}
buffer.append(LINE_SEPARATOR);
}
ASTNode convert() {
TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
typeDeclaration.setInterface(true);
typeDeclaration.setModifiers(this.modifiers);
typeDeclaration.setName(ast.newSimpleName(this.name));
// set superinterfaces
if (this.superInterfaces != null) {
for (int j = 0, max2 = this.superInterfaces.length; j < max2; j++) {
String currentInterfaceName = this.superInterfaces[j];
Name interfaceName;
if (currentInterfaceName.indexOf('.') == -1) {
// the superclass is a simple name
interfaceName = ast.newSimpleName(currentInterfaceName);
} else {
// the superclass is a qualified name
String[] interfaceNames = splitOn('.', currentInterfaceName);
interfaceName = ast.newName(interfaceNames);
}
typeDeclaration.superInterfaces().add(interfaceName);
}
}
typeDeclaration.setProperty(CompilationUnitSorter.RELATIVE_ORDER, new Integer(this.sourceStart));
return typeDeclaration;
}
}
class SortCompilationUnit extends SortElement {
SortCompilationUnit(int sourceStart) {
super(sourceStart, 0);
this.id = COMPILATION_UNIT;
}
void display(StringBuffer buffer, int tab) {
// nothing to do
}
ASTNode convert() {
return ast.newCompilationUnit();
}
/**
* @see org.eclipse.jdt.internal.core.SortElementBuilder.SortElement#generateSource(java.lang.StringBuffer)
*/
protected void generateSource(StringBuffer buffer) {
super.generateSource(buffer);
int length = this.children_count;
if (length != 0) {
int end = this.firstChildBeforeSorting.sourceStart;
int start = this.lastChildBeforeSorting.sourceEnd + 1;
buffer.append(SortElementBuilder.this.source, 0, end);
for (int i = 0; i < length; i++) {
((SortElementBuilder.SortElement)this.astNodes[i].getProperty(CORRESPONDING_ELEMENT)).generateSource(buffer);
}
buffer.append(SortElementBuilder.this.source, start, this.sourceEnd - start + 1);
}
}
protected void mapPositions() {
int length = this.children_count;
if (length != 0) {
int end = this.firstChildBeforeSorting.sourceStart;
int start = this.lastChildBeforeSorting.sourceEnd + 1;
mapNextPosition(this, 0, end);
for (int i = 0; i < length; i++) {
children[i].mapPositions();
}
mapNextPosition(this, start, this.sourceEnd);
} else {
mapNextPosition(this, this.sourceStart, this.sourceEnd);
}
}
}
SortElement currentElement;
Stack stack;
SortCompilationUnit compilationUnit;
Scanner scanner;
AST ast;
char[] source;
int[] lineEnds;
Comparator comparator;
int[] positionsToMap;
int positionsToMapIndex;
public SortElementBuilder(char[] source, int[] positionsToMap, Comparator comparator, CompilerOptions options) {
this.source = source;
this.comparator = comparator;
this.positionsToMap = positionsToMap;
this.ast = AST.newAST(AST.JLS2);
this.scanner = new Scanner(false, false, false, options.sourceLevel/*sourceLevel*/, null, null, true/*taskCaseSensitive*/);
}
/*
* @see ISourceElementRequestor#acceptLineSeparatorPositions(int[])
*/
public void acceptLineSeparatorPositions(int[] positions) {
this.lineEnds = positions;
}
public String getSource() {
StringBuffer buffer = new StringBuffer();
this.positionsToMapIndex = 0;
this.compilationUnit.generateSource(buffer);
if (this.positionsToMap != null) {
this.compilationUnit.mapPositions();
}
return buffer.toString();
}
private static int searchLineNumber(
int[] startLineIndexes,
int position) {
// this code is completely useless, but it is the same implementation than
// org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
// if (startLineIndexes == null)
// return 1;
int length = startLineIndexes.length;
if (length == 0)
return 1;
int g = 0, d = length - 1;
int m = 0;
while (g <= d) {
m = (g + d) / 2;
if (position < startLineIndexes[m]) {
d = m - 1;
} else
if (position > startLineIndexes[m]) {
g = m + 1;
} else {
return m + 1;
}
}
if (position < startLineIndexes[m]) {
return m + 1;
}
return m + 2;
}
void sort() {
this.compilationUnit.sort();
}
void mapNextPosition(SortJavaElement node, int start, int end) {
int i = this.positionsToMapIndex;
for (; i < this.positionsToMap.length; i++) {
int nextPosition = this.positionsToMap[i];
if (nextPosition >= start
&& nextPosition <= end) {
this.positionsToMap[i] += (node.newSourceStart - node.sourceStart);
} else {
break;
}
}
this.positionsToMapIndex = i;
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterCompilationUnit()
*/
public void enterCompilationUnit() {
this.stack = new Stack();
push(this.compilationUnit = new SortCompilationUnit(0));
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterConstructor(MethodInfo)
*/
public void enterConstructor(MethodInfo methodInfo) {
if ((this.currentElement.id & SortJavaElement.TYPE) != 0) {
SortConstructorDeclaration constructorDeclaration = new SortConstructorDeclaration(methodInfo.declarationStart, methodInfo.modifiers, methodInfo.name, methodInfo.parameterNames, methodInfo.parameterTypes, methodInfo.exceptionTypes);
this.currentElement.addChild(constructorDeclaration);
push(constructorDeclaration);
}
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterField(FieldInfo)
*/
public void enterField(FieldInfo fieldInfo) {
if ((this.currentElement.id & SortJavaElement.TYPE) != 0) {
SortFieldDeclaration fieldDeclaration = new SortFieldDeclaration(fieldInfo.declarationStart, fieldInfo.modifiers, fieldInfo.type, fieldInfo.name, fieldInfo.nameSourceStart);
SortElement[] currentElementChildren = this.currentElement.children;
if (currentElementChildren != null) {
SortElement previousElement = this.currentElement.children[this.currentElement.children_count - 1];
if (previousElement.id == SortJavaElement.FIELD && ((SortFieldDeclaration) previousElement).declarationStart == fieldInfo.declarationStart) {
SortMultipleFieldDeclaration multipleFielDeclaration = new SortMultipleFieldDeclaration((SortFieldDeclaration) previousElement);
multipleFielDeclaration.addField(fieldDeclaration);
this.currentElement.children[this.currentElement.children_count - 1] = multipleFielDeclaration;
} else if (previousElement.id == SortJavaElement.MULTIPLE_FIELD && ((SortMultipleFieldDeclaration) previousElement).declarationStart == fieldInfo.declarationStart) {
((SortMultipleFieldDeclaration) previousElement).addField(fieldDeclaration);
} else {
this.currentElement.addChild(fieldDeclaration);
}
} else {
this.currentElement.addChild(fieldDeclaration);
}
push(fieldDeclaration);
}
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterInitializer(int, int)
*/
public void enterInitializer(int declarationStart, int modifiers) {
if ((this.currentElement.id & SortJavaElement.TYPE) != 0) {
SortInitializer initializer = new SortInitializer(declarationStart, modifiers);
this.currentElement.addChild(initializer);
push(initializer);
}
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterMethod(MethodInfo)
*/
public void enterMethod(MethodInfo methodInfo) {
if ((this.currentElement.id & SortJavaElement.TYPE) != 0) {
SortMethodDeclaration methodDeclaration = new SortMethodDeclaration(methodInfo.declarationStart, methodInfo.modifiers, methodInfo.name, methodInfo.parameterNames, methodInfo.parameterTypes, methodInfo.exceptionTypes, methodInfo.returnType);
this.currentElement.addChild(methodDeclaration);
push(methodDeclaration);
}
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#enterType(TypeInfo)
*/
public void enterType(TypeInfo typeInfo) {
SortType type = null;
switch (typeInfo.kind) {
case IGenericType.CLASS_DECL:
case IGenericType.ANNOTATION_TYPE_DECL: // TODO (olivier) might need a SortAnnotationTypeDeclaration
type = new SortClassDeclaration(typeInfo.declarationStart, typeInfo.modifiers, typeInfo.name, typeInfo.superclass, typeInfo.superinterfaces);
break;
case IGenericType.INTERFACE_DECL:
case IGenericType.ENUM_DECL: // TODO (olivier) might need a SortEnumDeclaration
type = new SortInterfaceDeclaration(typeInfo.declarationStart, typeInfo.modifiers, typeInfo.name, typeInfo.superinterfaces);
break;
}
this.currentElement.addChild(type);
push(type);
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitCompilationUnit(int)
*/
public void exitCompilationUnit(int declarationEnd) {
pop(declarationEnd);
sort();
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitConstructor(int)
*/
public void exitConstructor(int declarationEnd) {
pop(declarationEnd);
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitField(int, int, int)
*/
public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
int normalizedDeclarationSourceEnd = this.normalizeSourceEnd(declarationSourceEnd);
if (this.currentElement.id == SortJavaElement.FIELD) {
SortFieldDeclaration fieldDeclaration = (SortFieldDeclaration) this.currentElement;
fieldDeclaration.declarationSourceEnd = normalizedDeclarationSourceEnd;
}
pop(declarationEnd);
if (this.currentElement.children != null) {
SortElement element = this.currentElement.children[this.currentElement.children_count - 1];
switch(element.id) {
case SortJavaElement.MULTIPLE_FIELD :
SortMultipleFieldDeclaration multipleFielDeclaration = (SortMultipleFieldDeclaration) element;
multipleFielDeclaration.innerFields[multipleFielDeclaration.fieldCounter - 1].declarationSourceEnd = normalizedDeclarationSourceEnd;
multipleFielDeclaration.sourceEnd = normalizedDeclarationSourceEnd;
break;
case SortJavaElement.FIELD :
SortFieldDeclaration fieldDeclaration = (SortFieldDeclaration) element;
/*
* we will revert to the previous source end in case this field is
* part of a multiple field declaration
*/
fieldDeclaration.previousSourceEnd = fieldDeclaration.sourceEnd;
fieldDeclaration.sourceEnd = normalizedDeclarationSourceEnd;
}
}
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitInitializer(int)
*/
public void exitInitializer(int declarationEnd) {
pop(declarationEnd);
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitMethod(int, int, int)
*/
public void exitMethod(int declarationEnd, int defaultValueStart, int defaultValueEnd) {
pop(declarationEnd);
}
/**
* @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitType(int)
*/
public void exitType(int declarationEnd) {
pop(declarationEnd);
}
final int normalizeSourceStart(int position) {
if (position == 0) {
return 0;
}
int index = position - 1;
while(index >= 0 && Character.isWhitespace(this.source[index])) {
index--;
}
int originalLineNumber = searchLineNumber(this.lineEnds, position);
int newLineNumber = searchLineNumber(this.lineEnds, index);
if (originalLineNumber == newLineNumber) {
return index + 1;
} else {
return this.lineEnds[newLineNumber - 1] + 1;
}
}
final int normalizeSourceEnd(int position) {
int lineNumber = searchLineNumber(this.lineEnds, position);
if (lineNumber == 1) {
return position;
}
int normalizeSourceEnd = 0;
if (lineNumber - 1 >= this.lineEnds.length) {
normalizeSourceEnd = this.source.length - 1;
} else {
normalizeSourceEnd = this.lineEnds[lineNumber - 1];
}
int index = position + 1;
while (index < normalizeSourceEnd && Character.isWhitespace(this.source[index])) {
index++;
}
if (index == normalizeSourceEnd) {
return normalizeSourceEnd;
} else {
return position;
}
}
private void pop(int declarationEnd) {
this.currentElement.sourceEnd = normalizeSourceEnd(declarationEnd);
this.currentElement.closeCollections();
this.stack.pop();
if (!this.stack.isEmpty()) {
this.currentElement = (SortElement) this.stack.peek();
}
}
private void push(SortElement sortElement) {
this.currentElement = sortElement;
this.stack.push(sortElement);
}
}