<commit_before>/*
 * 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 <NAME>
 */
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("  ");
	}

	private abstract class AnalysisFactory <AnalysisResult> {
		private String analysisName;
		private IdentityHashMap<Method, AnalysisResult> map = new IdentityHashMap<Method, AnalysisResult>();

		public AnalysisFactory(String analysisName) {
			this.analysisName = analysisName;
		}

		public AnalysisResult getAnalysis(Method method) throws CFGBuilderException, DataflowAnalysisException {
			AnalysisResult 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();

				try {
					result = analyze(method);
				} 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;
					}
					throw e;
				}

				if (TIME_ANALYSES) {
					long end = System.currentTimeMillis();
					indent();
					System.out.println("CC: finished " + analysisName + " in " + (end - begin) + " millis");
					--depth;
				}

				map.put(method, result);
			}
			return result;
		}

		protected abstract AnalysisResult 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)) {
				try {
					new PruneUnconditionalExceptionThrowerEdges(methodGen, cfg, getConstantPoolGen(), analysisContext).execute();
				} catch (DataflowAnalysisException e) {
					// FIXME: should report the error
				}
			}
			cfg.setFlags(cfg.getFlags() | PRUNED_UNCONDITIONAL_THROWERS);

			busyCFGSet.remove(methodId);

			return cfg;
		}

		protected CFG analyze(Method method) throws CFGBuilderException {
			MethodGen methodGen = getMethodGen(method);
			CFGBuilder cfgBuilder = CFGBuilderFactory.create(methodGen);
			cfgBuilder.build();
			return cfgBuilder.getCFG();
		}
	}

	/* ----------------------------------------------------------------------
	 * Fields
	 * ---------------------------------------------------------------------- */

	private JavaClass jclass;
	private AnalysisContext analysisContext;

	private NoExceptionAnalysisFactory<MethodGen> methodGenFactory =
	        new NoExceptionAnalysisFactory<MethodGen>("MethodGen construction") {
		        protected MethodGen analyze(Method method) {
			        if (method.getCode() == null)
				        return null;
			        return new MethodGen(method, jclass.getClassName(), getConstantPoolGen());
		        }
	        };

	private CFGFactory cfgFactory = new CFGFactory();

	private AnalysisFactory<ValueNumberDataflow> vnaDataflowFactory =
	        new AnalysisFactory<ValueNumberDataflow>("value number analysis") {
		        protected ValueNumberDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        LoadedFieldSet loadedFieldSet = getLoadedFieldSet(method);
			        ValueNumberAnalysis analysis = new ValueNumberAnalysis(methodGen, dfs, loadedFieldSet,
							getLookupFailureCallback());
			        CFG cfg = getCFG(method);
			        ValueNumberDataflow vnaDataflow = new ValueNumberDataflow(cfg, analysis);
			        vnaDataflow.execute();
			        return vnaDataflow;
		        }
	        };

	private AnalysisFactory<IsNullValueDataflow> invDataflowFactory =
	        new AnalysisFactory<IsNullValueDataflow>("null value analysis") {
		        protected IsNullValueDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        CFG cfg = getCFG(method);
			        ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        AssertionMethods assertionMethods = getAssertionMethods();

			        IsNullValueAnalysis invAnalysis = new IsNullValueAnalysis(methodGen, cfg, vnaDataflow, dfs, assertionMethods);
			        IsNullValueDataflow invDataflow = new IsNullValueDataflow(cfg, invAnalysis);
			        invDataflow.execute();
			        return invDataflow;
		        }
	        };

	private AnalysisFactory<TypeDataflow> typeDataflowFactory =
	        new AnalysisFactory<TypeDataflow>("type analysis") {
		        protected TypeDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        CFG cfg = getRawCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        ExceptionSetFactory exceptionSetFactory = getExceptionSetFactory(method);

			        TypeAnalysis typeAnalysis =
			                new TypeAnalysis(methodGen, cfg, dfs, getLookupFailureCallback(), exceptionSetFactory);
			        TypeDataflow typeDataflow = new TypeDataflow(cfg, typeAnalysis);
			        typeDataflow.execute();

			        return typeDataflow;
		        }
	        };

	private NoDataflowAnalysisFactory<DepthFirstSearch> dfsFactory =
	        new NoDataflowAnalysisFactory<DepthFirstSearch>("depth first search") {
		        protected DepthFirstSearch analyze(Method method) throws CFGBuilderException {
			        CFG cfg = getRawCFG(method);
			        DepthFirstSearch dfs = new DepthFirstSearch(cfg);
			        dfs.search();
			        return dfs;
		        }
	        };

	private NoDataflowAnalysisFactory<ReverseDepthFirstSearch> rdfsFactory =
	        new NoDataflowAnalysisFactory<ReverseDepthFirstSearch>("reverse depth first search") {
		        protected ReverseDepthFirstSearch analyze(Method method) throws CFGBuilderException {
			        CFG cfg = getRawCFG(method);
			        ReverseDepthFirstSearch rdfs = new ReverseDepthFirstSearch(cfg);
			        rdfs.search();
			        return rdfs;
		        }
	        };

	private NoExceptionAnalysisFactory<BitSet> bytecodeSetFactory =
	        new NoExceptionAnalysisFactory<BitSet>("bytecode set construction") {
		        protected BitSet analyze(Method method) {
			        final BitSet result = new BitSet();

			        Code code = method.getCode();
			        if (code != null) {
				        byte[] instructionList = code.getCode();

				        // Create a callback to put the opcodes of the method's
				        // bytecode instructions into the BitSet.
				        BytecodeScanner.Callback callback = new BytecodeScanner.Callback() {
					        public void handleInstruction(int opcode, int index) {
						        result.set(opcode, true);
					        }
				        };

				        // Scan the method.
				        BytecodeScanner scanner = new BytecodeScanner();
				        scanner.scan(instructionList, callback);
			        }

			        return result;
		        }
	        };

