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);
if (DEBUG) {
System.out.println("Have multiple casts for " + sourceLineAnnotation);
}
}
} else {
if (!haveInstanceOf.add(sourceLineAnnotation)) {
haveMultipleInstanceOf.add(sourceLineAnnotation);
if (DEBUG) {
System.out.println("Have multiple instanceof for " + sourceLineAnnotation);
}
}
}
}
BitSet linesMentionedMultipleTimes = classContext.linesMentionedMultipleTimes(method);
LineNumberTable lineNumberTable = methodGen.getLineNumberTable(methodGen.getConstantPool());
Map<BugAnnotation, String> instanceOfChecks = new HashMap<BugAnnotation, String>();
String constantClass = null;
boolean methodInvocationWasGeneric = false;
int pcForConstantClass = -1;
for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
Location location = i.next();
InstructionHandle handle = location.getHandle();
int pc = handle.getPosition();
Instruction ins = handle.getInstruction();
boolean wasMethodInvocationWasGeneric = methodInvocationWasGeneric;
methodInvocationWasGeneric = false;
if (ins instanceof InvokeInstruction) {
InvokeInstruction iinv = (InvokeInstruction) ins;
XMethod m = XFactory.createXMethod(iinv, cpg);
if (m != null) {
String sourceSignature = m.getSourceSignature();
methodInvocationWasGeneric = sourceSignature != null
&& (sourceSignature.startsWith("<") || sourceSignature.indexOf("java/lang/Class") >= 0);
if (DEBUG && methodInvocationWasGeneric) {
System.out.println(m + " has source signature " + sourceSignature);
}
}
}
if (ins instanceof LDC) {
LDC ldc = (LDC) ins;
Object value = ldc.getValue(cpg);
if (value instanceof ConstantClass) {
ConstantClass cc = (ConstantClass) value;
constantClass = cc.getBytes(classContext.getJavaClass().getConstantPool());
pcForConstantClass = pc;
}
}
if (!(ins instanceof CHECKCAST) && !(ins instanceof INSTANCEOF)) {
continue;
}
boolean isCast = ins instanceof CHECKCAST;
int occurrences = cfg.getLocationsContainingInstructionWithOffset(pc).size();
boolean split = occurrences > 1;
if (lineNumberTable != null) {
int line = lineNumberTable.getSourceLine(handle.getPosition());
if (line > 0 && linesMentionedMultipleTimes.get(line)) {
split = true;
}
}
IsNullValueFrame nullFrame = isNullDataflow.getFactAtLocation(location);
if (!nullFrame.isValid()) {
continue;
}
IsNullValue operandNullness = nullFrame.getTopValue();
if (DEBUG) {
String kind = isCast ? "checkedCast" : "instanceof";
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));
final 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);
assert castSig.length() > 1;
if (!isCast) {
accumulator.accumulateBug(new BugInstance(this, "NP_NULL_INSTANCEOF", split ? LOW_PRIORITY : NORMAL_PRIORITY)
.addClassAndMethod(methodGen, sourceFile).addType(castSig), sourceLineAnnotation);
}
continue;
}
if (!(operandType instanceof ReferenceType)) {
// Shouldn't happen - illegal bytecode
continue;
}
final ReferenceType refType = (ReferenceType) operandType;
boolean impliesByGenerics = typeDataflow.getAnalysis().isImpliedByGenericTypes(refType);
if (impliesByGenerics && !isCast) {
continue;
}
final boolean typesAreEqual = refType.equals(castType);
if (isCast && typesAreEqual) {
// 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;
}
int priority = HIGH_PRIORITY;
if (split && (castSig2.endsWith("Error;") || castSig2.endsWith("Exception;"))) {
priority = LOW_PRIORITY;
}
// report bug only if types are not equal, see bug 3598482
if(!typesAreEqual){
bugReporter.reportBug(new BugInstance(this, isCast ? "BC_IMPOSSIBLE_CAST" : "BC_IMPOSSIBLE_INSTANCEOF", priority)
.addClassAndMethod(methodGen, sourceFile).addFoundAndExpectedType(refType, castType)
.addSourceLine(sourceLineAnnotation));
}
continue;
}
if (!operandTypeIsExact && refSig2.equals("Ljava/lang/Object;")) {
continue;
}
/*
if (false && isCast && haveMultipleCast.contains(sourceLineAnnotation) || !isCast
&& haveMultipleInstanceOf.contains(sourceLineAnnotation)) {
// skip; might be due to JSR inlining
continue;
}*/
String castName = castSig2.substring(1, castSig2.length() - 1).replace('/', '.');
String refName = refSig2.substring(1, refSig2.length() - 1).replace('/', '.');
if (vnaDataflow == null) {
vnaDataflow = classContext.getValueNumberDataflow(method);
}
ValueNumberFrame vFrame = vnaDataflow.getFactAtLocation(location);
if (paramValueNumberSet == null) {
paramValueNumberSet = getParameterValueNumbers(classContext, method, cfg);
}
ValueNumber valueNumber = vFrame.getTopValue();
BugAnnotation valueSource = ValueNumberSourceInfo.findAnnotationFromValueNumber(method, location, valueNumber, vFrame,