/******************************************************************************
* 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
*****************************************************************************/
/*
* MethodPositions.java
*
* Created on 23. Mai 2005, 14:49
*/
package com.ibm.wala.sourcepos;
import java.io.DataInputStream;
import java.io.IOException;
/**
* This class represents the MethodPositions attribute.
*
* @author Siegfried Weber
* @author Juergen Graf <juergen.graf@gmail.com>
*/
public final class MethodPositions extends PositionsAttribute {
/** Stores the attribute name of this attribute */
public static final String ATTRIBUTE_NAME = "joana.sourceinfo.MethodPositions";
private static final String ERR_COLUMN_ZERO = "Error in MethodPositions attribute: Invalid column number in %1$s.";
private static final String ERR_LINE_ZERO = "Error in MethodPositions attribute: Invalid line number in %1$s.";
private static final String ERR_RANGE_UNDEFINED = "Error in MethodPositions attribute: %1$s and %2$s are undefined.";
private static final String ERR_SET_RANGE_UNDEFINED = "Error in MethodPositions attribute: Invalid positions, so %1$s and %2$s are set undefined.";
private static final String ERR_POSITION_UNDEFINED = "Error in MethodPositions attribute: %1$s is undefined.";
private static final String ERR_END_BEFORE_START = "Error in MethodPositions attribute: %2$s (%4$s) is before %1$s (%3$s).";
private static final String WARN_INVALID_BLOCK_END = "Warning in MethodPositions attribute: Invalid method block end position.";
private static final String WARN_PARAMETER_NOT_IN_DECLARATION = "Warning in MethodPositions attribute: Parameter not in the declaration range.";
/** positions of the method declaration */
private Range declaration;
/** positions of the method parameters */
private Range parameter;
/** positions of the method block */
private Range block_end;
/**
* Creates a new instance of MethodPositions
*
* @param data
* the byte array containing the attribute
* @throws IOException
* if the attribute can't be read.
*/
public MethodPositions(byte[] data) throws IOException {
super(data);
if (Debug.PRINT_CHARACTER_RANGE_TABLE) {
Debug.info("MethodPositions found: ");
Debug.info(toString());
}
}
@Override
protected final void readData(DataInputStream in) throws IOException {
declaration = readRange(in, "declaration_start", "declaration_end", false);
parameter = readRange(in, "parameter_start", "parameter_end", true);
block_end = readRange(in, "block_end_start", "block_end_end", false);
if (!parameter.isUndefined()
&& (!declaration.getStartPosition().isBefore(parameter.getStartPosition()) || !parameter.getEndPosition().isBefore(
declaration.getEndPosition())))
Debug.warn(WARN_PARAMETER_NOT_IN_DECLARATION);
if (!declaration.getEndPosition().isBefore(block_end.getStartPosition()))
Debug.warn(WARN_INVALID_BLOCK_END);
}
/**
* Reads a range from the input stream.
*
* @param in
* the input stream
* @param startVarName
* the variable name for the start position
* @param endVarName
* the variable name for the end position
* @param undefinedAllowed
* {@code true} if the range may be undefined.
* @return the range
* @throws IOException
* if the input stream cannot be read
*/
private Range readRange(DataInputStream in, String startVarName, String endVarName, boolean undefinedAllowed) throws IOException {
boolean valid = true;
Range range = null;
Position start = null;
Position end = null;
try {
start = readPosition(in, startVarName);
} catch (InvalidPositionException e) {
valid = false;
}
try {
end = readPosition(in, endVarName);
} catch (InvalidPositionException e) {
valid = false;
}
if (valid) {
try {
range = new Range(start, end);
} catch (InvalidRangeException e) {
switch (e.getThisCause()) {
case END_BEFORE_START:
Debug.warn(ERR_END_BEFORE_START, startVarName, endVarName, start, end);
case START_UNDEFINED:
Debug.warn(ERR_POSITION_UNDEFINED, startVarName);
case END_UNDEFINED:
Debug.warn(ERR_POSITION_UNDEFINED, endVarName);
}
}
}
if (range == null) {
range = new Range();
Debug.warn(ERR_SET_RANGE_UNDEFINED, startVarName, endVarName);
}
if (range.isUndefined() && !undefinedAllowed) {
Debug.warn(ERR_RANGE_UNDEFINED, startVarName, endVarName);
}
return range;
}
/**
* Reads a position from the input stream.
*
* @param in
* the input stream
* @param varName
* the variable name for this position
* @throws IOException
* if the input stream cannot be read
* @throws InvalidPositionException
* if the read position is invalid
*/
private Position readPosition(DataInputStream in, String varName) throws IOException, InvalidPositionException {
Position pos = null;
try {
pos = new Position(in.readInt());
} catch (InvalidPositionException e) {
switch (e.getThisCause()) {
case LINE_NUMBER_ZERO:
Debug.warn(ERR_LINE_ZERO, varName);
throw e;
case COLUMN_NUMBER_ZERO:
Debug.warn(ERR_COLUMN_ZERO, varName);
throw e;
default:
assert false;
}
}
return pos;
}
/**
* Returns the source position range of the method declaration.
*
* @return the source position range of the method declaration
*/
public final Range getHeaderInfo() {
return declaration;
}
/**
* Returns the source position range of the method parameter declaration.
*
* @return the source position range of the method parameter declaration
*/
public final Range getMethodInfo() {
return parameter;
}
/**
* Returns the source position range of the end of the method block.
*
* @return the source position range of the end of the method block
*/
public final Range getFooterInfo() {
return block_end;
}
@Override
public String toString() {
return "header: " + declaration + " params: " + parameter + " footer:" + block_end;
}
}