/*
	private AnalysisFactory<LockCountDataflow> anyLockCountDataflowFactory =
	new AnalysisFactory<LockCountDataflow>("lock count analysis (any lock)") {
		protected LockCountDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			MethodGen methodGen = getMethodGen(method);
			ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			DepthFirstSearch dfs = getDepthFirstSearch(method);
			CFG cfg = getCFG(method);

			AnyLockCountAnalysis analysis = new AnyLockCountAnalysis(methodGen, vnaDataflow, dfs);
			LockCountDataflow dataflow = new LockCountDataflow(cfg, analysis);
			dataflow.execute();
			return dataflow;
		}
	};
*/

	private AnalysisFactory<LockDataflow> lockDataflowFactory =
	        new AnalysisFactory<LockDataflow>("lock set analysis") {
		        protected LockDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        CFG cfg = getCFG(method);

			        LockAnalysis analysis = new LockAnalysis(methodGen, vnaDataflow, dfs);
			        LockDataflow dataflow = new LockDataflow(cfg, analysis);
			        dataflow.execute();
			        return dataflow;
		        }
	        };

	private AnalysisFactory<ReturnPathDataflow> returnPathDataflowFactory =
	        new AnalysisFactory<ReturnPathDataflow>("return path analysis") {
		        protected ReturnPathDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        ReturnPathAnalysis analysis = new ReturnPathAnalysis(dfs);
			        ReturnPathDataflow dataflow = new ReturnPathDataflow(cfg, analysis);
			        dataflow.execute();
			        return dataflow;
		        }
	        };

	private AnalysisFactory<DominatorsAnalysis> nonExceptionDominatorsAnalysisFactory =
	        new AnalysisFactory<DominatorsAnalysis>("non-exception dominators analysis") {
		        protected DominatorsAnalysis analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        DominatorsAnalysis analysis = new DominatorsAnalysis(cfg, dfs, true);
			        Dataflow<java.util.BitSet, DominatorsAnalysis> dataflow =
			                new Dataflow<java.util.BitSet, DominatorsAnalysis>(cfg, analysis);
			        dataflow.execute();
			        return analysis;
		        }
	        };

	private AnalysisFactory<PostDominatorsAnalysis> nonExceptionPostDominatorsAnalysisFactory =
	        new AnalysisFactory<PostDominatorsAnalysis>("non-exception postdominators analysis") {
		        protected PostDominatorsAnalysis analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        ReverseDepthFirstSearch rdfs = getReverseDepthFirstSearch(method);
			        PostDominatorsAnalysis analysis = new PostDominatorsAnalysis(cfg, rdfs, true);
			        Dataflow<java.util.BitSet, PostDominatorsAnalysis> dataflow =
			                new Dataflow<java.util.BitSet, PostDominatorsAnalysis>(cfg, analysis);
			        dataflow.execute();
			        return analysis;
		        }
	        };

	private NoExceptionAnalysisFactory<ExceptionSetFactory> exceptionSetFactoryFactory =
	        new NoExceptionAnalysisFactory<ExceptionSetFactory>("exception set factory") {
		        protected ExceptionSetFactory analyze(Method method) {
			        return new ExceptionSetFactory();
		        }
	        };

	private NoExceptionAnalysisFactory<String[]> parameterSignatureListFactory =
	        new NoExceptionAnalysisFactory<String[]>("parameter signature list factory") {
		        protected String[] analyze(Method method) {
			        SignatureParser parser = new SignatureParser(method.getSignature());
			        ArrayList<String> resultList = new ArrayList<String>();
			        for (Iterator<String> i = parser.parameterSignatureIterator(); i.hasNext();) {
				        resultList.add(i.next());
			        }
			        return resultList.toArray(new String[resultList.size()]);
		        }
	        };

	private static final BitSet fieldInstructionOpcodeSet = new BitSet();
	static {
		fieldInstructionOpcodeSet.set(Constants.GETFIELD);
		fieldInstructionOpcodeSet.set(Constants.PUTFIELD);
		fieldInstructionOpcodeSet.set(Constants.GETSTATIC);
		fieldInstructionOpcodeSet.set(Constants.PUTSTATIC);
	}

	/**
	 * Factory to determine which fields are loaded and stored
	 * by the instructions in a method, and the overall method.
	 * The main purpose is to support efficient redundant load elimination
	 * and forward substitution in ValueNumberAnalysis (there is no need to
	 * remember stores of fields that are never read,
	 * or loads of fields that are only loaded in one location).
	 * However, it might be useful for other kinds of analysis.
	 *
	 * <p> The tricky part is that in addition to fields loaded and stored
	 * with get/putfield and get/putstatic, we also try to figure
	 * out field accessed through calls to inner-class access methods.
	 */
	private NoExceptionAnalysisFactory<LoadedFieldSet> loadedFieldSetFactory =
			new NoExceptionAnalysisFactory<LoadedFieldSet>("loaded field set factory") {
				protected LoadedFieldSet analyze(Method method) {
					MethodGen methodGen = getMethodGen(method);
					InstructionList il = methodGen.getInstructionList();

					LoadedFieldSet loadedFieldSet = new LoadedFieldSet();
<commit_msg>Get ClassContext compiling again<commit_after>/*
 * 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 <NAME>
 */
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("  ");
	}

	private abstract class AnalysisFactory <AnalysisResult> {
		private String analysisName;
		private IdentityHashMap<Method, AnalysisResult> map = new IdentityHashMap<Method, AnalysisResult>();

		public AnalysisFactory(String analysisName) {
			this.analysisName = analysisName;
		}

		public AnalysisResult getAnalysis(Method method) throws CFGBuilderException, DataflowAnalysisException {
			AnalysisResult 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();

				try {
					result = analyze(method);
				} 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;
					}
					throw e;
				}

				if (TIME_ANALYSES) {
					long end = System.currentTimeMillis();
					indent();
					System.out.println("CC: finished " + analysisName + " in " + (end - begin) + " millis");
					--depth;
				}

				map.put(method, result);
			}
			return result;
		}

		protected abstract AnalysisResult 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)) {
				try {
					new PruneUnconditionalExceptionThrowerEdges(methodGen, cfg, getConstantPoolGen(), analysisContext).execute();
				} catch (DataflowAnalysisException e) {
					// FIXME: should report the error
				}
			}
			cfg.setFlags(cfg.getFlags() | PRUNED_UNCONDITIONAL_THROWERS);

			busyCFGSet.remove(methodId);

			return cfg;
		}

		protected CFG analyze(Method method) throws CFGBuilderException {
			MethodGen methodGen = getMethodGen(method);
			CFGBuilder cfgBuilder = CFGBuilderFactory.create(methodGen);
			cfgBuilder.build();
			return cfgBuilder.getCFG();
		}
	}

	/* ----------------------------------------------------------------------
	 * Fields
	 * ---------------------------------------------------------------------- */

	private JavaClass jclass;
	private AnalysisContext analysisContext;

	private NoExceptionAnalysisFactory<MethodGen> methodGenFactory =
	        new NoExceptionAnalysisFactory<MethodGen>("MethodGen construction") {
		        protected MethodGen analyze(Method method) {
			        if (method.getCode() == null)
				        return null;
			        return new MethodGen(method, jclass.getClassName(), getConstantPoolGen());
		        }
	        };

	private CFGFactory cfgFactory = new CFGFactory();

	private AnalysisFactory<ValueNumberDataflow> vnaDataflowFactory =
	        new AnalysisFactory<ValueNumberDataflow>("value number analysis") {
		        protected ValueNumberDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        LoadedFieldSet loadedFieldSet = getLoadedFieldSet(method);
			        ValueNumberAnalysis analysis = new ValueNumberAnalysis(methodGen, dfs, loadedFieldSet,
							getLookupFailureCallback());
			        CFG cfg = getCFG(method);
			        ValueNumberDataflow vnaDataflow = new ValueNumberDataflow(cfg, analysis);
			        vnaDataflow.execute();
			        return vnaDataflow;
		        }
	        };

	private AnalysisFactory<IsNullValueDataflow> invDataflowFactory =
	        new AnalysisFactory<IsNullValueDataflow>("null value analysis") {
		        protected IsNullValueDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        CFG cfg = getCFG(method);
			        ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        AssertionMethods assertionMethods = getAssertionMethods();

			        IsNullValueAnalysis invAnalysis = new IsNullValueAnalysis(methodGen, cfg, vnaDataflow, dfs, assertionMethods);
			        IsNullValueDataflow invDataflow = new IsNullValueDataflow(cfg, invAnalysis);
			        invDataflow.execute();
			        return invDataflow;
		        }
	        };

	private AnalysisFactory<TypeDataflow> typeDataflowFactory =
	        new AnalysisFactory<TypeDataflow>("type analysis") {
		        protected TypeDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        CFG cfg = getRawCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        ExceptionSetFactory exceptionSetFactory = getExceptionSetFactory(method);

			        TypeAnalysis typeAnalysis =
			                new TypeAnalysis(methodGen, cfg, dfs, getLookupFailureCallback(), exceptionSetFactory);
			        TypeDataflow typeDataflow = new TypeDataflow(cfg, typeAnalysis);
			        typeDataflow.execute();

			        return typeDataflow;
		        }
	        };

	private NoDataflowAnalysisFactory<DepthFirstSearch> dfsFactory =
	        new NoDataflowAnalysisFactory<DepthFirstSearch>("depth first search") {
		        protected DepthFirstSearch analyze(Method method) throws CFGBuilderException {
			        CFG cfg = getRawCFG(method);
			        DepthFirstSearch dfs = new DepthFirstSearch(cfg);
			        dfs.search();
			        return dfs;
		        }
	        };

	private NoDataflowAnalysisFactory<ReverseDepthFirstSearch> rdfsFactory =
	        new NoDataflowAnalysisFactory<ReverseDepthFirstSearch>("reverse depth first search") {
		        protected ReverseDepthFirstSearch analyze(Method method) throws CFGBuilderException {
			        CFG cfg = getRawCFG(method);
			        ReverseDepthFirstSearch rdfs = new ReverseDepthFirstSearch(cfg);
			        rdfs.search();
			        return rdfs;
		        }
	        };

	private NoExceptionAnalysisFactory<BitSet> bytecodeSetFactory =
	        new NoExceptionAnalysisFactory<BitSet>("bytecode set construction") {
		        protected BitSet analyze(Method method) {
			        final BitSet result = new BitSet();

			        Code code = method.getCode();
			        if (code != null) {
				        byte[] instructionList = code.getCode();

				        // Create a callback to put the opcodes of the method's
				        // bytecode instructions into the BitSet.
				        BytecodeScanner.Callback callback = new BytecodeScanner.Callback() {
					        public void handleInstruction(int opcode, int index) {
						        result.set(opcode, true);
					        }
				        };

				        // Scan the method.
				        BytecodeScanner scanner = new BytecodeScanner();
				        scanner.scan(instructionList, callback);
			        }

			        return result;
		        }
	        };

