    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.verifier.statics;
    019
    020
    021import java.util.Hashtable;
    022
    023import org.apache.bcel.generic.Type;
    024import org.apache.bcel.verifier.exc.LocalVariableInfoInconsistentException;
    025
    026/**
    027 * A utility class holding the information about
    028 * the name and the type of a local variable in
    029 * a given slot (== index). This information
    030 * often changes in course of byte code offsets.
    031 *
    032 * @version $Id$
    033 */
    034public class LocalVariableInfo{
    035
    036    /** The types database. KEY: String representing the offset integer. */
    037    private final Hashtable<String, Type> types = new Hashtable<>();
    038    /** The names database. KEY: String representing the offset integer. */
    039    private final Hashtable<String, String> names = new Hashtable<>();
    040
    041    /**
    042     * Adds a name of a local variable and a certain slot to our 'names'
    043     * (Hashtable) database.
    044     */
    045    private void setName(final int offset, final String name) {
    046        names.put(Integer.toString(offset), name);
    047    }
    048    /**
    049     * Adds a type of a local variable and a certain slot to our 'types'
    050     * (Hashtable) database.
    051     */
    052    private void setType(final int offset, final Type t) {
    053        types.put(Integer.toString(offset), t);
    054    }
    055
    056    /**
    057     * Returns the type of the local variable that uses this local
    058     * variable slot at the given bytecode offset.
    059     * Care for legal bytecode offsets yourself, otherwise the return value
    060     * might be wrong.
    061     * May return 'null' if nothing is known about the type of this local
    062     * variable slot at the given bytecode offset.
    063     */
    064    public Type getType(final int offset) {
    065        return types.get(Integer.toString(offset));
    066    }
    067    /**
    068     * Returns the name of the local variable that uses this local
    069     * variable slot at the given bytecode offset.
    070     * Care for legal bytecode offsets yourself, otherwise the return value
    071     * might be wrong.
    072     * May return 'null' if nothing is known about the type of this local
    073     * variable slot at the given bytecode offset.
    074     */
    075    public String getName(final int offset) {
    076        return names.get(Integer.toString(offset));
    077    }
    078    /**
    079     * Adds some information about this local variable (slot).
    080     * @throws LocalVariableInfoInconsistentException if the new information conflicts
    081     *         with already gathered information.
    082     */
    083    public void add(final String name, final int startpc, final int length, final Type t) throws LocalVariableInfoInconsistentException{
    084        for (int i=startpc; i<=startpc+length; i++) { // incl/incl-notation!
    085            add(i,name,t);
    086        }
    087    }
    088
    089    /**
    090     * Adds information about name and type for a given offset.
    091     * @throws LocalVariableInfoInconsistentException if the new information conflicts
    092     *         with already gathered information.
    093     */
    094    private void add(final int offset, final String name, final Type t) throws LocalVariableInfoInconsistentException{
    095        if (getName(offset) != null) {
    096            if (! getName(offset).equals(name)) {
    097                throw new LocalVariableInfoInconsistentException("At bytecode offset '"+offset+
    098                    "' a local variable has two different names: '"+getName(offset)+"' and '"+name+"'.");
    099            }
    100        }
    101        if (getType(offset) != null) {
    102            if (! getType(offset).equals(t)) {
    103                throw new LocalVariableInfoInconsistentException("At bytecode offset '"+offset+
    104                    "' a local variable has two different types: '"+getType(offset)+"' and '"+t+"'.");
    105            }
    106        }
    107        setName(offset, name);
    108        setType(offset, t);
    109    }
    110}