📄 classcontext.java
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2003,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;import java.util.*;import org.apache.bcel.Constants;import org.apache.bcel.classfile.Code;import org.apache.bcel.classfile.JavaClass;import org.apache.bcel.classfile.Method;import org.apache.bcel.generic.ClassGen;import org.apache.bcel.generic.ConstantPoolGen;import org.apache.bcel.generic.FieldInstruction;import org.apache.bcel.generic.Instruction;import org.apache.bcel.generic.InstructionHandle;import org.apache.bcel.generic.InstructionList;import org.apache.bcel.generic.INVOKESTATIC;import org.apache.bcel.generic.MethodGen;/** * 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 implements AnalysisFeatures { /** * We only do pruning of infeasible exception edges * if the <code>WORK_HARD</code> analysis feature * is enabled. */ public static final boolean PRUNE_INFEASIBLE_EXCEPTION_EDGES = WORK_HARD; /** * Only try to determine unconditional exception throwers * if we're not trying to conserve space. */ public static final boolean PRUNE_UNCONDITIONAL_EXCEPTION_THROWER_EDGES = !CONSERVE_SPACE; public static final boolean DEBUG = Boolean.getBoolean("classContext.debug"); private static final int PRUNED_INFEASIBLE_EXCEPTIONS = 1; private static final int PRUNED_UNCONDITIONAL_THROWERS = 2; private static final boolean TIME_ANALYSES = Boolean.getBoolean("classContext.timeAnalyses"); private static final boolean DEBUG_CFG = Boolean.getBoolean("classContext.debugCFG"); /* ---------------------------------------------------------------------- * Helper classes * ---------------------------------------------------------------------- */ 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(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, ClassContext.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; } /** * 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 */ 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 = null; try { analysis = analyze(method); result.setAnalysis(analysis); } catch (CFGBuilderException e) { result.setCFGBuilderException(e); } catch (DataflowAnalysisException e) { if (TIME_ANALYSES) { long end = System.currentTimeMillis(); indent(); System.out.println("CC: " + analysisName + " killed by exception after " + (end - begin) + " millis"); e.printStackTrace(); --depth; } 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(); } protected abstract Analysis analyze(Method method) throws CFGBuilderException, DataflowAnalysisException; } private abstract class NoExceptionAnalysisFactory <AnalysisResult> extends AnalysisFactory<AnalysisResult> { public NoExceptionAnalysisFactory(String analysisName) { super(analysisName); } public AnalysisResult 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"); } } } private abstract class NoDataflowAnalysisFactory <AnalysisResult> extends AnalysisFactory<AnalysisResult> { public NoDataflowAnalysisFactory(String analysisName) { super(analysisName); } public AnalysisResult getAnalysis(Method method) throws CFGBuilderException { try { return super.getAnalysis(method); } catch (DataflowAnalysisException e) { throw new IllegalStateException("Should not happen"); } } } private static final Set<String> busyCFGSet = new HashSet<String>(); private class CFGFactory extends AnalysisFactory<CFG> { public CFGFactory() { super("CFG construction"); } 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); } public CFG getRefinedCFG(Method method) throws CFGBuilderException { MethodGen methodGen = getMethodGen(method); CFG cfg = getRawCFG(method); // HACK: // Due to recursive method invocations, we may get a recursive // request for the pruned CFG of a method. In this case, // we just return the raw CFG. String methodId = methodGen.getClassName() + "." + methodGen.getName() + ":" + methodGen.getSignature(); if (DEBUG_CFG) { indent(); System.out.println("CC: getting refined CFG for " + methodId); } if (DEBUG) System.out.println("ClassContext: request to prune " + methodId); if (!busyCFGSet.add(methodId)) return cfg; if (PRUNE_INFEASIBLE_EXCEPTION_EDGES && !cfg.isFlagSet(PRUNED_INFEASIBLE_EXCEPTIONS)) { try { TypeDataflow typeDataflow = getTypeDataflow(method); new PruneInfeasibleExceptionEdges(cfg, getMethodGen(method), typeDataflow).execute(); } catch (DataflowAnalysisException e) { // FIXME: should report the error } catch (ClassNotFoundException e) { getLookupFailureCallback().reportMissingClass(e); } } cfg.setFlags(cfg.getFlags() | PRUNED_INFEASIBLE_EXCEPTIONS); if (PRUNE_UNCONDITIONAL_EXCEPTION_THROWER_EDGES && !cfg.isFlagSet(PRUNED_UNCONDITIONAL_THROWERS)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -