/******************************************************************************* | |
* 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.wst.jsdt.internal.compiler.parser.diagnose; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractMethodDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.FieldDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.Initializer; | |
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration; | |
import org.eclipse.wst.jsdt.internal.compiler.lookup.CompilerModifiers; | |
public class RangeUtil { | |
// flags | |
public static final int NO_FLAG = 0; | |
public static final int LBRACE_MISSING = 1; | |
public static final int IGNORE = 2; | |
static class RangeResult { | |
private static final int INITIAL_SIZE = 10; | |
int pos; | |
int[] intervalStarts; | |
int[] intervalEnds; | |
int[] intervalFlags; | |
RangeResult() { | |
this.pos = 0; | |
this.intervalStarts = new int[INITIAL_SIZE]; | |
this.intervalEnds = new int[INITIAL_SIZE]; | |
this.intervalFlags = new int[INITIAL_SIZE]; | |
} | |
void addInterval(int start, int end){ | |
addInterval(start, end, NO_FLAG); | |
} | |
void addInterval(int start, int end, int flags){ | |
if(pos >= intervalStarts.length) { | |
System.arraycopy(intervalStarts, 0, intervalStarts = new int[pos * 2], 0, pos); | |
System.arraycopy(intervalEnds, 0, intervalEnds = new int[pos * 2], 0, pos); | |
System.arraycopy(intervalFlags, 0, intervalFlags = new int[pos * 2], 0, pos); | |
} | |
intervalStarts[pos] = start; | |
intervalEnds[pos] = end; | |
intervalFlags[pos] = flags; | |
pos++; | |
} | |
int[][] getRanges() { | |
int[] resultStarts = new int[pos]; | |
int[] resultEnds = new int[pos]; | |
int[] resultFlags = new int[pos]; | |
System.arraycopy(intervalStarts, 0, resultStarts, 0, pos); | |
System.arraycopy(intervalEnds, 0, resultEnds, 0, pos); | |
System.arraycopy(intervalFlags, 0, resultFlags, 0, pos); | |
if (resultStarts.length > 1) { | |
quickSort(resultStarts, resultEnds, resultFlags, 0, resultStarts.length - 1); | |
} | |
return new int[][]{resultStarts, resultEnds, resultFlags}; | |
} | |
private void quickSort(int[] list, int[] list2, int[] list3, int left, int right) { | |
int original_left= left; | |
int original_right= right; | |
int mid= list[(left + right) / 2]; | |
do { | |
while (compare(list[left], mid) < 0) { | |
left++; | |
} | |
while (compare(mid, list[right]) < 0) { | |
right--; | |
} | |
if (left <= right) { | |
int tmp= list[left]; | |
list[left]= list[right]; | |
list[right]= tmp; | |
tmp = list2[left]; | |
list2[left]= list2[right]; | |
list2[right]= tmp; | |
tmp = list3[left]; | |
list3[left]= list3[right]; | |
list3[right]= tmp; | |
left++; | |
right--; | |
} | |
} while (left <= right); | |
if (original_left < right) { | |
quickSort(list, list2, list3, original_left, right); | |
} | |
if (left < original_right) { | |
quickSort(list, list2, list3, left, original_right); | |
} | |
} | |
private int compare(int i1, int i2) { | |
return i1 - i2; | |
} | |
} | |
public static boolean containsErrorInSignature(AbstractMethodDeclaration method){ | |
return method.sourceEnd + 1 == method.bodyStart || method.bodyEnd == method.declarationSourceEnd; | |
} | |
public static int[][] computeDietRange(TypeDeclaration[] types) { | |
if(types == null || types.length == 0) { | |
return new int[3][0]; | |
} else { | |
RangeResult result = new RangeResult(); | |
computeDietRange0(types, result); | |
return result.getRanges(); | |
} | |
} | |
private static void computeDietRange0(TypeDeclaration[] types, RangeResult result) { | |
for (int j = 0; j < types.length; j++) { | |
//members | |
TypeDeclaration[] memberTypeDeclarations = types[j].memberTypes; | |
if(memberTypeDeclarations != null && memberTypeDeclarations.length > 0) { | |
computeDietRange0(types[j].memberTypes, result); | |
} | |
//methods | |
AbstractMethodDeclaration[] methods = types[j].methods; | |
if (methods != null) { | |
int length = methods.length; | |
for (int i = 0; i < length; i++) { | |
AbstractMethodDeclaration method = methods[i]; | |
if(containsIgnoredBody(method)) { | |
if(containsErrorInSignature(method)) { | |
method.errorInSignature = true; | |
result.addInterval(method.declarationSourceStart, method.declarationSourceEnd, IGNORE); | |
} else { | |
int flags = method.sourceEnd + 1 == method.bodyStart ? LBRACE_MISSING : NO_FLAG; | |
result.addInterval(method.bodyStart, method.bodyEnd, flags); | |
} | |
} | |
} | |
} | |
//initializers | |
FieldDeclaration[] fields = types[j].fields; | |
if (fields != null) { | |
int length = fields.length; | |
for (int i = 0; i < length; i++) { | |
if (fields[i] instanceof Initializer) { | |
Initializer initializer = (Initializer)fields[i]; | |
if(initializer.declarationSourceEnd == initializer.bodyEnd){ | |
initializer.errorInSignature = true; | |
result.addInterval(initializer.declarationSourceStart, initializer.declarationSourceEnd, IGNORE); | |
} else { | |
result.addInterval(initializer.bodyStart, initializer.bodyEnd); | |
} | |
} | |
} | |
} | |
} | |
} | |
public static boolean isInInterval(int start, int end, int[] intervalStart, int[] intervalEnd) { | |
int length = intervalStart.length; | |
for (int i = 0; i < length; i++) { | |
if(intervalStart[i] <= start && intervalEnd[i] >= end) { | |
return true; | |
} else if(intervalStart[i] > end) { | |
return false; | |
} | |
} | |
return false; | |
} | |
public static int getPreviousInterval(int start, int end, int[] intervalStart, int[] intervalEnd) { | |
int length = intervalStart.length; | |
for (int i = 0; i < length; i++) { | |
if(intervalStart[i] > end) { | |
return i - 1; | |
} | |
} | |
return length - 1; | |
} | |
public static boolean containsIgnoredBody(AbstractMethodDeclaration method){ | |
return !method.isDefaultConstructor() | |
&& !method.isClinit() | |
&& (method.modifiers & CompilerModifiers.AccSemicolonBody) == 0; | |
} | |
} |