/******************************************************************************* * Copyright (c) 2000, 2009 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.internal.compiler.parser.diagnose; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; 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(this.pos >= this.intervalStarts.length) { System.arraycopy(this.intervalStarts, 0, this.intervalStarts = new int[this.pos * 2], 0, this.pos); System.arraycopy(this.intervalEnds, 0, this.intervalEnds = new int[this.pos * 2], 0, this.pos); System.arraycopy(this.intervalFlags, 0, this.intervalFlags = new int[this.pos * 2], 0, this.pos); } this.intervalStarts[this.pos] = start; this.intervalEnds[this.pos] = end; this.intervalFlags[this.pos] = flags; this.pos++; } int[][] getRanges() { int[] resultStarts = new int[this.pos]; int[] resultEnds = new int[this.pos]; int[] resultFlags = new int[this.pos]; System.arraycopy(this.intervalStarts, 0, resultStarts, 0, this.pos); System.arraycopy(this.intervalEnds, 0, resultEnds, 0, this.pos); System.arraycopy(this.intervalFlags, 0, resultFlags, 0, this.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 - left) / 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.bits |= ASTNode.ErrorInSignature; 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.declarationSourceStart != initializer.declarationSourceEnd){ initializer.bits |= ASTNode.ErrorInSignature; result.addInterval(initializer.declarationSourceStart, initializer.declarationSourceEnd, IGNORE); } else { result.addInterval(initializer.bodyStart, initializer.bodyEnd); } } } } } } public static boolean containsIgnoredBody(AbstractMethodDeclaration method){ return !method.isDefaultConstructor() && !method.isClinit() && (method.modifiers & ExtraCompilerModifiers.AccSemicolonBody) == 0; } }