in jar-infer/jar-infer-lib/src/main/java/com/uber/nullaway/jarinfer/BytecodeAnnotator.java [146:190]
private static void annotateBytecode(
InputStream is,
OutputStream os,
MethodParamAnnotations nonnullParams,
MethodReturnAnnotations nullableReturns,
String nullableDesc,
String nonnullDesc)
throws IOException {
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(0);
ClassNode cn = new ClassNode(Opcodes.ASM7);
cr.accept(cn, 0);
String className = cn.name.replace('/', '.');
List<MethodNode> methods = cn.methods;
for (MethodNode method : methods) {
// Skip methods that already have nullability annotations anywhere in their signature
if (hasNullnessAnnotations(method)) {
continue;
}
boolean visible = annotationsShouldBeVisible(nullableDesc);
String methodSignature = className + "." + method.name + method.desc;
if (nullableReturns.contains(methodSignature)) {
// Add a @Nullable annotation on this method to indicate that the method can return null.
method.visitAnnotation(nullableDesc, visible);
LOG(debug, "DEBUG", "Added nullable return annotation for " + methodSignature);
}
Set<Integer> params = nonnullParams.get(methodSignature);
if (params != null) {
boolean isStatic = (method.access & Opcodes.ACC_STATIC) != 0;
for (Integer param : params) {
int paramNum = isStatic ? param : param - 1;
// Add a @Nonnull annotation on this parameter.
method.visitParameterAnnotation(paramNum, nonnullDesc, visible);
LOG(
debug,
"DEBUG",
"Added nonnull parameter annotation for #" + param + " in " + methodSignature);
}
}
}
cn.accept(cw);
os.write(cw.toByteArray());
}