LabelFlowAnalyzer.java revision e4a474ce30af55463d114b5c18c9b59eadbef00b
1/*******************************************************************************
2 * Copyright (c) 2009, 2014 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.jacoco.core.JaCoCo;
15import org.objectweb.asm.Handle;
16import org.objectweb.asm.Label;
17import org.objectweb.asm.MethodVisitor;
18import org.objectweb.asm.Opcodes;
19import org.objectweb.asm.tree.MethodNode;
20
21/**
22 * Method visitor to collect flow related information about the {@link Label}s
23 * within a class. It calculates the properties "multitarget" and "successor"
24 * that can afterwards be obtained via {@link LabelInfo}.
25 */
26public final class LabelFlowAnalyzer extends MethodVisitor {
27
28	/**
29	 * Marks all labels of the method with control flow information.
30	 *
31	 * @param method
32	 *            Method to mark labels
33	 */
34	public static void markLabels(final MethodNode method) {
35		method.instructions.accept(new LabelFlowAnalyzer());
36	}
37
38	/**
39	 * <code>true</code> if the current instruction is a potential successor of
40	 * the previous instruction. Accessible for testing.
41	 */
42	boolean successor = false;
43
44	/**
45	 * <code>true</code> for the very first instruction only. Accessible for
46	 * testing.
47	 */
48	boolean first = true;
49
50	/**
51	 * Create new instance.
52	 */
53	public LabelFlowAnalyzer() {
54		super(JaCoCo.ASM_API_VERSION);
55	}
56
57	@Override
58	public void visitJumpInsn(final int opcode, final Label label) {
59		LabelInfo.setTarget(label);
60		if (opcode == Opcodes.JSR) {
61			throw new AssertionError("Subroutines not supported.");
62		}
63		successor = opcode != Opcodes.GOTO;
64		first = false;
65	}
66
67	@Override
68	public void visitLabel(final Label label) {
69		if (first) {
70			LabelInfo.setTarget(label);
71		}
72		if (successor) {
73			LabelInfo.setSuccessor(label);
74		}
75	}
76
77	@Override
78	public void visitTableSwitchInsn(final int min, final int max,
79			final Label dflt, final Label... labels) {
80		visitSwitchInsn(dflt, labels);
81	}
82
83	@Override
84	public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
85			final Label[] labels) {
86		visitSwitchInsn(dflt, labels);
87	}
88
89	private void visitSwitchInsn(final Label dflt, final Label[] labels) {
90		LabelInfo.resetDone(dflt);
91		LabelInfo.resetDone(labels);
92		setTargetIfNotDone(dflt);
93		for (final Label l : labels) {
94			setTargetIfNotDone(l);
95		}
96		successor = false;
97		first = false;
98	}
99
100	private static void setTargetIfNotDone(final Label label) {
101		if (!LabelInfo.isDone(label)) {
102			LabelInfo.setTarget(label);
103			LabelInfo.setDone(label);
104		}
105	}
106
107	@Override
108	public void visitInsn(final int opcode) {
109		switch (opcode) {
110		case Opcodes.RET:
111			throw new AssertionError("Subroutines not supported.");
112		case Opcodes.IRETURN:
113		case Opcodes.LRETURN:
114		case Opcodes.FRETURN:
115		case Opcodes.DRETURN:
116		case Opcodes.ARETURN:
117		case Opcodes.RETURN:
118		case Opcodes.ATHROW:
119			successor = false;
120			break;
121		default:
122			successor = true;
123			break;
124		}
125		first = false;
126	}
127
128	@Override
129	public void visitIntInsn(final int opcode, final int operand) {
130		successor = true;
131		first = false;
132	}
133
134	@Override
135	public void visitVarInsn(final int opcode, final int var) {
136		successor = true;
137		first = false;
138	}
139
140	@Override
141	public void visitTypeInsn(final int opcode, final String type) {
142		successor = true;
143		first = false;
144	}
145
146	@Override
147	public void visitFieldInsn(final int opcode, final String owner,
148			final String name, final String desc) {
149		successor = true;
150		first = false;
151	}
152
153	@Override
154	public void visitMethodInsn(final int opcode, final String owner,
155			final String name, final String desc, final boolean itf) {
156		successor = true;
157		first = false;
158	}
159
160	@Override
161	public void visitInvokeDynamicInsn(final String name, final String desc,
162			final Handle bsm, final Object... bsmArgs) {
163		successor = true;
164		first = false;
165	}
166
167	@Override
168	public void visitLdcInsn(final Object cst) {
169		successor = true;
170		first = false;
171	}
172
173	@Override
174	public void visitIincInsn(final int var, final int increment) {
175		successor = true;
176		first = false;
177	}
178
179	@Override
180	public void visitMultiANewArrayInsn(final String desc, final int dims) {
181		successor = true;
182		first = false;
183	}
184
185}
186