/******************************************************************************
* 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();
}
}