if (caught && skipIfInsideCatchNull()) {
return;
}
// See what methods might be called here
XMethod calledMethod = XFactory.createXMethod(invokeInstruction, cpg);
if (true) {
// If a parameter is already marked as nonnull, don't complain about
// it here.
nullArgSet = (BitSet) nullArgSet.clone();
definitelyNullArgSet = (BitSet) definitelyNullArgSet.clone();
ClassDescriptor nonnullClassDesc = DescriptorFactory.createClassDescriptor(javax.annotation.Nonnull.class);
TypeQualifierValue<?> nonnullTypeQualifierValue = TypeQualifierValue.getValue(nonnullClassDesc, null);
for (int i = nullArgSet.nextSetBit(0); i >= 0; i = nullArgSet.nextSetBit(i + 1)) {
TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(calledMethod, i,
nonnullTypeQualifierValue);
if (tqa != null && tqa.when == When.ALWAYS) {
nullArgSet.clear(i);
definitelyNullArgSet.clear(i);
}
}
}
TypeFrame typeFrame = typeDataflow.getFactAtLocation(location);
Set<JavaClassAndMethod> targetMethodSet = Hierarchy.resolveMethodCallTargets(invokeInstruction, typeFrame, cpg);
if (DEBUG_NULLARG) {
System.out.println("Possibly called methods: " + targetMethodSet);
}
// See if any call targets unconditionally dereference one of the null
// arguments
BitSet unconditionallyDereferencedNullArgSet = new BitSet();
List<JavaClassAndMethod> dangerousCallTargetList = new LinkedList<JavaClassAndMethod>();
List<JavaClassAndMethod> veryDangerousCallTargetList = new LinkedList<JavaClassAndMethod>();
for (JavaClassAndMethod targetMethod : targetMethodSet) {
if (DEBUG_NULLARG) {
System.out.println("For target method " + targetMethod);
}
ParameterProperty property = unconditionalDerefParamDatabase.getProperty(targetMethod.toMethodDescriptor());
if (property == null) {
continue;
}
if (DEBUG_NULLARG) {
System.out.println("\tUnconditionally dereferenced params: " + property);
}
BitSet targetUnconditionallyDereferencedNullArgSet = property.getMatchingParameters(nullArgSet);
if (targetUnconditionallyDereferencedNullArgSet.isEmpty()) {
continue;
}
dangerousCallTargetList.add(targetMethod);
unconditionallyDereferencedNullArgSet.or(targetUnconditionallyDereferencedNullArgSet);
if (!property.getMatchingParameters(definitelyNullArgSet).isEmpty()) {
veryDangerousCallTargetList.add(targetMethod);
}
}
if (dangerousCallTargetList.isEmpty()) {
return;
}
WarningPropertySet<WarningProperty> propertySet = new WarningPropertySet<WarningProperty>();
// See if there are any safe targets
Set<JavaClassAndMethod> safeCallTargetSet = new HashSet<JavaClassAndMethod>();
safeCallTargetSet.addAll(targetMethodSet);
safeCallTargetSet.removeAll(dangerousCallTargetList);
if (safeCallTargetSet.isEmpty()) {
propertySet.addProperty(NullArgumentWarningProperty.ALL_DANGEROUS_TARGETS);
if (dangerousCallTargetList.size() == 1) {
propertySet.addProperty(NullArgumentWarningProperty.MONOMORPHIC_CALL_SITE);
}
}
// Call to private method? In theory there should be only one possible
// target.
boolean privateCall = safeCallTargetSet.isEmpty() && dangerousCallTargetList.size() == 1
&& dangerousCallTargetList.get(0).getMethod().isPrivate();
String bugType;
int priority;
if (privateCall || invokeInstruction.getOpcode() == Constants.INVOKESTATIC
|| invokeInstruction.getOpcode() == Constants.INVOKESPECIAL) {
bugType = "NP_NULL_PARAM_DEREF_NONVIRTUAL";
priority = HIGH_PRIORITY;
} else if (safeCallTargetSet.isEmpty()) {
bugType = "NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS";
priority = NORMAL_PRIORITY;
} else {
return;
}
if (caught) {
priority++;
}
if (dangerousCallTargetList.size() > veryDangerousCallTargetList.size()) {
priority++;
} else {
propertySet.addProperty(NullArgumentWarningProperty.ACTUAL_PARAMETER_GUARANTEED_NULL);
}
XMethod calledFrom = XFactory.createXMethod(classContext.getJavaClass(), method);
if (safeCallToPrimateParseMethod(calledMethod, location)) {
return;
}
BugInstance warning = new BugInstance(this, bugType, priority).addClassAndMethod(classContext.getJavaClass(), method)
.addMethod(calledMethod).describe(MethodAnnotation.METHOD_CALLED).addSourceLine(classContext, method, location);
// boolean uncallable = false;
if (!AnalysisContext.currentXFactory().isCalledDirectlyOrIndirectly(calledFrom) && calledFrom.isPrivate()) {
propertySet.addProperty(GeneralWarningProperty.IN_UNCALLABLE_METHOD);
// uncallable = true;
}
// Check which params might be null