1 /******************************************************************************* 2 * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors 3 * This program and the accompanying materials are made available under 4 * the terms of the Eclipse Public License 2.0 which is available at 5 * http://www.eclipse.org/legal/epl-2.0 6 * 7 * SPDX-License-Identifier: EPL-2.0 8 * 9 * Contributors: 10 * Marc R. Hoffmann - initial API and implementation 11 * 12 *******************************************************************************/ 13 package org.jacoco.core.internal.flow; 14 15 import org.jacoco.core.internal.instr.InstrSupport; 16 import org.objectweb.asm.ClassVisitor; 17 import org.objectweb.asm.MethodVisitor; 18 import org.objectweb.asm.commons.AnalyzerAdapter; 19 20 /** 21 * A {@link org.objectweb.asm.ClassVisitor} that calculates probes for every 22 * method. 23 */ 24 public class ClassProbesAdapter extends ClassVisitor 25 implements IProbeIdGenerator { 26 27 private static final MethodProbesVisitor EMPTY_METHOD_PROBES_VISITOR = new MethodProbesVisitor() { 28 }; 29 30 private final ClassProbesVisitor cv; 31 32 private final boolean trackFrames; 33 34 private int counter = 0; 35 36 private String name; 37 38 /** 39 * Creates a new adapter that delegates to the given visitor. 40 * 41 * @param cv 42 * instance to delegate to 43 * @param trackFrames 44 * if <code>true</code> stackmap frames are tracked and provided 45 */ ClassProbesAdapter(final ClassProbesVisitor cv, final boolean trackFrames)46 public ClassProbesAdapter(final ClassProbesVisitor cv, 47 final boolean trackFrames) { 48 super(InstrSupport.ASM_API_VERSION, cv); 49 this.cv = cv; 50 this.trackFrames = trackFrames; 51 } 52 53 @Override visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)54 public void visit(final int version, final int access, final String name, 55 final String signature, final String superName, 56 final String[] interfaces) { 57 this.name = name; 58 super.visit(version, access, name, signature, superName, interfaces); 59 } 60 61 @Override visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions)62 public final MethodVisitor visitMethod(final int access, final String name, 63 final String desc, final String signature, 64 final String[] exceptions) { 65 final MethodProbesVisitor methodProbes; 66 final MethodProbesVisitor mv = cv.visitMethod(access, name, desc, 67 signature, exceptions); 68 if (mv == null) { 69 // We need to visit the method in any case, otherwise probe ids 70 // are not reproducible 71 methodProbes = EMPTY_METHOD_PROBES_VISITOR; 72 } else { 73 methodProbes = mv; 74 } 75 return new MethodSanitizer(null, access, name, desc, signature, 76 exceptions) { 77 78 @Override 79 public void visitEnd() { 80 super.visitEnd(); 81 LabelFlowAnalyzer.markLabels(this); 82 final MethodProbesAdapter probesAdapter = new MethodProbesAdapter( 83 methodProbes, ClassProbesAdapter.this); 84 if (trackFrames) { 85 final AnalyzerAdapter analyzer = new AnalyzerAdapter( 86 ClassProbesAdapter.this.name, access, name, desc, 87 probesAdapter); 88 probesAdapter.setAnalyzer(analyzer); 89 methodProbes.accept(this, analyzer); 90 } else { 91 methodProbes.accept(this, probesAdapter); 92 } 93 } 94 }; 95 } 96 97 @Override 98 public void visitEnd() { 99 cv.visitTotalProbeCount(counter); 100 super.visitEnd(); 101 } 102 103 // === IProbeIdGenerator === 104 105 public int nextId() { 106 return counter++; 107 } 108 109 } 110