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