• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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