CoverageBuilder.java revision 1b885c7bc666c215c3947ad4d12099273a5f533f
1/*******************************************************************************
2 * Copyright (c) 2009, 2010 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.analysis;
13
14import java.util.ArrayList;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.Map;
19
20import org.jacoco.core.data.ExecutionData;
21import org.jacoco.core.data.ExecutionDataStore;
22import org.jacoco.core.data.IClassStructureVisitor;
23import org.jacoco.core.data.IMethodStructureVisitor;
24import org.jacoco.core.data.IStructureVisitor;
25
26/**
27 * Builder for hierarchical {@link ICoverageNode} structures based on execution
28 * and structure information. The builder is constructed for a given
29 * {@link ExecutionDataStore} and then feed with class structure information
30 * through its {@link IStructureVisitor} interface. Afterwards the collected
31 * data can be obtained with {@link #getClasses()}, {@link #getSourceFiles()} or
32 * {@link #getBundle(String)}.
33 *
34 * @author Marc R. Hoffmann
35 * @version $qualified.bundle.version$
36 */
37public class CoverageBuilder implements IStructureVisitor {
38
39	private final ExecutionDataStore executionData;
40
41	private final StringPool stringPool;
42
43	private final Map<Long, ClassCoverage> classes;
44
45	private final Map<String, SourceFileCoverage> sourcefiles;
46
47	/**
48	 * Create a new builder based on the given execution data.
49	 *
50	 * @param executionData
51	 *            execution data
52	 */
53	public CoverageBuilder(final ExecutionDataStore executionData) {
54		this(executionData, new StringPool());
55	}
56
57	/**
58	 * Create a new builder based on the given execution data.
59	 *
60	 * @param executionData
61	 *            execution data
62	 * @param stringPool
63	 *            pool to optimize the number of {@link String} instances
64	 */
65	public CoverageBuilder(final ExecutionDataStore executionData,
66			final StringPool stringPool) {
67		this.executionData = executionData;
68		this.stringPool = stringPool;
69		this.classes = new HashMap<Long, ClassCoverage>();
70		this.sourcefiles = new HashMap<String, SourceFileCoverage>();
71	}
72
73	/**
74	 * Returns all class nodes currently contained in this builder.
75	 *
76	 * @return all class nodes
77	 */
78	public Collection<ClassCoverage> getClasses() {
79		return Collections.unmodifiableCollection(classes.values());
80	}
81
82	/**
83	 * Returns all source file nodes currently contained in this builder.
84	 *
85	 * @return all source file nodes
86	 */
87	public Collection<SourceFileCoverage> getSourceFiles() {
88		return Collections.unmodifiableCollection(sourcefiles.values());
89	}
90
91	/**
92	 * Creates a bundle from all nodes currently contained in this bundle.
93	 *
94	 * @param name
95	 *            Name of the bundle
96	 * @return bundle containing all classes and source files
97	 */
98	public BundleCoverage getBundle(final String name) {
99		return new BundleCoverage(name, classes.values(), sourcefiles.values(),
100				stringPool);
101	}
102
103	// === IStructureVisitor ===
104
105	public IClassStructureVisitor visitClassStructure(final long id) {
106		final ExecutionData data = executionData.get(id);
107		final boolean[] covered = data == null ? null : data.getData();
108		final Collection<MethodCoverage> methods = new ArrayList<MethodCoverage>();
109		return new IClassStructureVisitor() {
110			String name;
111			String signature;
112			String superName;
113			String[] interfaces;
114			String sourcename;
115
116			public void visit(final String name, final String signature,
117					final String superName, final String[] interfaces) {
118				this.name = stringPool.get(name);
119				this.signature = stringPool.get(signature);
120				this.superName = stringPool.get(superName);
121				this.interfaces = stringPool.get(interfaces);
122			}
123
124			public void visitSourceFile(final String name) {
125				sourcename = stringPool.get(name);
126			}
127
128			public IMethodStructureVisitor visitMethodStructure(
129					final String name, final String desc, final String signature) {
130				return createMethodVisitor(name, desc, signature, methods,
131						covered);
132			}
133
134			public void visitEnd() {
135				final ClassCoverage classData = new ClassCoverage(name, id,
136						signature, superName, interfaces, sourcename, methods);
137				// Only consider classes that actually contain code:
138				if (classData.getInstructionCounter().getTotalCount() > 0) {
139					classes.put(Long.valueOf(id), classData);
140					if (sourcename != null) {
141						final String packageName = stringPool.get(classData
142								.getPackageName());
143						final SourceFileCoverage sourceFile = getSourceFile(
144								sourcename, packageName);
145						sourceFile.increment(classData);
146					}
147				}
148			}
149		};
150	}
151
152	private IMethodStructureVisitor createMethodVisitor(final String name,
153			final String desc, final String signature,
154			final Collection<MethodCoverage> container, final boolean[] covered) {
155		final MethodCoverage method = new MethodCoverage(stringPool.get(name),
156				stringPool.get(desc), stringPool.get(signature));
157		return new IMethodStructureVisitor() {
158			public void block(final int id, final int instructions,
159					final int[] lineNumbers) {
160				final boolean c = covered == null ? false : covered[id];
161				method.addBlock(instructions, lineNumbers, c);
162			}
163
164			public void visitEnd() {
165				// Only consider methods that actually contain code:
166				if (method.getInstructionCounter().getTotalCount() > 0) {
167					container.add(method);
168				}
169			}
170		};
171	}
172
173	private SourceFileCoverage getSourceFile(final String filename,
174			final String packagename) {
175		final String key = packagename + '/' + filename;
176		SourceFileCoverage sourcefile = sourcefiles.get(key);
177		if (sourcefile == null) {
178			sourcefile = new SourceFileCoverage(filename, packagename);
179			sourcefiles.put(key, sourcefile);
180		}
181		return sourcefile;
182	}
183
184}
185