/* * Bytecode Analysis Framework * Copyright (C) 2008 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.umd.cs.findbugs.ba.obl; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import org.apache.bcel.Constants; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.Instruction; import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InvokeInstruction; import org.apache.bcel.generic.ReferenceType; import edu.umd.cs.findbugs.SystemProperties; /** * A cache for looking up the collection of ObligationPolicyDatabaseActions * associated with a given InstructionHandle. Avoids the need for repeated * (slow) lookups. * * @author David Hovemeyer */ public class InstructionActionCache { private static final boolean DEBUG_LOOKUP = SystemProperties.getBoolean("oa.debug.lookup"); private ObligationPolicyDatabase database; private Map<InstructionHandle, Collection<ObligationPolicyDatabaseAction>> actionCache; public InstructionActionCache(ObligationPolicyDatabase database) { this.database = database; this.actionCache = new HashMap<InstructionHandle, Collection<ObligationPolicyDatabaseAction>>(); } public Collection<ObligationPolicyDatabaseAction> getActions(InstructionHandle handle, ConstantPoolGen cpg) { Collection<ObligationPolicyDatabaseAction> actionList = actionCache.get(handle); if (actionList == null) { Instruction ins = handle.getInstruction(); actionList = Collections.emptyList(); if (ins instanceof InvokeInstruction) { InvokeInstruction inv = (InvokeInstruction) ins; String signature = inv.getSignature(cpg); if (signature.indexOf(';') >= -1) { actionList = new LinkedList<ObligationPolicyDatabaseAction>(); if (signature.substring(0, signature.indexOf(')')).indexOf("Ljava/io/Closeable;") >= 0) { actionList.add(ObligationPolicyDatabaseAction.CLEAR); } else { ReferenceType receiverType = inv.getReferenceType(cpg); String methodName = inv.getName(cpg); boolean isStatic = inv.getOpcode() == Constants.INVOKESTATIC; database.getActions(receiverType, methodName, signature, isStatic, actionList); if (actionList.isEmpty()) { actionList = Collections.emptyList(); } } if (DEBUG_LOOKUP && !actionList.isEmpty()) { System.out.println(" At " + handle + ": " + actionList); } } } actionCache.put(handle, actionList); } return actionList; } public boolean addsObligation(InstructionHandle handle, ConstantPoolGen cpg, Obligation obligation) { return hasAction(handle, cpg, obligation, ObligationPolicyDatabaseActionType.ADD); } public boolean deletesObligation(InstructionHandle handle, ConstantPoolGen cpg, Obligation obligation) { return hasAction(handle, cpg, obligation, ObligationPolicyDatabaseActionType.DEL); } private boolean hasAction(InstructionHandle handle, ConstantPoolGen cpg, Obligation obligation, ObligationPolicyDatabaseActionType actionType) { Collection<ObligationPolicyDatabaseAction> actionList = getActions(handle, cpg); for (ObligationPolicyDatabaseAction action : actionList) { if (action.getActionType() == actionType && action.getObligation().equals(obligation)) { return true; } } return false; } }