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