/****************************************************************************** * Copyright (c) 2002 - 2014 IBM Corporation. * 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 *****************************************************************************/ /* * CRTData.java * * Created on 7. Juni 2005, 11:48 */ package com.ibm.wala.sourcepos; /** * This class represents an entry in the CharacterRangeTable. * * @see CRTFlags * @see CRTable * @author Siegfried Weber * @author Juergen Graf <juergen.graf@gmail.com> */ public final class CRTData { private static final String WARN_INVALID_PC_RANGE = "Error at CRT entry %1$s: the program counter start index (%2$s) must be greater or equal than the end index (%3$s)."; private static final String WARN_INVALID_START_LINE_NUMBER = "Error at CRT entry %1$s: the line number of the source start position must not be 0."; private static final String WARN_INVALID_START_COLUMN_NUMBER = "Error at CRT entry %1$s: the column number of the source start position not be 0."; private static final String WARN_INVALID_END_LINE_NUMBER = "Error at CRT entry %1$s: the line number of the source end position must not be 0."; private static final String WARN_INVALID_END_COLUMN_NUMBER = "Error at CRT entry %1$s: the column number of the source end position must not be 0."; private static final String WARN_END_BEFORE_START = "Error at CRT entry %1$s: the source end position (%3$s) is before the source start position (%2$s)."; private static final String WARN_START_UNDEFINED = "Error at CRT entry %1$s: the source start position is undefined."; private static final String WARN_END_UNDEFINED = "Error at CRT entry %1$s: the source end position is undefined."; /** start index in the code array of the code attribute */ private final int pc_start_index; /** end index in the code array of the code attribute */ private final int pc_end_index; /** positions in the source file */ private final Range source_positions; /** * flags * * @see CRTFlags */ private final CRTFlags flags; /** * Creates a new instance of CRTData. {@code source_start_position} and * {@code source_end_position} can be {@code 0} to show that a range in the * code array of the code attribute has no source positions. * * @param pc_start_index * start index in the code array of the code attribute as unsigned * short * @param pc_end_index * end index in the code array of the code attribute as unsigned * short * @param source_start_position * start position in the source file as unsigned int * @param source_end_position * end position in the source file as unsigned int * @param flags * flags defined in {@link CRTFlags} * @throws InvalidCRTDataException * if a parameter violates one of the following conditions: * <ul> * <li>{@code pc_start_index < pc_end_index}</li> * <li>{@code source_start_position} is a valid position.</li> * <li>{@code source_end_position} is a valid position.</li> * <li>{@code source_start_position <= source_end_position}</li> * <li>{@code source_start_position} and {@code source_end_position} * must be a valid range.</li> * <li>{@code flags} must contain valid flags.</li> * </ul> */ CRTData(short pc_start_index, short pc_end_index, int source_start_position, int source_end_position, short flags) throws InvalidCRTDataException { this.pc_start_index = pc_start_index & 0xFFFF; this.pc_end_index = pc_end_index & 0xFFFF; if (pc_start_index > pc_end_index) throw new InvalidCRTDataException(WARN_INVALID_PC_RANGE, this.pc_start_index, this.pc_end_index); Position source_start = null; try { source_start = new Position(source_start_position); } catch (InvalidPositionException e) { switch (e.getThisCause()) { case LINE_NUMBER_ZERO: throw new InvalidCRTDataException(WARN_INVALID_START_LINE_NUMBER); case COLUMN_NUMBER_ZERO: throw new InvalidCRTDataException(WARN_INVALID_START_COLUMN_NUMBER); default: assert false; } } Position source_end = null; try { source_end = new Position(source_end_position); } catch (InvalidPositionException e) { switch (e.getThisCause()) { case LINE_NUMBER_ZERO: throw new InvalidCRTDataException(WARN_INVALID_END_LINE_NUMBER); case COLUMN_NUMBER_ZERO: throw new InvalidCRTDataException(WARN_INVALID_END_COLUMN_NUMBER); default: assert false; } } Range range = null; try { range = new Range(source_start, source_end); } catch (InvalidRangeException e) { switch (e.getThisCause()) { case END_BEFORE_START: throw new InvalidCRTDataException(WARN_END_BEFORE_START, source_start.toString(), source_end.toString()); case START_UNDEFINED: throw new InvalidCRTDataException(WARN_START_UNDEFINED); case END_UNDEFINED: throw new InvalidCRTDataException(WARN_END_UNDEFINED); } } finally { this.source_positions = range; } this.flags = new CRTFlags(flags); } public final CRTFlags getFlags() { return this.flags; } /** * Tests whether the given index lies within the range of this data. * * @param pc * the index to test * @return whether the given index lies within the range of this data or not. */ public final boolean isInRange(int pc) { return pc_start_index <= pc && pc <= pc_end_index; } /** * Tests whether the given data is consistently with this data. To be * consistently with another data this data has to be equal or more precise. * Otherwise the datas are contradictory. * * @param d * the data to test with * @return whether the given data is consistently. */ public final boolean matches(CRTData d) { return d != null && (isMorePrecise(d) || d.isMorePrecise(this)); } /** * Tests whether this data is equal to or more precise than the given data. * This data is equal or more precise if the program counter range and the * source range lie within the range of the given data. If this data or the * parameter have no source positions, only program counter range decides. * * @param d * the data to test with * @return whether this data is equal to or more precise than the given one. */ public final boolean isMorePrecise(CRTData d) { return d != null && pc_start_index >= d.pc_start_index && pc_end_index <= d.pc_end_index && (source_positions.isWithin(d.source_positions) || hasNoPosition() || d.hasNoPosition()); } /** * Returns {@code true} if this data has no source position. * * @return {@code true} if this data has no source position. */ private boolean hasNoPosition() { return source_positions.isUndefined(); } /** * Returns the source positions. * * @return The returned array consists of four positions: the start line * number, the start column number, the end line number, the end * column number */ public final Range getSourceInfo() { return source_positions; } @Override public String toString() { return "(Range [pc]: " + pc_start_index + "-" + pc_end_index + ") => " + source_positions.toString(); } }