📄 classcontext.java
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2003-2005 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;import java.util.ArrayList;import java.util.Arrays;import java.util.BitSet;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.TreeSet;import org.apache.bcel.Constants;import org.apache.bcel.classfile.Code;import org.apache.bcel.classfile.JavaClass;import org.apache.bcel.classfile.LineNumber;import org.apache.bcel.classfile.LineNumberTable;import org.apache.bcel.classfile.Method;import org.apache.bcel.generic.ClassGen;import org.apache.bcel.generic.ClassGenException;import org.apache.bcel.generic.ConstantPoolGen;import org.apache.bcel.generic.FieldInstruction;import org.apache.bcel.generic.GETSTATIC;import org.apache.bcel.generic.IFNE;import org.apache.bcel.generic.INVOKESTATIC;import org.apache.bcel.generic.Instruction;import org.apache.bcel.generic.InstructionHandle;import org.apache.bcel.generic.InstructionList;import org.apache.bcel.generic.InvokeInstruction;import org.apache.bcel.generic.MethodGen;import edu.umd.cs.findbugs.SystemProperties;import edu.umd.cs.findbugs.TigerSubstitutes;import edu.umd.cs.findbugs.annotations.CheckForNull;import edu.umd.cs.findbugs.annotations.NonNull;import edu.umd.cs.findbugs.annotations.Nullable;import edu.umd.cs.findbugs.ba.ca.CallListAnalysis;import edu.umd.cs.findbugs.ba.ca.CallListDataflow;import edu.umd.cs.findbugs.ba.constant.ConstantAnalysis;import edu.umd.cs.findbugs.ba.constant.ConstantDataflow;import edu.umd.cs.findbugs.ba.deref.UnconditionalValueDerefAnalysis;import edu.umd.cs.findbugs.ba.deref.UnconditionalValueDerefDataflow;import edu.umd.cs.findbugs.ba.deref.UnconditionalValueDerefSet;import edu.umd.cs.findbugs.ba.heap.LoadAnalysis;import edu.umd.cs.findbugs.ba.heap.LoadDataflow;import edu.umd.cs.findbugs.ba.heap.StoreAnalysis;import edu.umd.cs.findbugs.ba.heap.StoreDataflow;import edu.umd.cs.findbugs.ba.npe.DerefFinder;import edu.umd.cs.findbugs.ba.npe.IsNullValueAnalysis;import edu.umd.cs.findbugs.ba.npe.IsNullValueDataflow;import edu.umd.cs.findbugs.ba.npe.ReturnPathTypeAnalysis;import edu.umd.cs.findbugs.ba.npe.ReturnPathTypeDataflow;import edu.umd.cs.findbugs.ba.npe.UsagesRequiringNonNullValues;import edu.umd.cs.findbugs.ba.npe2.DefinitelyNullSetAnalysis;import edu.umd.cs.findbugs.ba.npe2.DefinitelyNullSetDataflow;import edu.umd.cs.findbugs.ba.type.ExceptionSetFactory;import edu.umd.cs.findbugs.ba.type.TypeAnalysis;import edu.umd.cs.findbugs.ba.type.TypeDataflow;import edu.umd.cs.findbugs.ba.vna.LoadedFieldSet;import edu.umd.cs.findbugs.ba.vna.MergeTree;import edu.umd.cs.findbugs.ba.vna.ValueNumberAnalysis;import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;import edu.umd.cs.findbugs.util.MapCache;import edu.umd.cs.findbugs.util.TopologicalSort;import edu.umd.cs.findbugs.util.TopologicalSort.OutEdges;/** * A ClassContext caches all of the auxiliary objects used to analyze * the methods of a class. That way, these objects don't need to * be created over and over again. * * @author David Hovemeyer */public class ClassContext { public static final boolean DEBUG = SystemProperties.getBoolean("classContext.debug"); private static final int PRUNED_INFEASIBLE_EXCEPTIONS = 1; private static final int PRUNED_UNCONDITIONAL_THROWERS = 2; private static final int REFINED = 4; private static final boolean TIME_ANALYSES = SystemProperties.getBoolean("classContext.timeAnalyses"); private static final boolean DEBUG_CFG = SystemProperties.getBoolean("classContext.debugCFG"); private static final boolean DUMP_DATAFLOW_ANALYSIS = SystemProperties.getBoolean("dataflow.dump"); /* ---------------------------------------------------------------------- * Helper classes * ---------------------------------------------------------------------- */ /** * Unpacked code for a method. * Contains set of all opcodes in the method, as well as a map * of bytecode offsets to opcodes. */ private static class UnpackedCode { private BitSet bytecodeSet; private short[] offsetToBytecodeMap; public UnpackedCode(BitSet bytecodeSet, short[] offsetToBytecodeMap) { this.bytecodeSet = bytecodeSet; this.offsetToBytecodeMap = offsetToBytecodeMap; } /** * @return Returns the bytecodeSet. */ public BitSet getBytecodeSet() { return bytecodeSet; } /** * @return Returns the offsetToBytecodeMap. */ public short[] getOffsetToBytecodeMap() { return offsetToBytecodeMap; } } private static int depth; private static void indent() { for (int i = 0; i < depth; ++i) System.out.print(" "); } /** * An AnalysisResult stores the result of requesting an analysis * from an AnalysisFactory. It can represent a successful outcome * (where the Analysis object can be returned), or an unsuccessful * outcome (where an exception was thrown trying to create the * analysis). For unsuccessful outcomes, we rethrow the original * exception rather than making another attempt to create the analysis * (since if it fails once, it will never succeed). */ private static class AnalysisResult<Analysis> { private boolean analysisSetExplicitly; private Analysis analysis; private AnalysisException analysisException; private CFGBuilderException cfgBuilderException; private DataflowAnalysisException dataflowAnalysisException; public Analysis getAnalysis() throws CFGBuilderException, DataflowAnalysisException { if (analysisSetExplicitly) return analysis; if (dataflowAnalysisException != null) throw dataflowAnalysisException; if (analysisException != null) throw analysisException; if (cfgBuilderException != null) throw cfgBuilderException; throw new IllegalStateException(); } /** * Record a successful outcome, where the analysis was created. * * @param analysis the Analysis */ public void setAnalysis(@Nullable Analysis analysis) { this.analysisSetExplicitly = true; this.analysis = analysis; } /** * Record that an AnalysisException occurred while attempting * to create the Analysis. * * @param analysisException the AnalysisException */ public void setAnalysisException(AnalysisException analysisException) { this.analysisException = analysisException; } /** * Record that a CFGBuilderException occurred while attempting * to create the Analysis. * * @param cfgBuilderException the CFGBuilderException */ public void setCFGBuilderException(CFGBuilderException cfgBuilderException) { this.cfgBuilderException = cfgBuilderException; } /** * Record that a DataflowAnalysisException occurred while attempting * to create the Analysis. * * @param dataflowException the DataflowAnalysisException */ public void setDataflowAnalysisException(DataflowAnalysisException dataflowException) { this.dataflowAnalysisException = dataflowException; } } /** * Abstract factory class for creating analysis objects. * Handles caching of analysis results for a method. */ private abstract class AnalysisFactory <Analysis> { private String analysisName; private HashMap<Method, AnalysisResult<Analysis>> map = new HashMap<Method, ClassContext.AnalysisResult<Analysis>>(); /** * Constructor. * * @param analysisName name of the analysis factory: for diagnostics/debugging */ public AnalysisFactory(String analysisName) { this.analysisName = analysisName; analysisFactoryList.add(this); } /** * Get the Analysis for given method. * If Analysis has already been performed, the cached result is * returned. * * @param method the method to analyze * @return the Analysis object representing the result of analyzing the method * @throws CFGBuilderException if the CFG can't be constructed for the method * @throws DataflowAnalysisException if dataflow analysis fails on the method */ @CheckForNull public Analysis getAnalysis(Method method) throws CFGBuilderException, DataflowAnalysisException { AnalysisResult<Analysis> result = map.get(method); if (result == null) { if (TIME_ANALYSES) { ++depth; indent(); System.out.println("CC: Starting " + analysisName + " for " + SignatureConverter.convertMethodSignature(jclass, method) + ":"); } long begin = System.currentTimeMillis(); // Create a new AnalysisResult result = new AnalysisResult<Analysis>(); // Attempt to create the Analysis and store it in the AnalysisResult. // If an exception occurs, record it in the AnalysisResult. Analysis analysis; try { analysis = analyze(method); result.setAnalysis(analysis); } catch (CFGBuilderException e) { result.setCFGBuilderException(e); } catch (DataflowAnalysisException e) { result.setDataflowAnalysisException(e); } catch (AnalysisException e) { result.setAnalysisException(e); } if (TIME_ANALYSES) { long end = System.currentTimeMillis(); indent(); System.out.println("CC: finished " + analysisName + " in " + (end - begin) + " millis"); --depth; } // Cache the outcome of this analysis attempt. map.put(method, result); } return result.getAnalysis(); } @CheckForNull protected abstract Analysis analyze(Method method) throws CFGBuilderException, DataflowAnalysisException; /** * @return true if this analysis factory is a dataflow analysis, * false if not */ public abstract boolean isDataflow(); /** * Purge result for given method. * * @param method the method whose analysis result should purged */ public void purge(Method method) { map.remove(method); } } private abstract class NoExceptionAnalysisFactory <Analysis> extends AnalysisFactory<Analysis> { public NoExceptionAnalysisFactory(String analysisName) { super(analysisName); } @Override public Analysis getAnalysis(Method method) { try { return super.getAnalysis(method); } catch (DataflowAnalysisException e) { throw new IllegalStateException("Should not happen"); } catch (CFGBuilderException e) { throw new IllegalStateException("Should not happen"); } } /* (non-Javadoc) * @see edu.umd.cs.findbugs.ba.ClassContext.AnalysisFactory#isDataflow() */ @Override public boolean isDataflow() { return false; } } private abstract class NoDataflowAnalysisFactory <Analysis> extends AnalysisFactory<Analysis> { public NoDataflowAnalysisFactory(String analysisName) { super(analysisName); } @Override public Analysis getAnalysis(Method method) throws CFGBuilderException { try { return super.getAnalysis(method); } catch (DataflowAnalysisException e) { throw new IllegalStateException("Should not happen"); } } /* (non-Javadoc) * @see edu.umd.cs.findbugs.ba.ClassContext.AnalysisFactory#isDataflow() */ @Override public boolean isDataflow() { return false; } } private final Set<String> busyCFGSet = new HashSet<String>(); private class CFGFactory extends AnalysisFactory<CFG> { public CFGFactory() { super("CFG construction"); } @Override public CFG getAnalysis(Method method) throws CFGBuilderException { try { return super.getAnalysis(method); } catch (DataflowAnalysisException e) { throw new IllegalStateException("Should not happen"); } } public CFG getRawCFG(Method method) throws CFGBuilderException { return getAnalysis(method); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -