package com.linkedin.parseq.lambda; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; /** * An implementation of ASM ClassVisitor which analyses classes as they are loaded and identifies classes * generated for Lamda expressions. In addition, it infers details such as source code location, function call within * Lambda expression.. */ class LambdaClassLocator extends ClassVisitor { private String _className; private boolean _isLambdaClass; private SourcePointer _sourcePointer; private InferredOperation _inferredOperation; private ClassLoader _loader; LambdaClassLocator(int api, ClassLoader loader) { super(api); _loader = loader; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); _className = name.replace('/', '.'); _isLambdaClass = Util.isALambdaClassByName(name); if (_isLambdaClass) { _sourcePointer = SourcePointer.get().orElse(null); } } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); //ignore visiting method if this is not generated Lambda class if (!_isLambdaClass) { return mv; } //these two methods are present in generated byte code for lambda //ignoring as they don't provide any insights into details we are looking for if (name.equals("<init>") || name.equals("get$Lambda")) { return mv; } //parse generated lambda code to get details about operation return new LambdaMethodVisitor(api, mv, _sourcePointer, this::setInferredOperation, this::setLineNumber, _loader); } private void setInferredOperation(InferredOperation inferredOperation) { _inferredOperation = inferredOperation; } private void setLineNumber(int lineNumber) { _sourcePointer.setLineNumber(lineNumber); } boolean isLambdaClass() { return _isLambdaClass; } LambdaClassDescription getLambdaClassDescription() { return new LambdaClassDescription(_className, _sourcePointer, _inferredOperation); } }