CoverageBuilder.java
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 0.4.1.20101007204400
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}