<commit_before>package edu.umd.cs.findbugs.detect;

import java.util.BitSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Synthetic;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INSTANCEOF;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.TypedInstruction;

import edu.umd.cs.findbugs.DeepSubtypeAnalysis;
import edu.umd.cs.findbugs.BugAccumulator;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.Detector;
import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.CFG;
import edu.umd.cs.findbugs.ba.CFGBuilderException;
import edu.umd.cs.findbugs.ba.ClassContext;
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
import edu.umd.cs.findbugs.ba.Location;
import edu.umd.cs.findbugs.ba.npe.IsNullValue;
import edu.umd.cs.findbugs.ba.npe.IsNullValueDataflow;
import edu.umd.cs.findbugs.ba.npe.IsNullValueFrame;
import edu.umd.cs.findbugs.ba.type.NullType;
import edu.umd.cs.findbugs.ba.type.TopType;
import edu.umd.cs.findbugs.ba.type.TypeDataflow;
import edu.umd.cs.findbugs.ba.type.TypeFrame;
import edu.umd.cs.findbugs.ba.vna.ValueNumber;
import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;

public class FindBadCast2 implements Detector {

	private BugReporter bugReporter;

	private Set<String> concreteCollectionClasses = new HashSet<String>();

	private Set<String> abstractCollectionClasses = new HashSet<String>();
	private Set<String> veryAbstractCollectionClasses = new HashSet<String>();

	private static final boolean DEBUG = SystemProperties.getBoolean("bc.debug");

	public FindBadCast2(BugReporter bugReporter) {
		this.bugReporter = bugReporter;
		veryAbstractCollectionClasses.add("java.util.Collection");
		veryAbstractCollectionClasses.add("java.util.Iterable");
		abstractCollectionClasses.add("java.util.Collection");
		abstractCollectionClasses.add("java.util.List");
		abstractCollectionClasses.add("java.util.Set");
		abstractCollectionClasses.add("java.util.SortedSet");
		abstractCollectionClasses.add("java.util.SortedMap");
		abstractCollectionClasses.add("java.util.Set");
		abstractCollectionClasses.add("java.util.Map");
		concreteCollectionClasses.add("java.util.LinkedHashMap");
		concreteCollectionClasses.add("java.util.LinkedHashSet");
		concreteCollectionClasses.add("java.util.HashMap");
		concreteCollectionClasses.add("java.util.HashSet");
		concreteCollectionClasses.add("java.util.TreeMap");
		concreteCollectionClasses.add("java.util.TreeSet");
		concreteCollectionClasses.add("java.util.ArrayList");
		concreteCollectionClasses.add("java.util.LinkedList");
		concreteCollectionClasses.add("java.util.Hashtable");
		concreteCollectionClasses.add("java.util.Vector");
	}

	public void visitClassContext(ClassContext classContext) {
		Method[] methodList = classContext.getJavaClass().getMethods();

		for (Method method : methodList) {
			if (method.getCode() == null)
				continue;

			try {
				analyzeMethod(classContext, method);
			} catch (CFGBuilderException e) {
				bugReporter.logError("Detector " + this.getClass().getName()
						+ " caught exception", e);
			} catch (DataflowAnalysisException e) {
//				bugReporter.logError("Detector " + this.getClass().getName()
//						+ " caught exception", e);
			}
		}
	}

	public boolean prescreen(ClassContext classContext, Method method) {
		BitSet bytecodeSet = classContext.getBytecodeSet(method);
		return bytecodeSet != null && (bytecodeSet.get(Constants.CHECKCAST)
				|| bytecodeSet.get(Constants.INSTANCEOF));
	}

