/* * Bytecode Analysis Framework * Copyright (C) 2004, 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.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.annotation.CheckForNull; import org.apache.bcel.generic.ObjectType; import org.apache.bcel.generic.Type; import edu.umd.cs.findbugs.annotations.SuppressWarnings; import edu.umd.cs.findbugs.ba.Hierarchy; import edu.umd.cs.findbugs.ba.XMethod; import edu.umd.cs.findbugs.bcel.BCELUtil; import edu.umd.cs.findbugs.classfile.ClassDescriptor; import edu.umd.cs.findbugs.classfile.Global; import edu.umd.cs.findbugs.internalAnnotations.DottedClassName; /** * Factory for Obligation and ObligationSet objects to be used in an instance of * ObligationAnalysis. */ public class ObligationFactory { private Map<String, Obligation> classNameToObligationMap; private Set<String> slashedClassNames = new HashSet<String>(); // // XXX: this is just for debugging. // static ObligationFactory lastInstance; @SuppressWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") public ObligationFactory() { this.classNameToObligationMap = new HashMap<String, Obligation>(); // lastInstance = this; } public int getMaxObligationTypes() { return classNameToObligationMap.size(); } public boolean signatureInvolvesObligations(String sig) { for (String c : slashedClassNames) if (sig.indexOf(c) >= 0) return true; return false; } /** * Determine whether class named by given ClassDescriptor is an Obligation * type. * * @param classDescriptor * a class * @return true if the class is an Obligation type, false otherwise */ public boolean isObligationType(ClassDescriptor classDescriptor) { try { return getObligationByType(BCELUtil.getObjectTypeInstance(classDescriptor.toDottedClassName())) != null; } catch (ClassNotFoundException e) { Global.getAnalysisCache().getErrorLogger().reportMissingClass(e); return false; } } /** * Get an Iterator over known Obligation types. * * @return Iterator over known Obligation types */ public Iterator<Obligation> obligationIterator() { return classNameToObligationMap.values().iterator(); } /** * Look up an Obligation by type. This returns the first Obligation that is * a supertype of the type given (meaning that the given type could be an * instance of the returned Obligation). * * @param type * a type * @return an Obligation that is a supertype of the given type, or null if * there is no such Obligation * @throws ClassNotFoundException */ public @CheckForNull Obligation getObligationByType(ObjectType type) throws ClassNotFoundException { for (Iterator<Obligation> i = obligationIterator(); i.hasNext();) { Obligation obligation = i.next(); if (Hierarchy.isSubtype(type, obligation.getType())) return obligation; } return null; } /** * Look up an Obligation by type. This returns the first Obligation that is * a supertype of the type given (meaning that the given type could be an * instance of the returned Obligation). * * @param classDescriptor * a ClassDescriptor naming a class type * @return an Obligation that is a supertype of the given type, or null if * there is no such Obligation * @throws ClassNotFoundException */ public @CheckForNull Obligation getObligationByType(ClassDescriptor classDescriptor) { try { return getObligationByType(BCELUtil.getObjectTypeInstance(classDescriptor.toDottedClassName())); } catch (ClassNotFoundException e) { Global.getAnalysisCache().getErrorLogger().reportMissingClass(e); return null; } } /** * Get array of Obligation types corresponding to the parameters of the * given method. * * @param xmethod * a method * @return array of Obligation types for each of the method's parameters; a * null element means the corresponding parameter is not an * Obligation type */ public Obligation[] getParameterObligationTypes(XMethod xmethod) { Type[] paramTypes = Type.getArgumentTypes(xmethod.getSignature()); Obligation[] result = new Obligation[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) { if (!(paramTypes[i] instanceof ObjectType)) { continue; } try { result[i] = getObligationByType((ObjectType) paramTypes[i]); } catch (ClassNotFoundException e) { Global.getAnalysisCache().getErrorLogger().reportMissingClass(e); } } return result; } public Obligation addObligation(@DottedClassName String className) { int nextId = classNameToObligationMap.size(); slashedClassNames.add(className.replace('.', '/')); Obligation obligation = new Obligation(className, nextId); if (classNameToObligationMap.put(className, obligation) != null) { throw new IllegalStateException("Obligation " + className + " added multiple times"); } return obligation; } public Obligation getObligationById(int id) { for (Obligation obligation : classNameToObligationMap.values()) { if (obligation.getId() == id) return obligation; } return null; } public Obligation getObligationByName(@DottedClassName String className) { return classNameToObligationMap.get(className); } public ObligationSet createObligationSet() { return new ObligationSet(/* getMaxObligationTypes(), */this); } } // vim:ts=4