/*
	private AnalysisFactory<LockCountDataflow> anyLockCountDataflowFactory =
	new AnalysisFactory<LockCountDataflow>("lock count analysis (any lock)") {
		protected LockCountDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			MethodGen methodGen = getMethodGen(method);
			ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			DepthFirstSearch dfs = getDepthFirstSearch(method);
			CFG cfg = getCFG(method);

			AnyLockCountAnalysis analysis = new AnyLockCountAnalysis(methodGen, vnaDataflow, dfs);
			LockCountDataflow dataflow = new LockCountDataflow(cfg, analysis);
			dataflow.execute();
			return dataflow;
		}
	};
*/

	private AnalysisFactory<LockDataflow> lockDataflowFactory =
	        new AnalysisFactory<LockDataflow>("lock set analysis") {
		        protected LockDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        MethodGen methodGen = getMethodGen(method);
			        ValueNumberDataflow vnaDataflow = getValueNumberDataflow(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        CFG cfg = getCFG(method);

			        LockAnalysis analysis = new LockAnalysis(methodGen, vnaDataflow, dfs);
			        LockDataflow dataflow = new LockDataflow(cfg, analysis);
			        dataflow.execute();
			        return dataflow;
		        }
	        };

	private AnalysisFactory<ReturnPathDataflow> returnPathDataflowFactory =
	        new AnalysisFactory<ReturnPathDataflow>("return path analysis") {
		        protected ReturnPathDataflow analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        ReturnPathAnalysis analysis = new ReturnPathAnalysis(dfs);
			        ReturnPathDataflow dataflow = new ReturnPathDataflow(cfg, analysis);
			        dataflow.execute();
			        return dataflow;
		        }
	        };

	private AnalysisFactory<DominatorsAnalysis> nonExceptionDominatorsAnalysisFactory =
	        new AnalysisFactory<DominatorsAnalysis>("non-exception dominators analysis") {
		        protected DominatorsAnalysis analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        DepthFirstSearch dfs = getDepthFirstSearch(method);
			        DominatorsAnalysis analysis = new DominatorsAnalysis(cfg, dfs, true);
			        Dataflow<java.util.BitSet, DominatorsAnalysis> dataflow =
			                new Dataflow<java.util.BitSet, DominatorsAnalysis>(cfg, analysis);
			        dataflow.execute();
			        return analysis;
		        }
	        };

	private AnalysisFactory<PostDominatorsAnalysis> nonExceptionPostDominatorsAnalysisFactory =
	        new AnalysisFactory<PostDominatorsAnalysis>("non-exception postdominators analysis") {
		        protected PostDominatorsAnalysis analyze(Method method) throws DataflowAnalysisException, CFGBuilderException {
			        CFG cfg = getCFG(method);
			        ReverseDepthFirstSearch rdfs = getReverseDepthFirstSearch(method);
			        PostDominatorsAnalysis analysis = new PostDominatorsAnalysis(cfg, rdfs, true);
			        Dataflow<java.util.BitSet, PostDominatorsAnalysis> dataflow =
			                new Dataflow<java.util.BitSet, PostDominatorsAnalysis>(cfg, analysis);
			        dataflow.execute();
			        return analysis;
		        }
	        };

	private NoExceptionAnalysisFactory<ExceptionSetFactory> exceptionSetFactoryFactory =
	        new NoExceptionAnalysisFactory<ExceptionSetFactory>("exception set factory") {
		        protected ExceptionSetFactory analyze(Method method) {
			        return new ExceptionSetFactory();
		        }
	        };

	private NoExceptionAnalysisFactory<String[]> parameterSignatureListFactory =
	        new NoExceptionAnalysisFactory<String[]>("parameter signature list factory") {
		        protected String[] analyze(Method method) {
			        SignatureParser parser = new SignatureParser(method.getSignature());
			        ArrayList<String> resultList = new ArrayList<String>();
			        for (Iterator<String> i = parser.parameterSignatureIterator(); i.hasNext();) {
				        resultList.add(i.next());
			        }
			        return resultList.toArray(new String[resultList.size()]);
		        }
	        };

	private static final BitSet fieldInstructionOpcodeSet = new BitSet();
	static {
		fieldInstructionOpcodeSet.set(Constants.GETFIELD);
		fieldInstructionOpcodeSet.set(Constants.PUTFIELD);
		fieldInstructionOpcodeSet.set(Constants.GETSTATIC);
		fieldInstructionOpcodeSet.set(Constants.PUTSTATIC);
	}

	/**
	 * Factory to determine which fields are loaded and stored
	 * by the instructions in a method, and the overall method.
	 * The main purpose is to support efficient redundant load elimination
	 * and forward substitution in ValueNumberAnalysis (there is no need to
	 * remember stores of fields that are never read,
	 * or loads of fields that are only loaded in one location).
	 * However, it might be useful for other kinds of analysis.
	 *
	 * <p> The tricky part is that in addition to fields loaded and stored
	 * with get/putfield and get/putstatic, we also try to figure
	 * out field accessed through calls to inner-class access methods.
	 */
	private NoExceptionAnalysisFactory<LoadedFieldSet> loadedFieldSetFactory =
			new NoExceptionAnalysisFactory<LoadedFieldSet>("loaded field set factory") {
				protected LoadedFieldSet analyze(Method method) {
					MethodGen methodGen = getMethodGen(method);
					InstructionList il = methodGen.getInstructionList();

					LoadedFieldSet loadedFieldSet = new LoadedFieldSet(methodGen);

{'fraction_non_alphanumeric': 0.0952040872383673, 'fraction_numerical': 0.001483271988133824, 'mean_word_length': 3.2491830065359477, 'pattern_counts': {'":': 4, '<': 107, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5009508', 'n_tokens_mistral': 10887, 'n_tokens_neox': 9231, 'n_words': 2477}