	private boolean isSynthetic(Method m) {
		Attribute[] attrs = m.getAttributes();
		for (Attribute attr : attrs) {
			if (attr instanceof Synthetic)
				return true;
		}
		return false;
	}
	private Set<ValueNumber> getParameterValueNumbers(ClassContext classContext, Method method,  CFG cfg ) throws DataflowAnalysisException, CFGBuilderException {
		ValueNumberDataflow vnaDataflow = classContext.getValueNumberDataflow(method);
		ValueNumberFrame vnaFrameAtEntry = vnaDataflow.getStartFact(cfg
				.getEntry());
		Set<ValueNumber> paramValueNumberSet = new HashSet<ValueNumber>();
		int firstParam = method.isStatic() ? 0 : 1;
		for (int i = firstParam; i < vnaFrameAtEntry.getNumLocals(); ++i) {
			paramValueNumberSet.add(vnaFrameAtEntry.getValue(i));
		}
		return paramValueNumberSet;
	}
	private void analyzeMethod(ClassContext classContext, Method method)
			throws CFGBuilderException, DataflowAnalysisException {
		if (isSynthetic(method) || !prescreen(classContext, method))
			return;
		BugAccumulator accumulator = new BugAccumulator(bugReporter);
		
		
		CFG cfg = classContext.getCFG(method);
		TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
		IsNullValueDataflow isNullDataflow = classContext.getIsNullValueDataflow(method);
		Set<ValueNumber> paramValueNumberSet = null;
		
		ValueNumberDataflow vnaDataflow = null;

		ConstantPoolGen cpg = classContext.getConstantPoolGen();
		MethodGen methodGen = classContext.getMethodGen(method);
		if (methodGen == null) return;
		String methodName = methodGen.getClassName() + "."
				+ methodGen.getName();
		String sourceFile = classContext.getJavaClass().getSourceFileName();
		if (DEBUG) {
			System.out.println("Checking " + methodName);
		}

		Set<SourceLineAnnotation> haveInstanceOf = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveCast = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveMultipleInstanceOf = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveMultipleCast = new HashSet<SourceLineAnnotation>();
		for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
			Location location = i.next();
			InstructionHandle handle = location.getHandle();
			Instruction ins = handle.getInstruction();

			if (!(ins instanceof CHECKCAST) && !(ins instanceof INSTANCEOF))
				continue;

			SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
					.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);
			if (ins instanceof CHECKCAST) {
				if (!haveCast.add(sourceLineAnnotation))
					haveMultipleCast.add(sourceLineAnnotation);
			} else {
				if (!haveInstanceOf.add(sourceLineAnnotation))
					haveMultipleInstanceOf.add(sourceLineAnnotation);
			}
		}
		for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
			Location location = i.next();
	
			InstructionHandle handle = location.getHandle();
			int pc = handle.getPosition();
			Instruction ins = handle.getInstruction();
	
			if (!(ins instanceof CHECKCAST) && !(ins instanceof INSTANCEOF))
				continue;
			if (handle.getNext() == null) continue;
			Instruction nextIns = handle.getNext().getInstruction();

			boolean isCast = ins instanceof CHECKCAST;
			String kind = isCast ? "checkedCast" : "instanceof";
			int occurrences = cfg.getLocationsContainingInstructionWithOffset(
					pc).size();
			boolean split = occurrences > 1;
			IsNullValueFrame nullFrame = isNullDataflow.getFactAtLocation(location);
			IsNullValue operandNullness = nullFrame.getTopValue();
			if (DEBUG) {
				System.out
						.println(kind + " at pc: " + pc + " in " + methodName);
				System.out.println(" occurrences: " + occurrences);
				System.out.println("XXX: " + operandNullness);
				
			}

			if (split && !isCast) {
				// don't report this case; it might be infeasible due to inlining
				continue;
			}

			TypeFrame frame = typeDataflow.getFactAtLocation(location);
			if (!frame.isValid()) {
				// This basic block is probably dead
				continue;
			}

			Type operandType = frame.getTopValue();
			if (operandType.equals(TopType.instance())) {
				// unreachable
				continue;
			}
			boolean operandTypeIsExact = frame.isExact(frame.getStackLocation(0));
			Type castType = ((TypedInstruction) ins).getType(cpg);

			if (!(castType instanceof ReferenceType)) {
				// This shouldn't happen either
				continue;
			}
			String castSig = castType.getSignature();
			
			if (operandType.equals(NullType.instance()) || operandNullness.isDefinitelyNull()) {
				SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
				.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);
				String castName = castSig.substring(1, castSig.length() - 1)
				.replace('/', '.');
				if (!isCast) accumulator.accumulateBug(new BugInstance(this,
						"NP_NULL_INSTANCEOF", NORMAL_PRIORITY)
						.addClassAndMethod(methodGen, sourceFile)
						.addClass(castName), sourceLineAnnotation);
				continue;

			}
			if (!(operandType instanceof ReferenceType)) {
				// Shouldn't happen - illegal bytecode
				continue;
			}
			ReferenceType refType = (ReferenceType) operandType;

		
			if (refType.equals(castType)) {
				// System.out.println("self-cast to " + castType.getSignature());
				continue;
			}
			
			String refSig = refType.getSignature();
			String castSig2 = castSig;
			String refSig2 = refSig;
			while (castSig2.charAt(0) == '[' && refSig2.charAt(0) == '[') {
				castSig2 = castSig2.substring(1);
				refSig2 = refSig2.substring(1);
			}

			
			SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
			.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);

			if (refSig2.charAt(0) != 'L' || castSig2.charAt(0) != 'L') {
				if ( castSig2.charAt(0) == '[' && (refSig2.equals("Ljava/io/Serializable;") 
						|| refSig2.equals("Ljava/lang/Object;")
						|| refSig2.equals("Ljava/lang/Cloneable;"))) continue;
				bugReporter.reportBug(
						new BugInstance(this,
						"BC_IMPOSSIBLE_CAST", HIGH_PRIORITY )
						.addClassAndMethod(methodGen, sourceFile)
						.addType(refSig)
						.addType(castSig)
						.addSourceLine(sourceLineAnnotation));
				continue;
			}

			if (refSig2.equals("Ljava/lang/Object;")  &!operandTypeIsExact) {<commit_msg>handle cast from array to serializable or cloneable<commit_after>package edu.umd.cs.findbugs.detect;

import java.util.BitSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Synthetic;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INSTANCEOF;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.TypedInstruction;

import edu.umd.cs.findbugs.DeepSubtypeAnalysis;
import edu.umd.cs.findbugs.BugAccumulator;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.Detector;
import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.CFG;
import edu.umd.cs.findbugs.ba.CFGBuilderException;
import edu.umd.cs.findbugs.ba.ClassContext;
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
import edu.umd.cs.findbugs.ba.Location;
import edu.umd.cs.findbugs.ba.npe.IsNullValue;
import edu.umd.cs.findbugs.ba.npe.IsNullValueDataflow;
import edu.umd.cs.findbugs.ba.npe.IsNullValueFrame;
import edu.umd.cs.findbugs.ba.type.NullType;
import edu.umd.cs.findbugs.ba.type.TopType;
import edu.umd.cs.findbugs.ba.type.TypeDataflow;
import edu.umd.cs.findbugs.ba.type.TypeFrame;
import edu.umd.cs.findbugs.ba.vna.ValueNumber;
import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;

public class FindBadCast2 implements Detector {

	private BugReporter bugReporter;

	private Set<String> concreteCollectionClasses = new HashSet<String>();

	private Set<String> abstractCollectionClasses = new HashSet<String>();
	private Set<String> veryAbstractCollectionClasses = new HashSet<String>();

	private static final boolean DEBUG = SystemProperties.getBoolean("bc.debug");

	public FindBadCast2(BugReporter bugReporter) {
		this.bugReporter = bugReporter;
		veryAbstractCollectionClasses.add("java.util.Collection");
		veryAbstractCollectionClasses.add("java.util.Iterable");
		abstractCollectionClasses.add("java.util.Collection");
		abstractCollectionClasses.add("java.util.List");
		abstractCollectionClasses.add("java.util.Set");
		abstractCollectionClasses.add("java.util.SortedSet");
		abstractCollectionClasses.add("java.util.SortedMap");
		abstractCollectionClasses.add("java.util.Set");
		abstractCollectionClasses.add("java.util.Map");
		concreteCollectionClasses.add("java.util.LinkedHashMap");
		concreteCollectionClasses.add("java.util.LinkedHashSet");
		concreteCollectionClasses.add("java.util.HashMap");
		concreteCollectionClasses.add("java.util.HashSet");
		concreteCollectionClasses.add("java.util.TreeMap");
		concreteCollectionClasses.add("java.util.TreeSet");
		concreteCollectionClasses.add("java.util.ArrayList");
		concreteCollectionClasses.add("java.util.LinkedList");
		concreteCollectionClasses.add("java.util.Hashtable");
		concreteCollectionClasses.add("java.util.Vector");
	}

	public void visitClassContext(ClassContext classContext) {
		Method[] methodList = classContext.getJavaClass().getMethods();

		for (Method method : methodList) {
			if (method.getCode() == null)
				continue;

			try {
				analyzeMethod(classContext, method);
			} catch (CFGBuilderException e) {
				bugReporter.logError("Detector " + this.getClass().getName()
						+ " caught exception", e);
			} catch (DataflowAnalysisException e) {
//				bugReporter.logError("Detector " + this.getClass().getName()
//						+ " caught exception", e);
			}
		}
	}

	public boolean prescreen(ClassContext classContext, Method method) {
		BitSet bytecodeSet = classContext.getBytecodeSet(method);
		return bytecodeSet != null && (bytecodeSet.get(Constants.CHECKCAST)
				|| bytecodeSet.get(Constants.INSTANCEOF));
	}

	private boolean isSynthetic(Method m) {
		Attribute[] attrs = m.getAttributes();
		for (Attribute attr : attrs) {
			if (attr instanceof Synthetic)
				return true;
		}
		return false;
	}
	private Set<ValueNumber> getParameterValueNumbers(ClassContext classContext, Method method,  CFG cfg ) throws DataflowAnalysisException, CFGBuilderException {
		ValueNumberDataflow vnaDataflow = classContext.getValueNumberDataflow(method);
		ValueNumberFrame vnaFrameAtEntry = vnaDataflow.getStartFact(cfg
				.getEntry());
		Set<ValueNumber> paramValueNumberSet = new HashSet<ValueNumber>();
		int firstParam = method.isStatic() ? 0 : 1;
		for (int i = firstParam; i < vnaFrameAtEntry.getNumLocals(); ++i) {
			paramValueNumberSet.add(vnaFrameAtEntry.getValue(i));
		}
		return paramValueNumberSet;
	}
	private void analyzeMethod(ClassContext classContext, Method method)
			throws CFGBuilderException, DataflowAnalysisException {
		if (isSynthetic(method) || !prescreen(classContext, method))
			return;
		BugAccumulator accumulator = new BugAccumulator(bugReporter);
		
		
		CFG cfg = classContext.getCFG(method);
		TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
		IsNullValueDataflow isNullDataflow = classContext.getIsNullValueDataflow(method);
		Set<ValueNumber> paramValueNumberSet = null;
		
		ValueNumberDataflow vnaDataflow = null;

		ConstantPoolGen cpg = classContext.getConstantPoolGen();
		MethodGen methodGen = classContext.getMethodGen(method);
		if (methodGen == null) return;
		String methodName = methodGen.getClassName() + "."
				+ methodGen.getName();
		String sourceFile = classContext.getJavaClass().getSourceFileName();
		if (DEBUG) {
			System.out.println("Checking " + methodName);
		}

		Set<SourceLineAnnotation> haveInstanceOf = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveCast = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveMultipleInstanceOf = new HashSet<SourceLineAnnotation>();
		Set<SourceLineAnnotation> haveMultipleCast = new HashSet<SourceLineAnnotation>();
		for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
			Location location = i.next();
			InstructionHandle handle = location.getHandle();
			Instruction ins = handle.getInstruction();

			if (!(ins instanceof CHECKCAST) && !(ins instanceof INSTANCEOF))
				continue;

			SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
					.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);
			if (ins instanceof CHECKCAST) {
				if (!haveCast.add(sourceLineAnnotation))
					haveMultipleCast.add(sourceLineAnnotation);
			} else {
				if (!haveInstanceOf.add(sourceLineAnnotation))
					haveMultipleInstanceOf.add(sourceLineAnnotation);
			}
		}
		for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
			Location location = i.next();
	
			InstructionHandle handle = location.getHandle();
			int pc = handle.getPosition();
			Instruction ins = handle.getInstruction();
	
			if (!(ins instanceof CHECKCAST) && !(ins instanceof INSTANCEOF))
				continue;
			if (handle.getNext() == null) continue;
			Instruction nextIns = handle.getNext().getInstruction();

			boolean isCast = ins instanceof CHECKCAST;
			String kind = isCast ? "checkedCast" : "instanceof";
			int occurrences = cfg.getLocationsContainingInstructionWithOffset(
					pc).size();
			boolean split = occurrences > 1;
			IsNullValueFrame nullFrame = isNullDataflow.getFactAtLocation(location);
			IsNullValue operandNullness = nullFrame.getTopValue();
			if (DEBUG) {
				System.out
						.println(kind + " at pc: " + pc + " in " + methodName);
				System.out.println(" occurrences: " + occurrences);
				System.out.println("XXX: " + operandNullness);
				
			}

			if (split && !isCast) {
				// don't report this case; it might be infeasible due to inlining
				continue;
			}

			TypeFrame frame = typeDataflow.getFactAtLocation(location);
			if (!frame.isValid()) {
				// This basic block is probably dead
				continue;
			}

			Type operandType = frame.getTopValue();
			if (operandType.equals(TopType.instance())) {
				// unreachable
				continue;
			}
			boolean operandTypeIsExact = frame.isExact(frame.getStackLocation(0));
			Type castType = ((TypedInstruction) ins).getType(cpg);

			if (!(castType instanceof ReferenceType)) {
				// This shouldn't happen either
				continue;
			}
			String castSig = castType.getSignature();
			
			if (operandType.equals(NullType.instance()) || operandNullness.isDefinitelyNull()) {
				SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
				.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);
				String castName = castSig.substring(1, castSig.length() - 1)
				.replace('/', '.');
				if (!isCast) accumulator.accumulateBug(new BugInstance(this,
						"NP_NULL_INSTANCEOF", NORMAL_PRIORITY)
						.addClassAndMethod(methodGen, sourceFile)
						.addClass(castName), sourceLineAnnotation);
				continue;

			}
			if (!(operandType instanceof ReferenceType)) {
				// Shouldn't happen - illegal bytecode
				continue;
			}
			ReferenceType refType = (ReferenceType) operandType;

		
			if (refType.equals(castType)) {
				// System.out.println("self-cast to " + castType.getSignature());
				continue;
			}
			
			String refSig = refType.getSignature();
			String castSig2 = castSig;
			String refSig2 = refSig;
			while (castSig2.charAt(0) == '[' && refSig2.charAt(0) == '[') {
				castSig2 = castSig2.substring(1);
				refSig2 = refSig2.substring(1);
			}

			
			SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation
			.fromVisitedInstruction(classContext, methodGen, sourceFile, handle);

			if (refSig2.charAt(0) != 'L' || castSig2.charAt(0) != 'L') {
				if ( castSig2.charAt(0) == '[' && (refSig2.equals("Ljava/io/Serializable;") 
						|| refSig2.equals("Ljava/lang/Object;")
						|| refSig2.equals("Ljava/lang/Cloneable;"))) continue;
				if ( refSig2.charAt(0) == '[' && (castSig2.equals("Ljava/io/Serializable;") 
						|| castSig2.equals("Ljava/lang/Object;")
						|| castSig2.equals("Ljava/lang/Cloneable;"))) continue;
				bugReporter.reportBug(
						new BugInstance(this,
						"BC_IMPOSSIBLE_CAST", HIGH_PRIORITY )
						.addClassAndMethod(methodGen, sourceFile)
						.addType(refSig)
						.addType(castSig)
						.addSourceLine(sourceLineAnnotation));
				continue;
			}

			if (refSig2.equals("Ljava/lang/Object;")  &!operandTypeIsExact) {
{'fraction_non_alphanumeric': 0.12182812942175267, 'fraction_numerical': 0.0030657485142911046, 'mean_word_length': 4.888086642599278, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, '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': '5011023', 'n_tokens_mistral': 7431, 'n_tokens_neox': 6547, 'n_words': 1157}