LabelFlowAnalyzer.java revision 456cb13baa8f60eef812864ed5bbe3c5f858cdbb
1/*******************************************************************************
2 * Copyright (c) 2009, 2011 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.internal.flow;
13
14import org.objectweb.asm.AnnotationVisitor;
15import org.objectweb.asm.Attribute;
16import org.objectweb.asm.Label;
17import org.objectweb.asm.MethodVisitor;
18import org.objectweb.asm.Opcodes;
19
20/**
21 * Method visitor to collect flow related information about the {@link Label}s
22 * within a class. It calculates the properties "multitarget" and "successor"
23 * that can afterwards be obtained via {@link LabelInfo}.
24 */
25public final class LabelFlowAnalyzer implements MethodVisitor {
26
27	/**
28	 * <code>true</code> if the current instruction is a potential successor of
29	 * the previous instruction. Accessible for testing.
30	 */
31	boolean successor = false;
32
33	/**
34	 * <code>true</code> for the very first instruction only. Accessible for
35	 * testing.
36	 */
37	boolean first = true;
38
39	public void visitTryCatchBlock(final Label start, final Label end,
40			final Label handler, final String type) {
41		// Enforce probes at the beginning and end of the block:
42		LabelInfo.setTarget(start);
43		LabelInfo.setTarget(handler);
44	}
45
46	public void visitJumpInsn(final int opcode, final Label label) {
47		LabelInfo.setTarget(label);
48		if (opcode == Opcodes.JSR) {
49			throw new AssertionError("Subroutines not supported.");
50		}
51		successor = opcode != Opcodes.GOTO;
52		first = false;
53	}
54
55	public void visitLabel(final Label label) {
56		if (first) {
57			LabelInfo.setTarget(label);
58		}
59		if (successor) {
60			LabelInfo.setSuccessor(label);
61		}
62	}
63
64	public void visitTableSwitchInsn(final int min, final int max,
65			final Label dflt, final Label[] labels) {
66		visitSwitchInsn(dflt, labels);
67	}
68
69	public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
70			final Label[] labels) {
71		visitSwitchInsn(dflt, labels);
72	}
73
74	private void visitSwitchInsn(final Label dflt, final Label[] labels) {
75		LabelInfo.resetDone(dflt);
76		LabelInfo.resetDone(labels);
77		setTargetIfNotDone(dflt);
78		for (final Label l : labels) {
79			setTargetIfNotDone(l);
80		}
81		successor = false;
82		first = false;
83	}
84
85	private static void setTargetIfNotDone(final Label label) {
86		if (!LabelInfo.isDone(label)) {
87			LabelInfo.setTarget(label);
88			LabelInfo.setDone(label);
89		}
90	}
91
92	public void visitInsn(final int opcode) {
93		switch (opcode) {
94		case Opcodes.RET:
95			throw new AssertionError("Subroutines not supported.");
96		case Opcodes.IRETURN:
97		case Opcodes.LRETURN:
98		case Opcodes.FRETURN:
99		case Opcodes.DRETURN:
100		case Opcodes.ARETURN:
101		case Opcodes.RETURN:
102		case Opcodes.ATHROW:
103			successor = false;
104			break;
105		default:
106			successor = true;
107			break;
108		}
109		first = false;
110	}
111
112	public void visitIntInsn(final int opcode, final int operand) {
113		successor = true;
114		first = false;
115	}
116
117	public void visitVarInsn(final int opcode, final int var) {
118		successor = true;
119		first = false;
120	}
121
122	public void visitTypeInsn(final int opcode, final String type) {
123		successor = true;
124		first = false;
125	}
126
127	public void visitFieldInsn(final int opcode, final String owner,
128			final String name, final String desc) {
129		successor = true;
130		first = false;
131	}
132
133	public void visitMethodInsn(final int opcode, final String owner,
134			final String name, final String desc) {
135		successor = true;
136		first = false;
137	}
138
139	public void visitLdcInsn(final Object cst) {
140		successor = true;
141		first = false;
142	}
143
144	public void visitIincInsn(final int var, final int increment) {
145		successor = true;
146		first = false;
147	}
148
149	public void visitMultiANewArrayInsn(final String desc, final int dims) {
150		successor = true;
151		first = false;
152	}
153
154	// Not relevant:
155
156	public void visitAttribute(final Attribute attr) {
157	}
158
159	public AnnotationVisitor visitAnnotationDefault() {
160		return null;
161	}
162
163	public AnnotationVisitor visitAnnotation(final String desc,
164			final boolean visible) {
165		return null;
166	}
167
168	public AnnotationVisitor visitParameterAnnotation(final int parameter,
169			final String desc, final boolean visible) {
170		return null;
171	}
172
173	public void visitLocalVariable(final String name, final String desc,
174			final String signature, final Label start, final Label end,
175			final int index) {
176	}
177
178	public void visitCode() {
179	}
180
181	public void visitLineNumber(final int line, final Label start) {
182	}
183
184	public void visitFrame(final int type, final int nLocal,
185			final Object[] local, final int nStack, final Object[] stack) {
186	}
187
188	public void visitMaxs(final int maxStack, final int maxLocals) {
189	}
190
191	public void visitEnd() {
192	}
193
194}
195