diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2012-08-30 22:13:04 +0600 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2012-08-30 22:13:04 +0600 |
commit | e69ba4dbb015949c5d84ba7bbb0b53efac28bb23 (patch) | |
tree | 44cbe6d78216fcb3c37c0aca1dc7ed3fc09906fa /org.jacoco.core/src/org/jacoco/core | |
parent | a888d873ac20357a4a11029bc84c5c4b48e394a3 (diff) | |
download | platform_external_jacoco-e69ba4dbb015949c5d84ba7bbb0b53efac28bb23.tar.gz platform_external_jacoco-e69ba4dbb015949c5d84ba7bbb0b53efac28bb23.tar.bz2 platform_external_jacoco-e69ba4dbb015949c5d84ba7bbb0b53efac28bb23.zip |
Fix EOLs
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core')
60 files changed, 6706 insertions, 6706 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/JaCoCo.java b/org.jacoco.core/src/org/jacoco/core/JaCoCo.java index 83d8769b..c79fd1d2 100644 --- a/org.jacoco.core/src/org/jacoco/core/JaCoCo.java +++ b/org.jacoco.core/src/org/jacoco/core/JaCoCo.java @@ -1,37 +1,37 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core;
-
-import java.util.ResourceBundle;
-
-/**
- * Static Meta information about JaCoCo.
- */
-public final class JaCoCo {
-
- /** Qualified build version of the JaCoCo core library. */
- public static final String VERSION;
-
- /** Absolute URL of the current JaCoCo home page */
- public static final String HOMEURL;
-
- static {
- final ResourceBundle bundle = ResourceBundle
- .getBundle("org.jacoco.core.jacoco");
- VERSION = bundle.getString("VERSION");
- HOMEURL = bundle.getString("HOMEURL");
- }
-
- private JaCoCo() {
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core; + +import java.util.ResourceBundle; + +/** + * Static Meta information about JaCoCo. + */ +public final class JaCoCo { + + /** Qualified build version of the JaCoCo core library. */ + public static final String VERSION; + + /** Absolute URL of the current JaCoCo home page */ + public static final String HOMEURL; + + static { + final ResourceBundle bundle = ResourceBundle + .getBundle("org.jacoco.core.jacoco"); + VERSION = bundle.getString("VERSION"); + HOMEURL = bundle.getString("HOMEURL"); + } + + private JaCoCo() { + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java index 1b351d6d..b6400bcf 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -1,214 +1,214 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.StringTokenizer;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import org.jacoco.core.data.ExecutionData;
-import org.jacoco.core.data.ExecutionDataStore;
-import org.jacoco.core.internal.analysis.ClassAnalyzer;
-import org.jacoco.core.internal.analysis.ContentTypeDetector;
-import org.jacoco.core.internal.analysis.StringPool;
-import org.jacoco.core.internal.data.CRC64;
-import org.jacoco.core.internal.flow.ClassProbesAdapter;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-
-/**
- * An {@link Analyzer} instance processes a set of Java class files and
- * calculates coverage data for them. For each class file the result is reported
- * to a given {@link ICoverageVisitor} instance. In addition the
- * {@link Analyzer} requires a {@link ExecutionDataStore} instance that holds
- * the execution data for the classes to analyze. The {@link Analyzer} offers
- * several methods to analyze classes from a variety of sources.
- */
-public class Analyzer {
-
- private final ExecutionDataStore executionData;
-
- private final ICoverageVisitor coverageVisitor;
-
- private final StringPool stringPool;
-
- /**
- * Creates a new analyzer reporting to the given output.
- *
- * @param executionData
- * execution data
- * @param coverageVisitor
- * the output instance that will coverage data for every analyzed
- * class
- */
- public Analyzer(final ExecutionDataStore executionData,
- final ICoverageVisitor coverageVisitor) {
- this.executionData = executionData;
- this.coverageVisitor = coverageVisitor;
- this.stringPool = new StringPool();
- }
-
- /**
- * Creates an ASM class visitor for analysis.
- *
- * @param classid
- * id of the class calculated with {@link CRC64}
- * @return ASM visitor to write class definition to
- */
- private ClassVisitor createAnalyzingVisitor(final long classid) {
- final ExecutionData data = executionData.get(classid);
- final boolean[] classExec = data == null ? null : data.getData();
- final ClassAnalyzer analyzer = new ClassAnalyzer(classid, classExec,
- stringPool) {
- @Override
- public void visitEnd() {
- super.visitEnd();
- coverageVisitor.visitCoverage(getCoverage());
- }
- };
- return new ClassProbesAdapter(analyzer);
- }
-
- /**
- * Analyzes the class given as a ASM reader.
- *
- * @param reader
- * reader with class definitions
- */
- public void analyzeClass(final ClassReader reader) {
- final ClassVisitor visitor = createAnalyzingVisitor(CRC64
- .checksum(reader.b));
- reader.accept(visitor, 0);
- }
-
- /**
- * Analyzes the class definition from a given in-memory buffer.
- *
- * @param buffer
- * class definitions
- */
- public void analyzeClass(final byte[] buffer) {
- analyzeClass(new ClassReader(buffer));
- }
-
- /**
- * Analyzes the class definition from a given input stream.
- *
- * @param input
- * stream to read class definition from
- * @throws IOException
- */
- public void analyzeClass(final InputStream input) throws IOException {
- analyzeClass(new ClassReader(input));
- }
-
- /**
- * Analyzes all classes contained in the ZIP archive (jar, war, ear, etc.)
- * given as an input stream. Contained archives are read recursively.
- *
- * @param input
- * ZIP archive data
- * @return number of class files found
- * @throws IOException
- */
- public int analyzeArchive(final InputStream input) throws IOException {
- final ZipInputStream zip = new ZipInputStream(input);
- int count = 0;
- while (true) {
- final ZipEntry entry = zip.getNextEntry();
- if (entry == null) {
- break;
- }
- count += analyzeAll(zip);
- }
- return count;
- }
-
- /**
- * Analyzes all classes found in the given input stream. The input stream
- * may either represent a single class file or a ZIP archive that is
- * searched recursively for class files. All other content types are
- * ignored.
- *
- * @param input
- * input data
- * @return number of class files found
- * @throws IOException
- */
- public int analyzeAll(final InputStream input) throws IOException {
- final ContentTypeDetector detector = new ContentTypeDetector(input);
- switch (detector.getType()) {
- case ContentTypeDetector.CLASSFILE:
- analyzeClass(detector.getInputStream());
- return 1;
- case ContentTypeDetector.ZIPFILE:
- return analyzeArchive(detector.getInputStream());
- default:
- return 0;
- }
- }
-
- /**
- * Analyzes all class files contained in the given file or folder. Class
- * files as well as ZIP files are considered. Folders are searched
- * recursively.
- *
- * @param file
- * file or folder to look for class files
- * @return number of class files found
- * @throws IOException
- */
- public int analyzeAll(final File file) throws IOException {
- int count = 0;
- if (file.isDirectory()) {
- for (final File f : file.listFiles()) {
- count += analyzeAll(f);
- }
- } else {
- final InputStream in = new FileInputStream(file);
- try {
- count += analyzeAll(in);
- } finally {
- in.close();
- }
- }
- return count;
- }
-
- /**
- * Analyzes all classes from the given class path. Directories containing
- * class files as well as archive files are considered.
- *
- * @param path
- * path definition
- * @param basedir
- * optional base directory, if <code>null</code> the current
- * working directory is used as the base for relative path
- * entries
- * @return number of class files found
- * @throws IOException
- */
- public int analyzeAll(final String path, final File basedir)
- throws IOException {
- int count = 0;
- final StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
- while (st.hasMoreTokens()) {
- count += analyzeAll(new File(basedir, st.nextToken()));
- }
- return count;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.StringTokenizer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.internal.analysis.ClassAnalyzer; +import org.jacoco.core.internal.analysis.ContentTypeDetector; +import org.jacoco.core.internal.analysis.StringPool; +import org.jacoco.core.internal.data.CRC64; +import org.jacoco.core.internal.flow.ClassProbesAdapter; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; + +/** + * An {@link Analyzer} instance processes a set of Java class files and + * calculates coverage data for them. For each class file the result is reported + * to a given {@link ICoverageVisitor} instance. In addition the + * {@link Analyzer} requires a {@link ExecutionDataStore} instance that holds + * the execution data for the classes to analyze. The {@link Analyzer} offers + * several methods to analyze classes from a variety of sources. + */ +public class Analyzer { + + private final ExecutionDataStore executionData; + + private final ICoverageVisitor coverageVisitor; + + private final StringPool stringPool; + + /** + * Creates a new analyzer reporting to the given output. + * + * @param executionData + * execution data + * @param coverageVisitor + * the output instance that will coverage data for every analyzed + * class + */ + public Analyzer(final ExecutionDataStore executionData, + final ICoverageVisitor coverageVisitor) { + this.executionData = executionData; + this.coverageVisitor = coverageVisitor; + this.stringPool = new StringPool(); + } + + /** + * Creates an ASM class visitor for analysis. + * + * @param classid + * id of the class calculated with {@link CRC64} + * @return ASM visitor to write class definition to + */ + private ClassVisitor createAnalyzingVisitor(final long classid) { + final ExecutionData data = executionData.get(classid); + final boolean[] classExec = data == null ? null : data.getData(); + final ClassAnalyzer analyzer = new ClassAnalyzer(classid, classExec, + stringPool) { + @Override + public void visitEnd() { + super.visitEnd(); + coverageVisitor.visitCoverage(getCoverage()); + } + }; + return new ClassProbesAdapter(analyzer); + } + + /** + * Analyzes the class given as a ASM reader. + * + * @param reader + * reader with class definitions + */ + public void analyzeClass(final ClassReader reader) { + final ClassVisitor visitor = createAnalyzingVisitor(CRC64 + .checksum(reader.b)); + reader.accept(visitor, 0); + } + + /** + * Analyzes the class definition from a given in-memory buffer. + * + * @param buffer + * class definitions + */ + public void analyzeClass(final byte[] buffer) { + analyzeClass(new ClassReader(buffer)); + } + + /** + * Analyzes the class definition from a given input stream. + * + * @param input + * stream to read class definition from + * @throws IOException + */ + public void analyzeClass(final InputStream input) throws IOException { + analyzeClass(new ClassReader(input)); + } + + /** + * Analyzes all classes contained in the ZIP archive (jar, war, ear, etc.) + * given as an input stream. Contained archives are read recursively. + * + * @param input + * ZIP archive data + * @return number of class files found + * @throws IOException + */ + public int analyzeArchive(final InputStream input) throws IOException { + final ZipInputStream zip = new ZipInputStream(input); + int count = 0; + while (true) { + final ZipEntry entry = zip.getNextEntry(); + if (entry == null) { + break; + } + count += analyzeAll(zip); + } + return count; + } + + /** + * Analyzes all classes found in the given input stream. The input stream + * may either represent a single class file or a ZIP archive that is + * searched recursively for class files. All other content types are + * ignored. + * + * @param input + * input data + * @return number of class files found + * @throws IOException + */ + public int analyzeAll(final InputStream input) throws IOException { + final ContentTypeDetector detector = new ContentTypeDetector(input); + switch (detector.getType()) { + case ContentTypeDetector.CLASSFILE: + analyzeClass(detector.getInputStream()); + return 1; + case ContentTypeDetector.ZIPFILE: + return analyzeArchive(detector.getInputStream()); + default: + return 0; + } + } + + /** + * Analyzes all class files contained in the given file or folder. Class + * files as well as ZIP files are considered. Folders are searched + * recursively. + * + * @param file + * file or folder to look for class files + * @return number of class files found + * @throws IOException + */ + public int analyzeAll(final File file) throws IOException { + int count = 0; + if (file.isDirectory()) { + for (final File f : file.listFiles()) { + count += analyzeAll(f); + } + } else { + final InputStream in = new FileInputStream(file); + try { + count += analyzeAll(in); + } finally { + in.close(); + } + } + return count; + } + + /** + * Analyzes all classes from the given class path. Directories containing + * class files as well as archive files are considered. + * + * @param path + * path definition + * @param basedir + * optional base directory, if <code>null</code> the current + * working directory is used as the base for relative path + * entries + * @return number of class files found + * @throws IOException + */ + public int analyzeAll(final String path, final File basedir) + throws IOException { + int count = 0; + final StringTokenizer st = new StringTokenizer(path, File.pathSeparator); + while (st.hasMoreTokens()) { + count += analyzeAll(new File(basedir, st.nextToken())); + } + return count; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java b/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java index 82c953ae..7469deee 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java @@ -1,117 +1,117 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.io.Serializable;
-import java.util.Comparator;
-
-import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
-
-/**
- * Collection of comparators to compare {@link ICounter} objects by different
- * criteria.
- */
-public abstract class CounterComparator implements Comparator<ICounter>,
- Serializable {
-
- private static final long serialVersionUID = -3777463066252746748L;
-
- /**
- * Compares the absolute number of total items.
- */
- public static final CounterComparator TOTALITEMS = new CounterComparator() {
-
- private static final long serialVersionUID = 8824120489765405662L;
-
- public int compare(final ICounter c1, final ICounter c2) {
- return c1.getTotalCount() - c2.getTotalCount();
- }
- };
-
- /**
- * Compares the absolute number of covered items.
- */
- public static final CounterComparator COVEREDITEMS = new CounterComparator() {
-
- private static final long serialVersionUID = 1L;
-
- public int compare(final ICounter c1, final ICounter c2) {
- return c1.getCoveredCount() - c2.getCoveredCount();
- }
- };
-
- /**
- * Compares the absolute number of missed items.
- */
- public static final CounterComparator MISSEDITEMS = new CounterComparator() {
-
- private static final long serialVersionUID = -2991039557556551206L;
-
- public int compare(final ICounter c1, final ICounter c2) {
- return c1.getMissedCount() - c2.getMissedCount();
- }
- };
-
- /**
- * Compares the ratio of covered items.
- */
- public static final CounterComparator COVEREDRATIO = new CounterComparator() {
-
- private static final long serialVersionUID = 7897690710299613918L;
-
- public int compare(final ICounter c1, final ICounter c2) {
- return Double.compare(c1.getCoveredRatio(), c2.getCoveredRatio());
- }
- };
-
- /**
- * Compares the ratio of missed items.
- */
- public static final CounterComparator MISSEDRATIO = new CounterComparator() {
-
- private static final long serialVersionUID = -5014193668057469357L;
-
- public int compare(final ICounter c1, final ICounter c2) {
- return Double.compare(c1.getMissedRatio(), c2.getMissedRatio());
- }
- };
-
- /**
- * Creates a new version of this comparator that sorts in reverse order.
- *
- * @return reverse comparator
- */
- public CounterComparator reverse() {
- final CounterComparator original = this;
- return new CounterComparator() {
-
- private static final long serialVersionUID = 7703349549732801967L;
-
- public int compare(final ICounter o1, final ICounter o2) {
- return original.compare(o2, o1);
- }
- };
- }
-
- /**
- * Creates a new comparator for {@link ICoverageNode} counters of the given
- * entity based on this counter sorting criteria.
- *
- * @param entity
- * counter entity to sort on
- * @return comparator for {@link ICoverageNode} elements
- */
- public NodeComparator on(final CounterEntity entity) {
- return new NodeComparator(this, entity);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.io.Serializable; +import java.util.Comparator; + +import org.jacoco.core.analysis.ICoverageNode.CounterEntity; + +/** + * Collection of comparators to compare {@link ICounter} objects by different + * criteria. + */ +public abstract class CounterComparator implements Comparator<ICounter>, + Serializable { + + private static final long serialVersionUID = -3777463066252746748L; + + /** + * Compares the absolute number of total items. + */ + public static final CounterComparator TOTALITEMS = new CounterComparator() { + + private static final long serialVersionUID = 8824120489765405662L; + + public int compare(final ICounter c1, final ICounter c2) { + return c1.getTotalCount() - c2.getTotalCount(); + } + }; + + /** + * Compares the absolute number of covered items. + */ + public static final CounterComparator COVEREDITEMS = new CounterComparator() { + + private static final long serialVersionUID = 1L; + + public int compare(final ICounter c1, final ICounter c2) { + return c1.getCoveredCount() - c2.getCoveredCount(); + } + }; + + /** + * Compares the absolute number of missed items. + */ + public static final CounterComparator MISSEDITEMS = new CounterComparator() { + + private static final long serialVersionUID = -2991039557556551206L; + + public int compare(final ICounter c1, final ICounter c2) { + return c1.getMissedCount() - c2.getMissedCount(); + } + }; + + /** + * Compares the ratio of covered items. + */ + public static final CounterComparator COVEREDRATIO = new CounterComparator() { + + private static final long serialVersionUID = 7897690710299613918L; + + public int compare(final ICounter c1, final ICounter c2) { + return Double.compare(c1.getCoveredRatio(), c2.getCoveredRatio()); + } + }; + + /** + * Compares the ratio of missed items. + */ + public static final CounterComparator MISSEDRATIO = new CounterComparator() { + + private static final long serialVersionUID = -5014193668057469357L; + + public int compare(final ICounter c1, final ICounter c2) { + return Double.compare(c1.getMissedRatio(), c2.getMissedRatio()); + } + }; + + /** + * Creates a new version of this comparator that sorts in reverse order. + * + * @return reverse comparator + */ + public CounterComparator reverse() { + final CounterComparator original = this; + return new CounterComparator() { + + private static final long serialVersionUID = 7703349549732801967L; + + public int compare(final ICounter o1, final ICounter o2) { + return original.compare(o2, o1); + } + }; + } + + /** + * Creates a new comparator for {@link ICoverageNode} counters of the given + * entity based on this counter sorting criteria. + * + * @param entity + * counter entity to sort on + * @return comparator for {@link ICoverageNode} elements + */ + public NodeComparator on(final CounterEntity entity) { + return new NodeComparator(this, entity); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java index 38ea6594..bbf6c0b2 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java @@ -1,113 +1,113 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.jacoco.core.internal.analysis.BundleCoverageImpl;
-import org.jacoco.core.internal.analysis.SourceFileCoverageImpl;
-
-/**
- * Builder for hierarchical {@link ICoverageNode} structures from single
- * {@link IClassCoverage} nodes. The nodes are feed into the builder through its
- * {@link ICoverageVisitor} interface. Afterwards the aggregated data can be
- * obtained with {@link #getClasses()}, {@link #getSourceFiles()} or
- * {@link #getBundle(String)} in the following hierarchy:
- *
- * <pre>
- * {@link IBundleCoverage}
- * +-- {@link IPackageCoverage}*
- * +-- {@link IClassCoverage}*
- * +-- {@link ISourceFileCoverage}*
- * </pre>
- */
-public class CoverageBuilder implements ICoverageVisitor {
-
- private final Map<String, IClassCoverage> classes;
-
- private final Map<String, ISourceFileCoverage> sourcefiles;
-
- /**
- * Create a new builder.
- *
- */
- public CoverageBuilder() {
- this.classes = new HashMap<String, IClassCoverage>();
- this.sourcefiles = new HashMap<String, ISourceFileCoverage>();
- }
-
- /**
- * Returns all class nodes currently contained in this builder.
- *
- * @return all class nodes
- */
- public Collection<IClassCoverage> getClasses() {
- return Collections.unmodifiableCollection(classes.values());
- }
-
- /**
- * Returns all source file nodes currently contained in this builder.
- *
- * @return all source file nodes
- */
- public Collection<ISourceFileCoverage> getSourceFiles() {
- return Collections.unmodifiableCollection(sourcefiles.values());
- }
-
- /**
- * Creates a bundle from all nodes currently contained in this bundle.
- *
- * @param name
- * Name of the bundle
- * @return bundle containing all classes and source files
- */
- public IBundleCoverage getBundle(final String name) {
- return new BundleCoverageImpl(name, classes.values(),
- sourcefiles.values());
- }
-
- // === IStructureVisitor ===
-
- public void visitCoverage(final IClassCoverage coverage) {
- // Only consider classes that actually contain code:
- if (coverage.getInstructionCounter().getTotalCount() > 0) {
- final String name = coverage.getName();
- final IClassCoverage dup = classes.put(name, coverage);
- if (dup != null && dup.getId() != coverage.getId()) {
- throw new IllegalStateException(
- "Can't add different class with same name: " + name);
- }
- final String source = coverage.getSourceFileName();
- if (source != null) {
- final SourceFileCoverageImpl sourceFile = getSourceFile(source,
- coverage.getPackageName());
- sourceFile.increment(coverage);
- }
- }
- }
-
- private SourceFileCoverageImpl getSourceFile(final String filename,
- final String packagename) {
- final String key = packagename + '/' + filename;
- SourceFileCoverageImpl sourcefile = (SourceFileCoverageImpl) sourcefiles
- .get(key);
- if (sourcefile == null) {
- sourcefile = new SourceFileCoverageImpl(filename, packagename);
- sourcefiles.put(key, sourcefile);
- }
- return sourcefile;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.jacoco.core.internal.analysis.BundleCoverageImpl; +import org.jacoco.core.internal.analysis.SourceFileCoverageImpl; + +/** + * Builder for hierarchical {@link ICoverageNode} structures from single + * {@link IClassCoverage} nodes. The nodes are feed into the builder through its + * {@link ICoverageVisitor} interface. Afterwards the aggregated data can be + * obtained with {@link #getClasses()}, {@link #getSourceFiles()} or + * {@link #getBundle(String)} in the following hierarchy: + * + * <pre> + * {@link IBundleCoverage} + * +-- {@link IPackageCoverage}* + * +-- {@link IClassCoverage}* + * +-- {@link ISourceFileCoverage}* + * </pre> + */ +public class CoverageBuilder implements ICoverageVisitor { + + private final Map<String, IClassCoverage> classes; + + private final Map<String, ISourceFileCoverage> sourcefiles; + + /** + * Create a new builder. + * + */ + public CoverageBuilder() { + this.classes = new HashMap<String, IClassCoverage>(); + this.sourcefiles = new HashMap<String, ISourceFileCoverage>(); + } + + /** + * Returns all class nodes currently contained in this builder. + * + * @return all class nodes + */ + public Collection<IClassCoverage> getClasses() { + return Collections.unmodifiableCollection(classes.values()); + } + + /** + * Returns all source file nodes currently contained in this builder. + * + * @return all source file nodes + */ + public Collection<ISourceFileCoverage> getSourceFiles() { + return Collections.unmodifiableCollection(sourcefiles.values()); + } + + /** + * Creates a bundle from all nodes currently contained in this bundle. + * + * @param name + * Name of the bundle + * @return bundle containing all classes and source files + */ + public IBundleCoverage getBundle(final String name) { + return new BundleCoverageImpl(name, classes.values(), + sourcefiles.values()); + } + + // === IStructureVisitor === + + public void visitCoverage(final IClassCoverage coverage) { + // Only consider classes that actually contain code: + if (coverage.getInstructionCounter().getTotalCount() > 0) { + final String name = coverage.getName(); + final IClassCoverage dup = classes.put(name, coverage); + if (dup != null && dup.getId() != coverage.getId()) { + throw new IllegalStateException( + "Can't add different class with same name: " + name); + } + final String source = coverage.getSourceFileName(); + if (source != null) { + final SourceFileCoverageImpl sourceFile = getSourceFile(source, + coverage.getPackageName()); + sourceFile.increment(coverage); + } + } + } + + private SourceFileCoverageImpl getSourceFile(final String filename, + final String packagename) { + final String key = packagename + '/' + filename; + SourceFileCoverageImpl sourcefile = (SourceFileCoverageImpl) sourcefiles + .get(key); + if (sourcefile == null) { + sourcefile = new SourceFileCoverageImpl(filename, packagename); + sourcefiles.put(key, sourcefile); + } + return sourcefile; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java index 4ef59f16..30030470 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java @@ -1,164 +1,164 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.util.Collection;
-
-import org.jacoco.core.internal.analysis.CounterImpl;
-
-/**
- * Base implementation for coverage data nodes.
- */
-public class CoverageNodeImpl implements ICoverageNode {
-
- private final ElementType elementType;
-
- private final String name;
-
- /** Counter for branches. */
- protected CounterImpl branchCounter;
-
- /** Counter for instructions. */
- protected CounterImpl instructionCounter;
-
- /** Counter for lines */
- protected CounterImpl lineCounter;
-
- /** Counter for complexity. */
- protected CounterImpl complexityCounter;
-
- /** Counter for methods. */
- protected CounterImpl methodCounter;
-
- /** Counter for classes. */
- protected CounterImpl classCounter;
-
- /**
- * Creates a new coverage data node.
- *
- * @param elementType
- * type of the element represented by this instance
- * @param name
- * name of this node
- */
- public CoverageNodeImpl(final ElementType elementType, final String name) {
- this.elementType = elementType;
- this.name = name;
- this.branchCounter = CounterImpl.COUNTER_0_0;
- this.instructionCounter = CounterImpl.COUNTER_0_0;
- this.complexityCounter = CounterImpl.COUNTER_0_0;
- this.methodCounter = CounterImpl.COUNTER_0_0;
- this.classCounter = CounterImpl.COUNTER_0_0;
- this.lineCounter = CounterImpl.COUNTER_0_0;
- }
-
- /**
- * Increments the counters by the values given by another element.
- *
- * @param child
- * counters to add
- */
- public void increment(final ICoverageNode child) {
- instructionCounter = instructionCounter.increment(child
- .getInstructionCounter());
- branchCounter = branchCounter.increment(child.getBranchCounter());
- lineCounter = lineCounter.increment(child.getLineCounter());
- complexityCounter = complexityCounter.increment(child
- .getComplexityCounter());
- methodCounter = methodCounter.increment(child.getMethodCounter());
- classCounter = classCounter.increment(child.getClassCounter());
- }
-
- /**
- * Increments the counters by the values given by the collection of
- * elements.
- *
- * @param children
- * list of nodes, which counters will be added to this node
- */
- public void increment(final Collection<? extends ICoverageNode> children) {
- for (final ICoverageNode child : children) {
- increment(child);
- }
- }
-
- // === ICoverageDataNode ===
-
- public ElementType getElementType() {
- return elementType;
- }
-
- public String getName() {
- return name;
- }
-
- public ICounter getInstructionCounter() {
- return instructionCounter;
- }
-
- public ICounter getBranchCounter() {
- return branchCounter;
- }
-
- public ICounter getLineCounter() {
- return lineCounter;
- }
-
- public ICounter getComplexityCounter() {
- return complexityCounter;
- }
-
- public ICounter getMethodCounter() {
- return methodCounter;
- }
-
- public ICounter getClassCounter() {
- return classCounter;
- }
-
- public ICounter getCounter(final CounterEntity entity) {
- switch (entity) {
- case INSTRUCTION:
- return getInstructionCounter();
- case BRANCH:
- return getBranchCounter();
- case LINE:
- return getLineCounter();
- case COMPLEXITY:
- return getComplexityCounter();
- case METHOD:
- return getMethodCounter();
- case CLASS:
- return getClassCounter();
- }
- throw new AssertionError(entity);
- }
-
- public ICoverageNode getPlainCopy() {
- final CoverageNodeImpl copy = new CoverageNodeImpl(elementType, name);
- copy.instructionCounter = CounterImpl.getInstance(instructionCounter);
- copy.branchCounter = CounterImpl.getInstance(branchCounter);
- copy.lineCounter = CounterImpl.getInstance(lineCounter);
- copy.complexityCounter = CounterImpl.getInstance(complexityCounter);
- copy.methodCounter = CounterImpl.getInstance(methodCounter);
- copy.classCounter = CounterImpl.getInstance(classCounter);
- return copy;
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append(name).append(" [").append(elementType).append("]");
- return sb.toString();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.util.Collection; + +import org.jacoco.core.internal.analysis.CounterImpl; + +/** + * Base implementation for coverage data nodes. + */ +public class CoverageNodeImpl implements ICoverageNode { + + private final ElementType elementType; + + private final String name; + + /** Counter for branches. */ + protected CounterImpl branchCounter; + + /** Counter for instructions. */ + protected CounterImpl instructionCounter; + + /** Counter for lines */ + protected CounterImpl lineCounter; + + /** Counter for complexity. */ + protected CounterImpl complexityCounter; + + /** Counter for methods. */ + protected CounterImpl methodCounter; + + /** Counter for classes. */ + protected CounterImpl classCounter; + + /** + * Creates a new coverage data node. + * + * @param elementType + * type of the element represented by this instance + * @param name + * name of this node + */ + public CoverageNodeImpl(final ElementType elementType, final String name) { + this.elementType = elementType; + this.name = name; + this.branchCounter = CounterImpl.COUNTER_0_0; + this.instructionCounter = CounterImpl.COUNTER_0_0; + this.complexityCounter = CounterImpl.COUNTER_0_0; + this.methodCounter = CounterImpl.COUNTER_0_0; + this.classCounter = CounterImpl.COUNTER_0_0; + this.lineCounter = CounterImpl.COUNTER_0_0; + } + + /** + * Increments the counters by the values given by another element. + * + * @param child + * counters to add + */ + public void increment(final ICoverageNode child) { + instructionCounter = instructionCounter.increment(child + .getInstructionCounter()); + branchCounter = branchCounter.increment(child.getBranchCounter()); + lineCounter = lineCounter.increment(child.getLineCounter()); + complexityCounter = complexityCounter.increment(child + .getComplexityCounter()); + methodCounter = methodCounter.increment(child.getMethodCounter()); + classCounter = classCounter.increment(child.getClassCounter()); + } + + /** + * Increments the counters by the values given by the collection of + * elements. + * + * @param children + * list of nodes, which counters will be added to this node + */ + public void increment(final Collection<? extends ICoverageNode> children) { + for (final ICoverageNode child : children) { + increment(child); + } + } + + // === ICoverageDataNode === + + public ElementType getElementType() { + return elementType; + } + + public String getName() { + return name; + } + + public ICounter getInstructionCounter() { + return instructionCounter; + } + + public ICounter getBranchCounter() { + return branchCounter; + } + + public ICounter getLineCounter() { + return lineCounter; + } + + public ICounter getComplexityCounter() { + return complexityCounter; + } + + public ICounter getMethodCounter() { + return methodCounter; + } + + public ICounter getClassCounter() { + return classCounter; + } + + public ICounter getCounter(final CounterEntity entity) { + switch (entity) { + case INSTRUCTION: + return getInstructionCounter(); + case BRANCH: + return getBranchCounter(); + case LINE: + return getLineCounter(); + case COMPLEXITY: + return getComplexityCounter(); + case METHOD: + return getMethodCounter(); + case CLASS: + return getClassCounter(); + } + throw new AssertionError(entity); + } + + public ICoverageNode getPlainCopy() { + final CoverageNodeImpl copy = new CoverageNodeImpl(elementType, name); + copy.instructionCounter = CounterImpl.getInstance(instructionCounter); + copy.branchCounter = CounterImpl.getInstance(branchCounter); + copy.lineCounter = CounterImpl.getInstance(lineCounter); + copy.complexityCounter = CounterImpl.getInstance(complexityCounter); + copy.methodCounter = CounterImpl.getInstance(methodCounter); + copy.classCounter = CounterImpl.getInstance(classCounter); + return copy; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append(name).append(" [").append(elementType).append("]"); + return sb.toString(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java index 3e9c0e09..b362940b 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java @@ -1,30 +1,30 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.util.Collection;
-
-/**
- * Coverage data of a bundle. A bundle groups a collection of packages.
- *
- * @see IPackageCoverage
- */
-public interface IBundleCoverage extends ICoverageNode {
-
- /**
- * Returns all packages contained in this bundle.
- *
- * @return all packages
- */
- public Collection<IPackageCoverage> getPackages();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.util.Collection; + +/** + * Coverage data of a bundle. A bundle groups a collection of packages. + * + * @see IPackageCoverage + */ +public interface IBundleCoverage extends ICoverageNode { + + /** + * Returns all packages contained in this bundle. + * + * @return all packages + */ + public Collection<IPackageCoverage> getPackages(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java index 4f131a58..919c1b61 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java @@ -1,75 +1,75 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.util.Collection;
-
-/**
- * Coverage data of a single class containing methods. The name of this node is
- * the fully qualified class name in VM notation (slash separated).
- *
- * @see IMethodCoverage
- */
-public interface IClassCoverage extends ISourceNode {
-
- /**
- * Returns the identifier for this class which is the CRC64 signature of the
- * class definition.
- *
- * @return class identifier
- */
- public long getId();
-
- /**
- * Returns the VM signature of the class.
- *
- * @return VM signature of the class (may be <code>null</code>)
- */
- public String getSignature();
-
- /**
- * Returns the VM name of the superclass.
- *
- * @return VM name of the super class (may be <code>null</code>, i.e.
- * <code>java/lang/Object</code>)
- */
- public String getSuperName();
-
- /**
- * Returns the VM names of implemented/extended interfaces
- *
- * @return VM names of implemented/extended interfaces
- */
- public String[] getInterfaceNames();
-
- /**
- * Returns the VM name of the package this class belongs to.
- *
- * @return VM name of the package
- */
- public String getPackageName();
-
- /**
- * Returns the optional name of the corresponding source file.
- *
- * @return name of the corresponding source file
- */
- public String getSourceFileName();
-
- /**
- * Returns the methods included in this class.
- *
- * @return methods of this class
- */
- public Collection<IMethodCoverage> getMethods();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.util.Collection; + +/** + * Coverage data of a single class containing methods. The name of this node is + * the fully qualified class name in VM notation (slash separated). + * + * @see IMethodCoverage + */ +public interface IClassCoverage extends ISourceNode { + + /** + * Returns the identifier for this class which is the CRC64 signature of the + * class definition. + * + * @return class identifier + */ + public long getId(); + + /** + * Returns the VM signature of the class. + * + * @return VM signature of the class (may be <code>null</code>) + */ + public String getSignature(); + + /** + * Returns the VM name of the superclass. + * + * @return VM name of the super class (may be <code>null</code>, i.e. + * <code>java/lang/Object</code>) + */ + public String getSuperName(); + + /** + * Returns the VM names of implemented/extended interfaces + * + * @return VM names of implemented/extended interfaces + */ + public String[] getInterfaceNames(); + + /** + * Returns the VM name of the package this class belongs to. + * + * @return VM name of the package + */ + public String getPackageName(); + + /** + * Returns the optional name of the corresponding source file. + * + * @return name of the corresponding source file + */ + public String getSourceFileName(); + + /** + * Returns the methods included in this class. + * + * @return methods of this class + */ + public Collection<IMethodCoverage> getMethods(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java index 41c7f893..e2135f5a 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java @@ -1,89 +1,89 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * A counter holds the missed and the covered number of particular items like
- * classes, methods, branches or instructions.
- */
-public interface ICounter {
-
- /**
- * Status flag for no items (value is 0x00).
- */
- public static final int EMPTY = 0x00;
-
- /**
- * Status flag when all items are not covered (value is 0x01).
- */
- public static final int NOT_COVERED = 0x01;
-
- /**
- * Status flag when all items are covered (value is 0x02).
- */
- public static final int FULLY_COVERED = 0x02;
-
- /**
- * Status flag when items are partly covered (value is 0x03).
- */
- public static final int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED;
-
- /**
- * Returns the total count of items.
- *
- * @return total count of items
- */
- public int getTotalCount();
-
- /**
- * Returns the count of covered items.
- *
- * @return count of covered items
- */
- public int getCoveredCount();
-
- /**
- * Returns the count of missed items.
- *
- * @return count of missed items
- */
- public int getMissedCount();
-
- /**
- * Calculates the ratio of covered to total count items. If total count
- * items is 0 this method returns NaN.
- *
- * @return ratio of covered to total count items
- */
- public double getCoveredRatio();
-
- /**
- * Calculates the ratio of missed to total count items. If total count items
- * is 0 this method returns NaN.
- *
- * @return ratio of missed to total count items
- */
- public double getMissedRatio();
-
- /**
- * Returns the coverage status of this counter.
- *
- * @see ICounter#EMPTY
- * @see ICounter#NOT_COVERED
- * @see ICounter#PARTLY_COVERED
- * @see ICounter#FULLY_COVERED
- *
- * @return status of this line
- */
- public int getStatus();
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * A counter holds the missed and the covered number of particular items like + * classes, methods, branches or instructions. + */ +public interface ICounter { + + /** + * Status flag for no items (value is 0x00). + */ + public static final int EMPTY = 0x00; + + /** + * Status flag when all items are not covered (value is 0x01). + */ + public static final int NOT_COVERED = 0x01; + + /** + * Status flag when all items are covered (value is 0x02). + */ + public static final int FULLY_COVERED = 0x02; + + /** + * Status flag when items are partly covered (value is 0x03). + */ + public static final int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED; + + /** + * Returns the total count of items. + * + * @return total count of items + */ + public int getTotalCount(); + + /** + * Returns the count of covered items. + * + * @return count of covered items + */ + public int getCoveredCount(); + + /** + * Returns the count of missed items. + * + * @return count of missed items + */ + public int getMissedCount(); + + /** + * Calculates the ratio of covered to total count items. If total count + * items is 0 this method returns NaN. + * + * @return ratio of covered to total count items + */ + public double getCoveredRatio(); + + /** + * Calculates the ratio of missed to total count items. If total count items + * is 0 this method returns NaN. + * + * @return ratio of missed to total count items + */ + public double getMissedRatio(); + + /** + * Returns the coverage status of this counter. + * + * @see ICounter#EMPTY + * @see ICounter#NOT_COVERED + * @see ICounter#PARTLY_COVERED + * @see ICounter#FULLY_COVERED + * + * @return status of this line + */ + public int getStatus(); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java index ab500c27..71ab908e 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java @@ -1,144 +1,144 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * Interface for hierarchical coverage data nodes with different coverage
- * counters.
- */
-public interface ICoverageNode {
-
- /**
- * Type of a Java element represented by a {@link ICoverageNode} instance.
- */
- public enum ElementType {
-
- /** Method */
- METHOD,
-
- /** Class */
- CLASS,
-
- /** Source File */
- SOURCEFILE,
-
- /** Java Package */
- PACKAGE,
-
- /** Bundle of Packages */
- BUNDLE,
-
- /** Logical Group of Bundles */
- GROUP,
-
- }
-
- /**
- * Different counter types supported by JaCoCo.
- */
- public enum CounterEntity {
-
- /** Counter for instructions */
- INSTRUCTION,
-
- /** Counter for branches */
- BRANCH,
-
- /** Counter for source lines */
- LINE,
-
- /** Counter for cyclomatic complexity */
- COMPLEXITY,
-
- /** Counter for methods */
- METHOD,
-
- /** Counter for classes */
- CLASS
- }
-
- /**
- * Returns the type of element represented by this node.
- *
- * @return type of this node
- */
- public abstract ElementType getElementType();
-
- /**
- * Returns the name of this node.
- *
- * @return name of this node
- */
- public String getName();
-
- /**
- * Returns the counter for byte code instructions.
- *
- * @return counter for instructions
- */
- public abstract ICounter getInstructionCounter();
-
- /**
- * Returns the counter for branches.
- *
- * @return counter for branches
- */
- public ICounter getBranchCounter();
-
- /**
- * Returns the counter for lines.
- *
- * @return counter for lines
- */
- public ICounter getLineCounter();
-
- /**
- * Returns the counter for cyclomatic complexity.
- *
- * @return counter for complexity
- */
- public ICounter getComplexityCounter();
-
- /**
- * Returns the counter for methods.
- *
- * @return counter for methods
- */
- public ICounter getMethodCounter();
-
- /**
- * Returns the counter for classes.
- *
- * @return counter for classes
- */
- public ICounter getClassCounter();
-
- /**
- * Generic access to the the counters.
- *
- * @param entity
- * entity we're we want to have the counter for
- * @return counter for the given entity
- */
- public ICounter getCounter(CounterEntity entity);
-
- /**
- * Creates a plain copy of this node. While {@link ICoverageNode}
- * implementations may contain heavy data structures, the copy returned by
- * this method is reduced to the counters only. This helps to save memory
- * while processing huge structures.
- *
- * @return copy with counters only
- */
- public ICoverageNode getPlainCopy();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * Interface for hierarchical coverage data nodes with different coverage + * counters. + */ +public interface ICoverageNode { + + /** + * Type of a Java element represented by a {@link ICoverageNode} instance. + */ + public enum ElementType { + + /** Method */ + METHOD, + + /** Class */ + CLASS, + + /** Source File */ + SOURCEFILE, + + /** Java Package */ + PACKAGE, + + /** Bundle of Packages */ + BUNDLE, + + /** Logical Group of Bundles */ + GROUP, + + } + + /** + * Different counter types supported by JaCoCo. + */ + public enum CounterEntity { + + /** Counter for instructions */ + INSTRUCTION, + + /** Counter for branches */ + BRANCH, + + /** Counter for source lines */ + LINE, + + /** Counter for cyclomatic complexity */ + COMPLEXITY, + + /** Counter for methods */ + METHOD, + + /** Counter for classes */ + CLASS + } + + /** + * Returns the type of element represented by this node. + * + * @return type of this node + */ + public abstract ElementType getElementType(); + + /** + * Returns the name of this node. + * + * @return name of this node + */ + public String getName(); + + /** + * Returns the counter for byte code instructions. + * + * @return counter for instructions + */ + public abstract ICounter getInstructionCounter(); + + /** + * Returns the counter for branches. + * + * @return counter for branches + */ + public ICounter getBranchCounter(); + + /** + * Returns the counter for lines. + * + * @return counter for lines + */ + public ICounter getLineCounter(); + + /** + * Returns the counter for cyclomatic complexity. + * + * @return counter for complexity + */ + public ICounter getComplexityCounter(); + + /** + * Returns the counter for methods. + * + * @return counter for methods + */ + public ICounter getMethodCounter(); + + /** + * Returns the counter for classes. + * + * @return counter for classes + */ + public ICounter getClassCounter(); + + /** + * Generic access to the the counters. + * + * @param entity + * entity we're we want to have the counter for + * @return counter for the given entity + */ + public ICounter getCounter(CounterEntity entity); + + /** + * Creates a plain copy of this node. While {@link ICoverageNode} + * implementations may contain heavy data structures, the copy returned by + * this method is reduced to the counters only. This helps to save memory + * while processing huge structures. + * + * @return copy with counters only + */ + public ICoverageNode getPlainCopy(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java index 94a4ee5b..f21ad4db 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java @@ -1,28 +1,28 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * Interface for coverage data output as a stream of {@link IClassCoverage}
- * instances.
- */
-public interface ICoverageVisitor {
-
- /**
- * For analyzed class coverage data is emitted to this method.
- *
- * @param coverage
- * coverage data for a class
- */
- public void visitCoverage(IClassCoverage coverage);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * Interface for coverage data output as a stream of {@link IClassCoverage} + * instances. + */ +public interface ICoverageVisitor { + + /** + * For analyzed class coverage data is emitted to this method. + * + * @param coverage + * coverage data for a class + */ + public void visitCoverage(IClassCoverage coverage); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java index 1c4b6893..a384cd39 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java @@ -1,47 +1,47 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * The instruction and branch coverage of a single source line is described by
- * this interface.
- */
-public interface ILine {
-
- /**
- * Returns the instruction counter for this line.
- *
- * @return instruction counter
- */
- public ICounter getInstructionCounter();
-
- /**
- * Returns the branches counter for this line.
- *
- * @return branches counter
- */
- public ICounter getBranchCounter();
-
- /**
- * Returns the coverage status of this line, calculated from the
- * instructions counter and branch counter.
- *
- * @see ICounter#EMPTY
- * @see ICounter#NOT_COVERED
- * @see ICounter#PARTLY_COVERED
- * @see ICounter#FULLY_COVERED
- *
- * @return status of this line
- */
- public int getStatus();
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * The instruction and branch coverage of a single source line is described by + * this interface. + */ +public interface ILine { + + /** + * Returns the instruction counter for this line. + * + * @return instruction counter + */ + public ICounter getInstructionCounter(); + + /** + * Returns the branches counter for this line. + * + * @return branches counter + */ + public ICounter getBranchCounter(); + + /** + * Returns the coverage status of this line, calculated from the + * instructions counter and branch counter. + * + * @see ICounter#EMPTY + * @see ICounter#NOT_COVERED + * @see ICounter#PARTLY_COVERED + * @see ICounter#FULLY_COVERED + * + * @return status of this line + */ + public int getStatus(); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java index 0aae064a..40a4eec5 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java @@ -1,34 +1,34 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * Coverage data of a single method. The name of this node is the local method
- * name.
- */
-public interface IMethodCoverage extends ISourceNode {
-
- /**
- * Returns the parameter description of the method.
- *
- * @return parameter description
- */
- public String getDesc();
-
- /**
- * Returns the generic signature of the method if defined.
- *
- * @return generic signature or <code>null</code>
- */
- public String getSignature();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * Coverage data of a single method. The name of this node is the local method + * name. + */ +public interface IMethodCoverage extends ISourceNode { + + /** + * Returns the parameter description of the method. + * + * @return parameter description + */ + public String getDesc(); + + /** + * Returns the generic signature of the method if defined. + * + * @return generic signature or <code>null</code> + */ + public String getSignature(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java index 9edcda63..0a889761 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java @@ -1,40 +1,40 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.util.Collection;
-
-/**
- * Coverage data of a Java package containing classes and source files. The name
- * of this node is the package name in VM notation (slash separated). The name
- * of the default package is the empty string.
- *
- * @see IClassCoverage
- * @see ISourceFileCoverage
- */
-public interface IPackageCoverage extends ICoverageNode {
-
- /**
- * Returns all classes contained in this package.
- *
- * @return all classes
- */
- public Collection<IClassCoverage> getClasses();
-
- /**
- * Returns all source files in this package.
- *
- * @return all source files
- */
- public Collection<ISourceFileCoverage> getSourceFiles();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.util.Collection; + +/** + * Coverage data of a Java package containing classes and source files. The name + * of this node is the package name in VM notation (slash separated). The name + * of the default package is the empty string. + * + * @see IClassCoverage + * @see ISourceFileCoverage + */ +public interface IPackageCoverage extends ICoverageNode { + + /** + * Returns all classes contained in this package. + * + * @return all classes + */ + public Collection<IClassCoverage> getClasses(); + + /** + * Returns all source files in this package. + * + * @return all source files + */ + public Collection<ISourceFileCoverage> getSourceFiles(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java index 7e9475dc..e3b079e7 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java @@ -1,27 +1,27 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * Coverage data of a single source file. The name of this node is the local
- * name of the source file.
- */
-public interface ISourceFileCoverage extends ISourceNode {
-
- /**
- * Returns the VM name of the package the source file belongs to.
- *
- * @return package name
- */
- public String getPackageName();
-
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * Coverage data of a single source file. The name of this node is the local + * name of the source file. + */ +public interface ISourceFileCoverage extends ISourceNode { + + /** + * Returns the VM name of the package the source file belongs to. + * + * @return package name + */ + public String getPackageName(); + }
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java index bd979906..eda6cc0d 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java @@ -1,48 +1,48 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-/**
- * Interface for coverage nodes that have individual source lines like methods,
- * classes and source files.
- */
-public interface ISourceNode extends ICoverageNode {
-
- /** Place holder for unknown lines (no debug information) */
- public static int UNKNOWN_LINE = -1;
-
- /**
- * The number of the first line coverage information is available for. If no
- * line is contained, the method returns -1.
- *
- * @return number of the first line or {@link #UNKNOWN_LINE}
- */
- public int getFirstLine();
-
- /**
- * The number of the last line coverage information is available for. If no
- * line is contained, the method returns -1.
- *
- * @return number of the last line or {@link #UNKNOWN_LINE}
- */
- public int getLastLine();
-
- /**
- * Returns the line information for given line.
- *
- * @param nr
- * line number of interest
- * @return line information
- */
- public ILine getLine(int nr);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +/** + * Interface for coverage nodes that have individual source lines like methods, + * classes and source files. + */ +public interface ISourceNode extends ICoverageNode { + + /** Place holder for unknown lines (no debug information) */ + public static int UNKNOWN_LINE = -1; + + /** + * The number of the first line coverage information is available for. If no + * line is contained, the method returns -1. + * + * @return number of the first line or {@link #UNKNOWN_LINE} + */ + public int getFirstLine(); + + /** + * The number of the last line coverage information is available for. If no + * line is contained, the method returns -1. + * + * @return number of the last line or {@link #UNKNOWN_LINE} + */ + public int getLastLine(); + + /** + * Returns the line information for given line. + * + * @param nr + * line number of interest + * @return line information + */ + public ILine getLine(int nr); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java b/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java index 08960a61..2b1169bd 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java @@ -1,87 +1,87 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.analysis;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import org.jacoco.core.analysis.ICoverageNode.CounterEntity;
-
-/**
- * Comparator to compare {@link ICoverageNode} objects by different counter
- * criteria.
- *
- * @see CounterComparator#on(ICoverageNode.CounterEntity)
- */
-public class NodeComparator implements Comparator<ICoverageNode>, Serializable {
-
- private static final long serialVersionUID = 8550521643608826519L;
-
- private final Comparator<ICounter> counterComparator;
-
- private final CounterEntity entity;
-
- NodeComparator(final Comparator<ICounter> counterComparator,
- final CounterEntity entity) {
- this.counterComparator = counterComparator;
- this.entity = entity;
- }
-
- /**
- * Creates a new composite comparator with a second search criterion.
- *
- * @param second
- * second criterion comparator
- *
- * @return composite comparator
- */
- public NodeComparator second(final Comparator<ICoverageNode> second) {
- final Comparator<ICoverageNode> first = this;
- return new NodeComparator(null, null) {
-
- private static final long serialVersionUID = -5515272752138802838L;
-
- @Override
- public int compare(final ICoverageNode o1, final ICoverageNode o2) {
- final int result = first.compare(o1, o2);
- return result == 0 ? second.compare(o1, o2) : result;
- }
- };
- }
-
- /**
- * Returns a sorted copy of the given collection of {@link ICoverageNode}
- * elements.
- *
- * @param <T>
- * actual type of the elements
- * @param summaries
- * collection to create a copy of
- * @return sorted copy
- */
- public <T extends ICoverageNode> List<T> sort(final Collection<T> summaries) {
- final List<T> result = new ArrayList<T>(summaries);
- Collections.sort(result, this);
- return result;
- }
-
- public int compare(final ICoverageNode n1, final ICoverageNode n2) {
- final ICounter c1 = n1.getCounter(entity);
- final ICounter c2 = n2.getCounter(entity);
- return counterComparator.compare(c1, c2);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.analysis; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.jacoco.core.analysis.ICoverageNode.CounterEntity; + +/** + * Comparator to compare {@link ICoverageNode} objects by different counter + * criteria. + * + * @see CounterComparator#on(ICoverageNode.CounterEntity) + */ +public class NodeComparator implements Comparator<ICoverageNode>, Serializable { + + private static final long serialVersionUID = 8550521643608826519L; + + private final Comparator<ICounter> counterComparator; + + private final CounterEntity entity; + + NodeComparator(final Comparator<ICounter> counterComparator, + final CounterEntity entity) { + this.counterComparator = counterComparator; + this.entity = entity; + } + + /** + * Creates a new composite comparator with a second search criterion. + * + * @param second + * second criterion comparator + * + * @return composite comparator + */ + public NodeComparator second(final Comparator<ICoverageNode> second) { + final Comparator<ICoverageNode> first = this; + return new NodeComparator(null, null) { + + private static final long serialVersionUID = -5515272752138802838L; + + @Override + public int compare(final ICoverageNode o1, final ICoverageNode o2) { + final int result = first.compare(o1, o2); + return result == 0 ? second.compare(o1, o2) : result; + } + }; + } + + /** + * Returns a sorted copy of the given collection of {@link ICoverageNode} + * elements. + * + * @param <T> + * actual type of the elements + * @param summaries + * collection to create a copy of + * @return sorted copy + */ + public <T extends ICoverageNode> List<T> sort(final Collection<T> summaries) { + final List<T> result = new ArrayList<T>(summaries); + Collections.sort(result, this); + return result; + } + + public int compare(final ICoverageNode n1, final ICoverageNode n2) { + final ICounter c1 = n1.getCounter(entity); + final ICounter c2 = n2.getCounter(entity); + return counterComparator.compare(c1, c2); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java index 63061e67..90760802 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java @@ -1,157 +1,157 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-import static java.lang.String.format;
-
-import java.util.Arrays;
-
-/**
- * Execution data for a single Java class. While instances are immutable care
- * has to be taken about the probe data array of type <code>boolean[]</code>
- * which can be modified.
- */
-public final class ExecutionData {
-
- private final long id;
-
- private final String name;
-
- private final boolean[] data;
-
- /**
- * Creates a new {@link ExecutionData} object with the given probe data.
- *
- * @param id
- * class identifier
- * @param name
- * VM name
- * @param data
- * probe data
- */
- public ExecutionData(final long id, final String name, final boolean[] data) {
- this.id = id;
- this.name = name;
- this.data = data;
- }
-
- /**
- * Creates a new {@link ExecutionData} object with the given probe data
- * length. All probes are set to <code>false</code>.
- *
- * @param id
- * class identifier
- * @param name
- * VM name
- * @param dataLength
- * probe data length
- */
- public ExecutionData(final long id, final String name, final int dataLength) {
- this.id = id;
- this.name = name;
- this.data = new boolean[dataLength];
- }
-
- /**
- * Return the unique identifier for this class. The identifier is the CRC64
- * checksum of the raw class file definition.
- *
- * @return class identifier
- */
- public long getId() {
- return id;
- }
-
- /**
- * The VM name of the class.
- *
- * @return VM name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the execution data probes. A value of <code>true</code> indicates
- * that the corresponding probe was executed.
- *
- * @return execution data
- */
- public boolean[] getData() {
- return data;
- }
-
- /**
- * Sets all probe data entries to <code>false</code>.
- */
- public void reset() {
- Arrays.fill(data, false);
- }
-
- /**
- * Merges the given execution data into the probe data of this object. I.e.
- * a probe entry in this object is marked as executed (<code>true</code>) if
- * this probe or the corresponding other probe was executed. The probe array
- * of the other object is not modified.
- *
- * @param other
- */
- public void merge(final ExecutionData other) {
- assertCompatibility(other.getId(), other.getName(),
- other.getData().length);
- final boolean[] otherData = other.getData();
- for (int i = 0; i < data.length; i++) {
- if (otherData[i]) {
- data[i] = true;
- }
- }
- }
-
- /**
- * Asserts that this execution data object is compatible with the given
- * parameters. The purpose of this check is to detect a very unlikely class
- * id collision.
- *
- * @param id
- * other class id, must be the same
- * @param name
- * other name, must be equal to this name
- * @param dataLength
- * probe data length, must be the same as for this data
- * @throws IllegalStateException
- * if the given parameters do not match this instance
- */
- public void assertCompatibility(final long id, final String name,
- final int dataLength) throws IllegalStateException {
- if (this.id != id) {
- throw new IllegalStateException(format(
- "Different ids (%016x and %016x).", Long.valueOf(this.id),
- Long.valueOf(id)));
- }
- if (!this.name.equals(name)) {
- throw new IllegalStateException(format(
- "Different class names %s and %s for id %016x.", this.name,
- name, Long.valueOf(id)));
- }
- if (this.data.length != dataLength) {
- throw new IllegalStateException(format(
- "Incompatible execution data for class %s with id %016x.",
- name, Long.valueOf(id)));
- }
- }
-
- @Override
- public String toString() {
- return String.format("ExecutionData [name=%s, id=%016x]", name,
- Long.valueOf(id));
- }
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +import static java.lang.String.format; + +import java.util.Arrays; + +/** + * Execution data for a single Java class. While instances are immutable care + * has to be taken about the probe data array of type <code>boolean[]</code> + * which can be modified. + */ +public final class ExecutionData { + + private final long id; + + private final String name; + + private final boolean[] data; + + /** + * Creates a new {@link ExecutionData} object with the given probe data. + * + * @param id + * class identifier + * @param name + * VM name + * @param data + * probe data + */ + public ExecutionData(final long id, final String name, final boolean[] data) { + this.id = id; + this.name = name; + this.data = data; + } + + /** + * Creates a new {@link ExecutionData} object with the given probe data + * length. All probes are set to <code>false</code>. + * + * @param id + * class identifier + * @param name + * VM name + * @param dataLength + * probe data length + */ + public ExecutionData(final long id, final String name, final int dataLength) { + this.id = id; + this.name = name; + this.data = new boolean[dataLength]; + } + + /** + * Return the unique identifier for this class. The identifier is the CRC64 + * checksum of the raw class file definition. + * + * @return class identifier + */ + public long getId() { + return id; + } + + /** + * The VM name of the class. + * + * @return VM name + */ + public String getName() { + return name; + } + + /** + * Returns the execution data probes. A value of <code>true</code> indicates + * that the corresponding probe was executed. + * + * @return execution data + */ + public boolean[] getData() { + return data; + } + + /** + * Sets all probe data entries to <code>false</code>. + */ + public void reset() { + Arrays.fill(data, false); + } + + /** + * Merges the given execution data into the probe data of this object. I.e. + * a probe entry in this object is marked as executed (<code>true</code>) if + * this probe or the corresponding other probe was executed. The probe array + * of the other object is not modified. + * + * @param other + */ + public void merge(final ExecutionData other) { + assertCompatibility(other.getId(), other.getName(), + other.getData().length); + final boolean[] otherData = other.getData(); + for (int i = 0; i < data.length; i++) { + if (otherData[i]) { + data[i] = true; + } + } + } + + /** + * Asserts that this execution data object is compatible with the given + * parameters. The purpose of this check is to detect a very unlikely class + * id collision. + * + * @param id + * other class id, must be the same + * @param name + * other name, must be equal to this name + * @param dataLength + * probe data length, must be the same as for this data + * @throws IllegalStateException + * if the given parameters do not match this instance + */ + public void assertCompatibility(final long id, final String name, + final int dataLength) throws IllegalStateException { + if (this.id != id) { + throw new IllegalStateException(format( + "Different ids (%016x and %016x).", Long.valueOf(this.id), + Long.valueOf(id))); + } + if (!this.name.equals(name)) { + throw new IllegalStateException(format( + "Different class names %s and %s for id %016x.", this.name, + name, Long.valueOf(id))); + } + if (this.data.length != dataLength) { + throw new IllegalStateException(format( + "Incompatible execution data for class %s with id %016x.", + name, Long.valueOf(id))); + } + } + + @Override + public String toString() { + return String.format("ExecutionData [name=%s, id=%016x]", name, + Long.valueOf(id)); + } +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java index ba24fd4d..ba74db4b 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java @@ -1,151 +1,151 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-import static java.lang.String.format;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.jacoco.core.internal.data.CompactDataInput;
-
-/**
- * Deserialization of execution data from binary streams.
- */
-public class ExecutionDataReader {
-
- /** Underlying data input */
- protected final CompactDataInput in;
-
- private ISessionInfoVisitor sessionInfoVisitor = null;
-
- private IExecutionDataVisitor executionDataVisitor = null;
-
- private boolean firstBlock = true;
-
- /**
- * Creates a new reader based on the given input stream input. Depending on
- * the nature of the underlying stream input should be buffered as most data
- * is read in single bytes.
- *
- * @param input
- * input stream to read execution data from
- */
- public ExecutionDataReader(final InputStream input) {
- this.in = new CompactDataInput(input);
- }
-
- /**
- * Sets an listener for session information.
- *
- * @param visitor
- */
- public void setSessionInfoVisitor(final ISessionInfoVisitor visitor) {
- this.sessionInfoVisitor = visitor;
- }
-
- /**
- * Sets an listener for execution data.
- *
- * @param visitor
- */
- public void setExecutionDataVisitor(final IExecutionDataVisitor visitor) {
- this.executionDataVisitor = visitor;
- }
-
- /**
- * Reads all data and reports it to the corresponding visitors. The stream
- * is read until its end or a command confirmation has been sent.
- *
- * @return <code>true</code> if additional data can be expected after a
- * command has been executed. <code>false</code> if the end of the
- * stream has been reached.
- * @throws IOException
- * might be thrown by the underlying input stream
- */
- public boolean read() throws IOException {
- try {
- byte type;
- do {
- type = in.readByte();
- if (firstBlock && type != ExecutionDataWriter.BLOCK_HEADER) {
- throw new IOException("Invalid execution data file.");
- }
- firstBlock = false;
- } while (readBlock(type));
- return true;
- } catch (final EOFException e) {
- return false;
- }
- }
-
- /**
- * Reads a block of data identified by the given id. Subclasses may
- * overwrite this method to support additional block types.
- *
- * @param blocktype
- * block type
- * @return <code>true</code> if there are more blocks to read
- * @throws IOException
- * might be thrown by the underlying input stream
- */
- protected boolean readBlock(final byte blocktype) throws IOException {
- switch (blocktype) {
- case ExecutionDataWriter.BLOCK_HEADER:
- readHeader();
- return true;
- case ExecutionDataWriter.BLOCK_SESSIONINFO:
- readSessionInfo();
- return true;
- case ExecutionDataWriter.BLOCK_EXECUTIONDATA:
- readExecutionData();
- return true;
- default:
- throw new IOException(format("Unknown block type %x.",
- Byte.valueOf(blocktype)));
- }
- }
-
- private void readHeader() throws IOException {
- if (in.readChar() != ExecutionDataWriter.MAGIC_NUMBER) {
- throw new IOException("Invalid execution data file.");
- }
- final char version = in.readChar();
- if (version != ExecutionDataWriter.FORMAT_VERSION) {
- throw new IOException(format("Incompatible version %x.",
- Integer.valueOf(version)));
- }
- }
-
- private void readSessionInfo() throws IOException {
- if (sessionInfoVisitor == null) {
- throw new IOException("No session info visitor.");
- }
- final String id = in.readUTF();
- final long start = in.readLong();
- final long dump = in.readLong();
- sessionInfoVisitor.visitSessionInfo(new SessionInfo(id, start, dump));
- }
-
- private void readExecutionData() throws IOException {
- if (executionDataVisitor == null) {
- throw new IOException("No execution data visitor.");
- }
- final long id = in.readLong();
- final String name = in.readUTF();
- final boolean[] data = in.readBooleanArray();
- executionDataVisitor.visitClassExecution(new ExecutionData(id, name,
- data));
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +import static java.lang.String.format; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.jacoco.core.internal.data.CompactDataInput; + +/** + * Deserialization of execution data from binary streams. + */ +public class ExecutionDataReader { + + /** Underlying data input */ + protected final CompactDataInput in; + + private ISessionInfoVisitor sessionInfoVisitor = null; + + private IExecutionDataVisitor executionDataVisitor = null; + + private boolean firstBlock = true; + + /** + * Creates a new reader based on the given input stream input. Depending on + * the nature of the underlying stream input should be buffered as most data + * is read in single bytes. + * + * @param input + * input stream to read execution data from + */ + public ExecutionDataReader(final InputStream input) { + this.in = new CompactDataInput(input); + } + + /** + * Sets an listener for session information. + * + * @param visitor + */ + public void setSessionInfoVisitor(final ISessionInfoVisitor visitor) { + this.sessionInfoVisitor = visitor; + } + + /** + * Sets an listener for execution data. + * + * @param visitor + */ + public void setExecutionDataVisitor(final IExecutionDataVisitor visitor) { + this.executionDataVisitor = visitor; + } + + /** + * Reads all data and reports it to the corresponding visitors. The stream + * is read until its end or a command confirmation has been sent. + * + * @return <code>true</code> if additional data can be expected after a + * command has been executed. <code>false</code> if the end of the + * stream has been reached. + * @throws IOException + * might be thrown by the underlying input stream + */ + public boolean read() throws IOException { + try { + byte type; + do { + type = in.readByte(); + if (firstBlock && type != ExecutionDataWriter.BLOCK_HEADER) { + throw new IOException("Invalid execution data file."); + } + firstBlock = false; + } while (readBlock(type)); + return true; + } catch (final EOFException e) { + return false; + } + } + + /** + * Reads a block of data identified by the given id. Subclasses may + * overwrite this method to support additional block types. + * + * @param blocktype + * block type + * @return <code>true</code> if there are more blocks to read + * @throws IOException + * might be thrown by the underlying input stream + */ + protected boolean readBlock(final byte blocktype) throws IOException { + switch (blocktype) { + case ExecutionDataWriter.BLOCK_HEADER: + readHeader(); + return true; + case ExecutionDataWriter.BLOCK_SESSIONINFO: + readSessionInfo(); + return true; + case ExecutionDataWriter.BLOCK_EXECUTIONDATA: + readExecutionData(); + return true; + default: + throw new IOException(format("Unknown block type %x.", + Byte.valueOf(blocktype))); + } + } + + private void readHeader() throws IOException { + if (in.readChar() != ExecutionDataWriter.MAGIC_NUMBER) { + throw new IOException("Invalid execution data file."); + } + final char version = in.readChar(); + if (version != ExecutionDataWriter.FORMAT_VERSION) { + throw new IOException(format("Incompatible version %x.", + Integer.valueOf(version))); + } + } + + private void readSessionInfo() throws IOException { + if (sessionInfoVisitor == null) { + throw new IOException("No session info visitor."); + } + final String id = in.readUTF(); + final long start = in.readLong(); + final long dump = in.readLong(); + sessionInfoVisitor.visitSessionInfo(new SessionInfo(id, start, dump)); + } + + private void readExecutionData() throws IOException { + if (executionDataVisitor == null) { + throw new IOException("No execution data visitor."); + } + final long id = in.readLong(); + final String name = in.readUTF(); + final boolean[] data = in.readBooleanArray(); + executionDataVisitor.visitClassExecution(new ExecutionData(id, name, + data)); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java index 9ee1c28f..88b19cf0 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java @@ -1,124 +1,124 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * In-memory data store for execution data. The data can be added through its
- * {@link IExecutionDataVisitor} interface. If execution data is provided
- * multiple times for the same class the data is merged, i.e. a probe is marked
- * as executed if it is reported as executed at least once. This allows to merge
- * coverage date from multiple runs. A instance of this class is not thread
- * safe.
- */
-public final class ExecutionDataStore implements IExecutionDataVisitor {
-
- private final Map<Long, ExecutionData> entries = new HashMap<Long, ExecutionData>();
-
- /**
- * Adds the given {@link ExecutionData} object into the store. If there is
- * already execution data with this same class id, this structure is merged
- * with the given one.
- *
- * @param data
- * execution data to add or merge
- * @throws IllegalStateException
- * if the given {@link ExecutionData} object is not compatible
- * to a corresponding one, that is already contained
- * @see ExecutionData#assertCompatibility(long, String, int)
- */
- public void put(final ExecutionData data) throws IllegalStateException {
- final Long id = Long.valueOf(data.getId());
- final ExecutionData entry = entries.get(id);
- if (entry == null) {
- entries.put(id, data);
- } else {
- entry.merge(data);
- }
- }
-
- /**
- * Returns the {@link ExecutionData} entry with the given id if it exists in
- * this store.
- *
- * @param id
- * class id
- * @return execution data or <code>null</code>
- */
- public ExecutionData get(final long id) {
- return entries.get(Long.valueOf(id));
- }
-
- /**
- * Returns the coverage data for the class with the given identifier. If
- * there is no data available under the given id a new entry is created.
- *
- * @param id
- * class identifier
- * @param name
- * VM name of the class
- * @param dataLength
- * probe data length
- * @return execution data
- */
- public ExecutionData get(final Long id, final String name,
- final int dataLength) {
- ExecutionData entry = entries.get(id);
- if (entry == null) {
- entry = new ExecutionData(id.longValue(), name, dataLength);
- entries.put(id, entry);
- } else {
- entry.assertCompatibility(id.longValue(), name, dataLength);
- }
- return entry;
- }
-
- /**
- * Resets all execution data probes, i.e. marks them as not executed. The
- * execution data objects itself are not removed.
- */
- public void reset() {
- for (final ExecutionData executionData : this.entries.values()) {
- executionData.reset();
- }
- }
-
- /**
- * Returns a collection that represents current contents of the store.
- *
- * @return current contents
- */
- public Collection<ExecutionData> getContents() {
- return entries.values();
- }
-
- /**
- * Writes the content of the store to the given visitor interface.
- *
- * @param visitor
- * interface to write content to
- */
- public void accept(final IExecutionDataVisitor visitor) {
- for (final ExecutionData data : entries.values()) {
- visitor.visitClassExecution(data);
- }
- }
-
- // === IExecutionDataVisitor ===
-
- public void visitClassExecution(final ExecutionData data) {
- put(data);
- }
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * In-memory data store for execution data. The data can be added through its + * {@link IExecutionDataVisitor} interface. If execution data is provided + * multiple times for the same class the data is merged, i.e. a probe is marked + * as executed if it is reported as executed at least once. This allows to merge + * coverage date from multiple runs. A instance of this class is not thread + * safe. + */ +public final class ExecutionDataStore implements IExecutionDataVisitor { + + private final Map<Long, ExecutionData> entries = new HashMap<Long, ExecutionData>(); + + /** + * Adds the given {@link ExecutionData} object into the store. If there is + * already execution data with this same class id, this structure is merged + * with the given one. + * + * @param data + * execution data to add or merge + * @throws IllegalStateException + * if the given {@link ExecutionData} object is not compatible + * to a corresponding one, that is already contained + * @see ExecutionData#assertCompatibility(long, String, int) + */ + public void put(final ExecutionData data) throws IllegalStateException { + final Long id = Long.valueOf(data.getId()); + final ExecutionData entry = entries.get(id); + if (entry == null) { + entries.put(id, data); + } else { + entry.merge(data); + } + } + + /** + * Returns the {@link ExecutionData} entry with the given id if it exists in + * this store. + * + * @param id + * class id + * @return execution data or <code>null</code> + */ + public ExecutionData get(final long id) { + return entries.get(Long.valueOf(id)); + } + + /** + * Returns the coverage data for the class with the given identifier. If + * there is no data available under the given id a new entry is created. + * + * @param id + * class identifier + * @param name + * VM name of the class + * @param dataLength + * probe data length + * @return execution data + */ + public ExecutionData get(final Long id, final String name, + final int dataLength) { + ExecutionData entry = entries.get(id); + if (entry == null) { + entry = new ExecutionData(id.longValue(), name, dataLength); + entries.put(id, entry); + } else { + entry.assertCompatibility(id.longValue(), name, dataLength); + } + return entry; + } + + /** + * Resets all execution data probes, i.e. marks them as not executed. The + * execution data objects itself are not removed. + */ + public void reset() { + for (final ExecutionData executionData : this.entries.values()) { + executionData.reset(); + } + } + + /** + * Returns a collection that represents current contents of the store. + * + * @return current contents + */ + public Collection<ExecutionData> getContents() { + return entries.values(); + } + + /** + * Writes the content of the store to the given visitor interface. + * + * @param visitor + * interface to write content to + */ + public void accept(final IExecutionDataVisitor visitor) { + for (final ExecutionData data : entries.values()) { + visitor.visitClassExecution(data); + } + } + + // === IExecutionDataVisitor === + + public void visitClassExecution(final ExecutionData data) { + put(data); + } +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java index 2f42068e..33d8f627 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java @@ -1,119 +1,119 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.jacoco.core.internal.data.CompactDataOutput;
-
-/**
- * Serialization of execution data into binary streams.
- */
-public class ExecutionDataWriter implements ISessionInfoVisitor,
- IExecutionDataVisitor {
-
- /** File format version, will be incremented for each incompatible change. */
- public static final char FORMAT_VERSION = 0x1006;
-
- /** Magic number in header for file format identification. */
- public static final char MAGIC_NUMBER = 0xC0C0;
-
- /** Block identifier for file headers. */
- public static final byte BLOCK_HEADER = 0x01;
-
- /** Block identifier for session information. */
- public static final byte BLOCK_SESSIONINFO = 0x10;
-
- /** Block identifier for execution data of a single class. */
- public static final byte BLOCK_EXECUTIONDATA = 0x11;
-
- /** Underlying data output */
- protected final CompactDataOutput out;
-
- /**
- * Creates a new writer based on the given output stream. Depending on the
- * nature of the underlying stream output should be buffered as most data is
- * written in single bytes.
- *
- * @param output
- * binary stream to write execution data to
- * @throws IOException
- * if the header can't be written
- */
- public ExecutionDataWriter(final OutputStream output) throws IOException {
- this.out = new CompactDataOutput(output);
- writeHeader();
- }
-
- /**
- * Writes an file header to identify the stream and its protocol version.
- *
- * @throws IOException
- */
- private void writeHeader() throws IOException {
- out.writeByte(BLOCK_HEADER);
- out.writeChar(MAGIC_NUMBER);
- out.writeChar(FORMAT_VERSION);
- }
-
- /**
- * Flushes the underlying stream.
- *
- * @throws IOException
- */
- public void flush() throws IOException {
- out.flush();
- }
-
- public void visitSessionInfo(final SessionInfo info) {
- try {
- out.writeByte(BLOCK_SESSIONINFO);
- out.writeUTF(info.getId());
- out.writeLong(info.getStartTimeStamp());
- out.writeLong(info.getDumpTimeStamp());
- } catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public void visitClassExecution(final ExecutionData data) {
- try {
- out.writeByte(BLOCK_EXECUTIONDATA);
- out.writeLong(data.getId());
- out.writeUTF(data.getName());
- out.writeBooleanArray(data.getData());
- } catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Returns the first bytes of a file that represents a valid execution data
- * file. In any case every execution data file starts with the three bytes
- * <code>0x01 0xC0 0xC0</code>.
- *
- * @return first bytes of a execution data file
- */
- public static final byte[] getFileHeader() {
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- try {
- new ExecutionDataWriter(buffer);
- } catch (final IOException e) {
- // Must not happen with ByteArrayOutputStream
- throw new AssertionError(e);
- }
- return buffer.toByteArray();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.jacoco.core.internal.data.CompactDataOutput; + +/** + * Serialization of execution data into binary streams. + */ +public class ExecutionDataWriter implements ISessionInfoVisitor, + IExecutionDataVisitor { + + /** File format version, will be incremented for each incompatible change. */ + public static final char FORMAT_VERSION = 0x1006; + + /** Magic number in header for file format identification. */ + public static final char MAGIC_NUMBER = 0xC0C0; + + /** Block identifier for file headers. */ + public static final byte BLOCK_HEADER = 0x01; + + /** Block identifier for session information. */ + public static final byte BLOCK_SESSIONINFO = 0x10; + + /** Block identifier for execution data of a single class. */ + public static final byte BLOCK_EXECUTIONDATA = 0x11; + + /** Underlying data output */ + protected final CompactDataOutput out; + + /** + * Creates a new writer based on the given output stream. Depending on the + * nature of the underlying stream output should be buffered as most data is + * written in single bytes. + * + * @param output + * binary stream to write execution data to + * @throws IOException + * if the header can't be written + */ + public ExecutionDataWriter(final OutputStream output) throws IOException { + this.out = new CompactDataOutput(output); + writeHeader(); + } + + /** + * Writes an file header to identify the stream and its protocol version. + * + * @throws IOException + */ + private void writeHeader() throws IOException { + out.writeByte(BLOCK_HEADER); + out.writeChar(MAGIC_NUMBER); + out.writeChar(FORMAT_VERSION); + } + + /** + * Flushes the underlying stream. + * + * @throws IOException + */ + public void flush() throws IOException { + out.flush(); + } + + public void visitSessionInfo(final SessionInfo info) { + try { + out.writeByte(BLOCK_SESSIONINFO); + out.writeUTF(info.getId()); + out.writeLong(info.getStartTimeStamp()); + out.writeLong(info.getDumpTimeStamp()); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + public void visitClassExecution(final ExecutionData data) { + try { + out.writeByte(BLOCK_EXECUTIONDATA); + out.writeLong(data.getId()); + out.writeUTF(data.getName()); + out.writeBooleanArray(data.getData()); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the first bytes of a file that represents a valid execution data + * file. In any case every execution data file starts with the three bytes + * <code>0x01 0xC0 0xC0</code>. + * + * @return first bytes of a execution data file + */ + public static final byte[] getFileHeader() { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + try { + new ExecutionDataWriter(buffer); + } catch (final IOException e) { + // Must not happen with ByteArrayOutputStream + throw new AssertionError(e); + } + return buffer.toByteArray(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java index 15d1578c..94c5f0fb 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java @@ -1,29 +1,29 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-/**
- * Interface for data output of collected execution data. This interface is
- * meant to be implemented by parties that want to retrieve data from the
- * coverage runtime.
- */
-public interface IExecutionDataVisitor {
-
- /**
- * Provides execution data for a class.
- *
- * @param data
- * execution data for a class
- */
- public void visitClassExecution(ExecutionData data);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +/** + * Interface for data output of collected execution data. This interface is + * meant to be implemented by parties that want to retrieve data from the + * coverage runtime. + */ +public interface IExecutionDataVisitor { + + /** + * Provides execution data for a class. + * + * @param data + * execution data for a class + */ + public void visitClassExecution(ExecutionData data); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java b/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java index 10157348..35cf1c90 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java +++ b/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java @@ -1,83 +1,83 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.data;
-
-/**
- * Data object describing a session which was the source of execution data.
- * {@link SessionInfo} instances can be sorted by dump date through the
- * {@link Comparable} interface.
- */
-public class SessionInfo implements Comparable<SessionInfo> {
-
- private final String id;
-
- private final long start;
-
- private final long dump;
-
- /**
- * Create a immutable session info with the given data.
- *
- * @param id
- * arbitrary session identifier, must not be <code>null</code>
- * @param start
- * the epoc based time stamp when execution data recording has
- * been started
- * @param dump
- * the epoc based time stamp when execution data was collected
- */
- public SessionInfo(final String id, final long start, final long dump) {
- if (id == null) {
- throw new IllegalArgumentException();
- }
- this.id = id;
- this.start = start;
- this.dump = dump;
- }
-
- /**
- * @return identifier for this session
- */
- public String getId() {
- return id;
- }
-
- /**
- * @return the epoc based time stamp when execution data recording has been
- * started
- */
- public long getStartTimeStamp() {
- return start;
- }
-
- /**
- * @return the epoc based time stamp when execution data was collected
- */
- public long getDumpTimeStamp() {
- return dump;
- }
-
- public int compareTo(final SessionInfo other) {
- if (this.dump < other.dump) {
- return -1;
- }
- if (this.dump > other.dump) {
- return +1;
- }
- return 0;
- }
-
- @Override
- public String toString() {
- return "SessionInfo [" + id + "]";
- }
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.data; + +/** + * Data object describing a session which was the source of execution data. + * {@link SessionInfo} instances can be sorted by dump date through the + * {@link Comparable} interface. + */ +public class SessionInfo implements Comparable<SessionInfo> { + + private final String id; + + private final long start; + + private final long dump; + + /** + * Create a immutable session info with the given data. + * + * @param id + * arbitrary session identifier, must not be <code>null</code> + * @param start + * the epoc based time stamp when execution data recording has + * been started + * @param dump + * the epoc based time stamp when execution data was collected + */ + public SessionInfo(final String id, final long start, final long dump) { + if (id == null) { + throw new IllegalArgumentException(); + } + this.id = id; + this.start = start; + this.dump = dump; + } + + /** + * @return identifier for this session + */ + public String getId() { + return id; + } + + /** + * @return the epoc based time stamp when execution data recording has been + * started + */ + public long getStartTimeStamp() { + return start; + } + + /** + * @return the epoc based time stamp when execution data was collected + */ + public long getDumpTimeStamp() { + return dump; + } + + public int compareTo(final SessionInfo other) { + if (this.dump < other.dump) { + return -1; + } + if (this.dump > other.dump) { + return +1; + } + return 0; + } + + @Override + public String toString() { + return "SessionInfo [" + id + "]"; + } +} diff --git a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java index 07aa6c57..57b1aad9 100644 --- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java @@ -1,99 +1,99 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.instr;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.jacoco.core.internal.data.CRC64;
-import org.jacoco.core.internal.flow.ClassProbesAdapter;
-import org.jacoco.core.internal.instr.ClassInstrumenter;
-import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
-
-/**
- * Several APIs to instrument Java class definitions for coverage tracing.
- */
-public class Instrumenter {
-
- private final IExecutionDataAccessorGenerator accessGenerator;
-
- /**
- * Creates a new instance based on the given runtime.
- *
- * @param runtime
- * runtime used by the instrumented classes
- */
- public Instrumenter(final IExecutionDataAccessorGenerator runtime) {
- this.accessGenerator = runtime;
- }
-
- /**
- * Creates a ASM adapter for a class with the given id.
- *
- * @param classid
- * id of the class calculated with {@link CRC64}
- * @param cv
- * next class visitor in the chain
- * @return new visitor to write class definition to
- */
- private ClassVisitor createInstrumentingVisitor(final long classid,
- final ClassVisitor cv) {
- return new ClassProbesAdapter(new ClassInstrumenter(classid, accessGenerator,
- cv));
- }
-
- /**
- * Creates a instrumented version of the given class if possible.
- *
- * @param reader
- * definition of the class as ASM reader
- * @return instrumented definition or <code>null</code>
- *
- */
- public byte[] instrument(final ClassReader reader) {
- final ClassWriter writer = new ClassWriter(reader, 0);
- final ClassVisitor visitor = createInstrumentingVisitor(
- CRC64.checksum(reader.b), writer);
- reader.accept(visitor, ClassReader.EXPAND_FRAMES);
- return writer.toByteArray();
- }
-
- /**
- * Creates a instrumented version of the given class if possible.
- *
- * @param buffer
- * definition of the class
- * @return instrumented definition or <code>null</code>
- *
- */
- public byte[] instrument(final byte[] buffer) {
- return instrument(new ClassReader(buffer));
- }
-
- /**
- * Creates a instrumented version of the given class if possible.
- *
- * @param input
- * stream to read class definition from
- * @return instrumented definition or <code>null</code>
- * @throws IOException
- * if reading data from the stream fails
- *
- */
- public byte[] instrument(final InputStream input) throws IOException {
- return instrument(new ClassReader(input));
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.instr; + +import java.io.IOException; +import java.io.InputStream; + +import org.jacoco.core.internal.data.CRC64; +import org.jacoco.core.internal.flow.ClassProbesAdapter; +import org.jacoco.core.internal.instr.ClassInstrumenter; +import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; + +/** + * Several APIs to instrument Java class definitions for coverage tracing. + */ +public class Instrumenter { + + private final IExecutionDataAccessorGenerator accessGenerator; + + /** + * Creates a new instance based on the given runtime. + * + * @param runtime + * runtime used by the instrumented classes + */ + public Instrumenter(final IExecutionDataAccessorGenerator runtime) { + this.accessGenerator = runtime; + } + + /** + * Creates a ASM adapter for a class with the given id. + * + * @param classid + * id of the class calculated with {@link CRC64} + * @param cv + * next class visitor in the chain + * @return new visitor to write class definition to + */ + private ClassVisitor createInstrumentingVisitor(final long classid, + final ClassVisitor cv) { + return new ClassProbesAdapter(new ClassInstrumenter(classid, accessGenerator, + cv)); + } + + /** + * Creates a instrumented version of the given class if possible. + * + * @param reader + * definition of the class as ASM reader + * @return instrumented definition or <code>null</code> + * + */ + public byte[] instrument(final ClassReader reader) { + final ClassWriter writer = new ClassWriter(reader, 0); + final ClassVisitor visitor = createInstrumentingVisitor( + CRC64.checksum(reader.b), writer); + reader.accept(visitor, ClassReader.EXPAND_FRAMES); + return writer.toByteArray(); + } + + /** + * Creates a instrumented version of the given class if possible. + * + * @param buffer + * definition of the class + * @return instrumented definition or <code>null</code> + * + */ + public byte[] instrument(final byte[] buffer) { + return instrument(new ClassReader(buffer)); + } + + /** + * Creates a instrumented version of the given class if possible. + * + * @param input + * stream to read class definition from + * @return instrumented definition or <code>null</code> + * @throws IOException + * if reading data from the stream fails + * + */ + public byte[] instrument(final InputStream input) throws IOException { + return instrument(new ClassReader(input)); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java index 949f4a76..366ca742 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java @@ -1,116 +1,116 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.jacoco.core.analysis.CoverageNodeImpl;
-import org.jacoco.core.analysis.IBundleCoverage;
-import org.jacoco.core.analysis.IClassCoverage;
-import org.jacoco.core.analysis.IPackageCoverage;
-import org.jacoco.core.analysis.ISourceFileCoverage;
-
-/**
- * Implementation of {@link IBundleCoverage}.
- */
-public class BundleCoverageImpl extends CoverageNodeImpl implements
- IBundleCoverage {
-
- private final Collection<IPackageCoverage> packages;
-
- /**
- * Creates a new instance of a bundle with the given name.
- *
- * @param name
- * name of this bundle
- * @param packages
- * collection of all packages contained in this bundle
- */
- public BundleCoverageImpl(final String name,
- final Collection<IPackageCoverage> packages) {
- super(ElementType.BUNDLE, name);
- this.packages = packages;
- increment(packages);
- }
-
- /**
- * Creates a new instance of a bundle with the given name. The packages are
- * calculated from the given classes and source files.
- *
- * @param name
- * name of this bundle
- * @param classes
- * all classes in this bundle
- * @param sourcefiles
- * all source files in this bundle
- */
- public BundleCoverageImpl(final String name,
- final Collection<IClassCoverage> classes,
- final Collection<ISourceFileCoverage> sourcefiles) {
- this(name, groupByPackage(classes, sourcefiles));
- }
-
- private static Collection<IPackageCoverage> groupByPackage(
- final Collection<IClassCoverage> classes,
- final Collection<ISourceFileCoverage> sourcefiles) {
- final Map<String, Collection<IClassCoverage>> classesByPackage = new HashMap<String, Collection<IClassCoverage>>();
- for (final IClassCoverage c : classes) {
- addByName(classesByPackage, c.getPackageName(), c);
- }
-
- final Map<String, Collection<ISourceFileCoverage>> sourceFilesByPackage = new HashMap<String, Collection<ISourceFileCoverage>>();
- for (final ISourceFileCoverage s : sourcefiles) {
- addByName(sourceFilesByPackage, s.getPackageName(), s);
- }
-
- final Set<String> packageNames = new HashSet<String>();
- packageNames.addAll(classesByPackage.keySet());
- packageNames.addAll(sourceFilesByPackage.keySet());
-
- final Collection<IPackageCoverage> result = new ArrayList<IPackageCoverage>();
- for (final String name : packageNames) {
- Collection<IClassCoverage> c = classesByPackage.get(name);
- if (c == null) {
- c = Collections.emptyList();
- }
- Collection<ISourceFileCoverage> s = sourceFilesByPackage.get(name);
- if (s == null) {
- s = Collections.emptyList();
- }
- result.add(new PackageCoverageImpl(name, c, s));
- }
- return result;
- }
-
- private static <T> void addByName(final Map<String, Collection<T>> map,
- final String name, final T value) {
- Collection<T> list = map.get(name);
- if (list == null) {
- list = new ArrayList<T>();
- map.put(name, list);
- }
- list.add(value);
- }
-
- // === IBundleCoverage implementation ===
-
- public Collection<IPackageCoverage> getPackages() {
- return packages;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.jacoco.core.analysis.CoverageNodeImpl; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.IPackageCoverage; +import org.jacoco.core.analysis.ISourceFileCoverage; + +/** + * Implementation of {@link IBundleCoverage}. + */ +public class BundleCoverageImpl extends CoverageNodeImpl implements + IBundleCoverage { + + private final Collection<IPackageCoverage> packages; + + /** + * Creates a new instance of a bundle with the given name. + * + * @param name + * name of this bundle + * @param packages + * collection of all packages contained in this bundle + */ + public BundleCoverageImpl(final String name, + final Collection<IPackageCoverage> packages) { + super(ElementType.BUNDLE, name); + this.packages = packages; + increment(packages); + } + + /** + * Creates a new instance of a bundle with the given name. The packages are + * calculated from the given classes and source files. + * + * @param name + * name of this bundle + * @param classes + * all classes in this bundle + * @param sourcefiles + * all source files in this bundle + */ + public BundleCoverageImpl(final String name, + final Collection<IClassCoverage> classes, + final Collection<ISourceFileCoverage> sourcefiles) { + this(name, groupByPackage(classes, sourcefiles)); + } + + private static Collection<IPackageCoverage> groupByPackage( + final Collection<IClassCoverage> classes, + final Collection<ISourceFileCoverage> sourcefiles) { + final Map<String, Collection<IClassCoverage>> classesByPackage = new HashMap<String, Collection<IClassCoverage>>(); + for (final IClassCoverage c : classes) { + addByName(classesByPackage, c.getPackageName(), c); + } + + final Map<String, Collection<ISourceFileCoverage>> sourceFilesByPackage = new HashMap<String, Collection<ISourceFileCoverage>>(); + for (final ISourceFileCoverage s : sourcefiles) { + addByName(sourceFilesByPackage, s.getPackageName(), s); + } + + final Set<String> packageNames = new HashSet<String>(); + packageNames.addAll(classesByPackage.keySet()); + packageNames.addAll(sourceFilesByPackage.keySet()); + + final Collection<IPackageCoverage> result = new ArrayList<IPackageCoverage>(); + for (final String name : packageNames) { + Collection<IClassCoverage> c = classesByPackage.get(name); + if (c == null) { + c = Collections.emptyList(); + } + Collection<ISourceFileCoverage> s = sourceFilesByPackage.get(name); + if (s == null) { + s = Collections.emptyList(); + } + result.add(new PackageCoverageImpl(name, c, s)); + } + return result; + } + + private static <T> void addByName(final Map<String, Collection<T>> map, + final String name, final T value) { + Collection<T> list = map.get(name); + if (list == null) { + list = new ArrayList<T>(); + map.put(name, list); + } + list.add(value); + } + + // === IBundleCoverage implementation === + + public Collection<IPackageCoverage> getPackages() { + return packages; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java index dceca0b6..ce008f2f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java @@ -1,129 +1,129 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.IMethodCoverage;
-import org.jacoco.core.internal.flow.IClassProbesVisitor;
-import org.jacoco.core.internal.flow.IMethodProbesVisitor;
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.Attribute;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Analyzes the structure of a class.
- */
-public class ClassAnalyzer implements IClassProbesVisitor {
-
- private final long classid;
- private final boolean executionData[];
- private final StringPool stringPool;
-
- private ClassCoverageImpl coverage;
-
- /**
- * Creates a new analyzer that builds coverage data for a class.
- *
- * @param classid
- * id of the class
- * @param executionData
- * execution data for this class or <code>null</code>
- * @param stringPool
- * shared pool to minimize the number of {@link String} instances
- */
- public ClassAnalyzer(final long classid, final boolean[] executionData,
- final StringPool stringPool) {
- this.classid = classid;
- this.executionData = executionData;
- this.stringPool = stringPool;
- }
-
- /**
- * Returns the coverage data for this class after this visitor has been
- * processed.
- *
- * @return coverage data for this class
- */
- public ClassCoverageImpl getCoverage() {
- return coverage;
- }
-
- public void visit(final int version, final int access, final String name,
- final String signature, final String superName,
- final String[] interfaces) {
- this.coverage = new ClassCoverageImpl(stringPool.get(name), classid,
- stringPool.get(signature), stringPool.get(superName),
- stringPool.get(interfaces));
- }
-
- public void visitSource(final String source, final String debug) {
- this.coverage.setSourceFileName(stringPool.get(source));
- }
-
- public IMethodProbesVisitor visitMethod(final int access,
- final String name, final String desc, final String signature,
- final String[] exceptions) {
-
- // TODO: Use filter hook
- if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
- return null;
- }
-
- return new MethodAnalyzer(stringPool.get(name), stringPool.get(desc),
- stringPool.get(signature), executionData) {
- @Override
- public void visitEnd() {
- super.visitEnd();
- final IMethodCoverage methodCoverage = getCoverage();
- if (methodCoverage.getInstructionCounter().getTotalCount() > 0) {
- // Only consider methods that actually contain code
- coverage.addMethod(methodCoverage);
- }
- }
- };
- }
-
- public void visitTotalProbeCount(final int count) {
- // nothing to do
- }
-
- public AnnotationVisitor visitAnnotation(final String desc,
- final boolean visible) {
- // nothing to do
- return null;
- }
-
- public void visitAttribute(final Attribute attr) {
- // nothing to do
- }
-
- public FieldVisitor visitField(final int access, final String name,
- final String desc, final String signature, final Object value) {
- // nothing to do
- return null;
- }
-
- public void visitInnerClass(final String name, final String outerName,
- final String innerName, final int access) {
- // nothing to do
- }
-
- public void visitOuterClass(final String owner, final String name,
- final String desc) {
- // nothing to do
- }
-
- public void visitEnd() {
- // nothing to do
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.IMethodCoverage; +import org.jacoco.core.internal.flow.IClassProbesVisitor; +import org.jacoco.core.internal.flow.IMethodProbesVisitor; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Analyzes the structure of a class. + */ +public class ClassAnalyzer implements IClassProbesVisitor { + + private final long classid; + private final boolean executionData[]; + private final StringPool stringPool; + + private ClassCoverageImpl coverage; + + /** + * Creates a new analyzer that builds coverage data for a class. + * + * @param classid + * id of the class + * @param executionData + * execution data for this class or <code>null</code> + * @param stringPool + * shared pool to minimize the number of {@link String} instances + */ + public ClassAnalyzer(final long classid, final boolean[] executionData, + final StringPool stringPool) { + this.classid = classid; + this.executionData = executionData; + this.stringPool = stringPool; + } + + /** + * Returns the coverage data for this class after this visitor has been + * processed. + * + * @return coverage data for this class + */ + public ClassCoverageImpl getCoverage() { + return coverage; + } + + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + this.coverage = new ClassCoverageImpl(stringPool.get(name), classid, + stringPool.get(signature), stringPool.get(superName), + stringPool.get(interfaces)); + } + + public void visitSource(final String source, final String debug) { + this.coverage.setSourceFileName(stringPool.get(source)); + } + + public IMethodProbesVisitor visitMethod(final int access, + final String name, final String desc, final String signature, + final String[] exceptions) { + + // TODO: Use filter hook + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + return null; + } + + return new MethodAnalyzer(stringPool.get(name), stringPool.get(desc), + stringPool.get(signature), executionData) { + @Override + public void visitEnd() { + super.visitEnd(); + final IMethodCoverage methodCoverage = getCoverage(); + if (methodCoverage.getInstructionCounter().getTotalCount() > 0) { + // Only consider methods that actually contain code + coverage.addMethod(methodCoverage); + } + } + }; + } + + public void visitTotalProbeCount(final int count) { + // nothing to do + } + + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + // nothing to do + return null; + } + + public void visitAttribute(final Attribute attr) { + // nothing to do + } + + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + // nothing to do + return null; + } + + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { + // nothing to do + } + + public void visitOuterClass(final String owner, final String name, + final String desc) { + // nothing to do + } + + public void visitEnd() { + // nothing to do + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java index dd06a6bd..54479bbf 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java @@ -1,115 +1,115 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.jacoco.core.analysis.IClassCoverage;
-import org.jacoco.core.analysis.IMethodCoverage;
-
-/**
- * Implementation of {@link IClassCoverage}.
- */
-public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage {
-
- private final long id;
- private final String signature;
- private final String superName;
- private final String[] interfaces;
- private final Collection<IMethodCoverage> methods;
- private String sourceFileName;
-
- /**
- * Creates a class coverage data object with the given parameters.
- *
- * @param name
- * vm name of the class
- * @param id
- * class identifier
- * @param signature
- * vm signature of the class
- * @param superName
- * vm name of the superclass of this class
- * @param interfaces
- * vm names of interfaces of this class
- */
- public ClassCoverageImpl(final String name, final long id,
- final String signature, final String superName,
- final String[] interfaces) {
- super(ElementType.CLASS, name);
- this.id = id;
- this.signature = signature;
- this.superName = superName;
- this.interfaces = interfaces;
- this.methods = new ArrayList<IMethodCoverage>();
- this.classCounter = CounterImpl.COUNTER_1_0;
- }
-
- /**
- * Add a method to this class.
- *
- * @param method
- * method data to add
- */
- public void addMethod(final IMethodCoverage method) {
- this.methods.add(method);
- increment(method);
- // As class is considered as covered when at least one method is
- // covered:
- if (methodCounter.getCoveredCount() > 0) {
- this.classCounter = CounterImpl.COUNTER_0_1;
- }
- }
-
- /**
- * Sets the name of the corresponding source file for this class.
- *
- * @param sourceFileName
- * name of the source file
- */
- public void setSourceFileName(final String sourceFileName) {
- this.sourceFileName = sourceFileName;
- }
-
- // === IClassCoverage implementation ===
-
- public long getId() {
- return id;
- }
-
- public String getSignature() {
- return signature;
- }
-
- public String getSuperName() {
- return superName;
- }
-
- public String[] getInterfaceNames() {
- return interfaces;
- }
-
- public String getPackageName() {
- final int pos = getName().lastIndexOf('/');
- return pos == -1 ? "" : getName().substring(0, pos);
- }
-
- public String getSourceFileName() {
- return sourceFileName;
- }
-
- public Collection<IMethodCoverage> getMethods() {
- return methods;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import java.util.ArrayList; +import java.util.Collection; + +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.IMethodCoverage; + +/** + * Implementation of {@link IClassCoverage}. + */ +public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage { + + private final long id; + private final String signature; + private final String superName; + private final String[] interfaces; + private final Collection<IMethodCoverage> methods; + private String sourceFileName; + + /** + * Creates a class coverage data object with the given parameters. + * + * @param name + * vm name of the class + * @param id + * class identifier + * @param signature + * vm signature of the class + * @param superName + * vm name of the superclass of this class + * @param interfaces + * vm names of interfaces of this class + */ + public ClassCoverageImpl(final String name, final long id, + final String signature, final String superName, + final String[] interfaces) { + super(ElementType.CLASS, name); + this.id = id; + this.signature = signature; + this.superName = superName; + this.interfaces = interfaces; + this.methods = new ArrayList<IMethodCoverage>(); + this.classCounter = CounterImpl.COUNTER_1_0; + } + + /** + * Add a method to this class. + * + * @param method + * method data to add + */ + public void addMethod(final IMethodCoverage method) { + this.methods.add(method); + increment(method); + // As class is considered as covered when at least one method is + // covered: + if (methodCounter.getCoveredCount() > 0) { + this.classCounter = CounterImpl.COUNTER_0_1; + } + } + + /** + * Sets the name of the corresponding source file for this class. + * + * @param sourceFileName + * name of the source file + */ + public void setSourceFileName(final String sourceFileName) { + this.sourceFileName = sourceFileName; + } + + // === IClassCoverage implementation === + + public long getId() { + return id; + } + + public String getSignature() { + return signature; + } + + public String getSuperName() { + return superName; + } + + public String[] getInterfaceNames() { + return interfaces; + } + + public String getPackageName() { + final int pos = getName().lastIndexOf('/'); + return pos == -1 ? "" : getName().substring(0, pos); + } + + public String getSourceFileName() { + return sourceFileName; + } + + public Collection<IMethodCoverage> getMethods() { + return methods; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java index 33804396..d8e369fb 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java @@ -1,103 +1,103 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.objectweb.asm.Opcodes;
-
-/**
- * Detector for content types of binary streams based on a magic headers.
- */
-public class ContentTypeDetector {
-
- /** Unknown file type */
- public static final int UNKNOWN = -1;
-
- /** File type Java class */
- public static final int CLASSFILE = 0xcafebabe;
-
- /** File type ZIP archive */
- public static final int ZIPFILE = 0x504b0304;
-
- private static final int BUFFER_SIZE = 8;
-
- private final InputStream in;
-
- private final int type;
-
- /**
- * Creates a new detector based on the given input. To process the complete
- * original input afterwards use the stream returned by
- * {@link #getInputStream()}.
- *
- * @param in
- * input to read the header from
- * @throws IOException
- */
- public ContentTypeDetector(final InputStream in) throws IOException {
- if (in.markSupported()) {
- this.in = in;
- } else {
- this.in = new BufferedInputStream(in, BUFFER_SIZE);
- }
- this.in.mark(BUFFER_SIZE);
- this.type = determineType(this.in);
- this.in.reset();
- }
-
- private static int determineType(final InputStream in) throws IOException {
- switch (readInt(in)) {
- case ZIPFILE:
- return ZIPFILE;
- case CLASSFILE:
- // also verify version to distinguish from Mach Object files:
- switch (readInt(in)) {
- case Opcodes.V1_1:
- case Opcodes.V1_2:
- case Opcodes.V1_3:
- case Opcodes.V1_4:
- case Opcodes.V1_5:
- case Opcodes.V1_6:
- case Opcodes.V1_7:
- return CLASSFILE;
- }
- }
- return UNKNOWN;
- }
-
- private static int readInt(final InputStream in) throws IOException {
- return in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read();
- }
-
- /**
- * Returns an input stream instance to read the complete content (including
- * the header) of the underlying stream.
- *
- * @return input stream containing the complete content
- */
- public InputStream getInputStream() {
- return in;
- }
-
- /**
- * Returns the detected file type.
- *
- * @return file type
- */
- public int getType() {
- return type;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.objectweb.asm.Opcodes; + +/** + * Detector for content types of binary streams based on a magic headers. + */ +public class ContentTypeDetector { + + /** Unknown file type */ + public static final int UNKNOWN = -1; + + /** File type Java class */ + public static final int CLASSFILE = 0xcafebabe; + + /** File type ZIP archive */ + public static final int ZIPFILE = 0x504b0304; + + private static final int BUFFER_SIZE = 8; + + private final InputStream in; + + private final int type; + + /** + * Creates a new detector based on the given input. To process the complete + * original input afterwards use the stream returned by + * {@link #getInputStream()}. + * + * @param in + * input to read the header from + * @throws IOException + */ + public ContentTypeDetector(final InputStream in) throws IOException { + if (in.markSupported()) { + this.in = in; + } else { + this.in = new BufferedInputStream(in, BUFFER_SIZE); + } + this.in.mark(BUFFER_SIZE); + this.type = determineType(this.in); + this.in.reset(); + } + + private static int determineType(final InputStream in) throws IOException { + switch (readInt(in)) { + case ZIPFILE: + return ZIPFILE; + case CLASSFILE: + // also verify version to distinguish from Mach Object files: + switch (readInt(in)) { + case Opcodes.V1_1: + case Opcodes.V1_2: + case Opcodes.V1_3: + case Opcodes.V1_4: + case Opcodes.V1_5: + case Opcodes.V1_6: + case Opcodes.V1_7: + return CLASSFILE; + } + } + return UNKNOWN; + } + + private static int readInt(final InputStream in) throws IOException { + return in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read(); + } + + /** + * Returns an input stream instance to read the complete content (including + * the header) of the underlying stream. + * + * @return input stream containing the complete content + */ + public InputStream getInputStream() { + return in; + } + + /** + * Returns the detected file type. + * + * @return file type + */ + public int getType() { + return type; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java index d9d2ac30..de156923 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java @@ -1,203 +1,203 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.ICounter;
-
-/**
- * {@link ICounter} implementations. Implementing a factory pattern allows to
- * share counter instances.
- */
-public abstract class CounterImpl implements ICounter {
-
- /** Max counter value for which singletons are created */
- private static final int SINGLETON_LIMIT = 30;
-
- private static final CounterImpl[][] SINGLETONS = new CounterImpl[SINGLETON_LIMIT + 1][];
-
- static {
- for (int i = 0; i <= SINGLETON_LIMIT; i++) {
- SINGLETONS[i] = new CounterImpl[SINGLETON_LIMIT + 1];
- for (int j = 0; j <= SINGLETON_LIMIT; j++) {
- SINGLETONS[i][j] = new Fix(i, j);
- }
- }
- }
-
- /** Constant for Counter with 0/0 values. */
- public static final CounterImpl COUNTER_0_0 = SINGLETONS[0][0];
-
- /** Constant for Counter with 1/0 values. */
- public static final CounterImpl COUNTER_1_0 = SINGLETONS[1][0];
-
- /** Constant for Counter with 0/1 values. */
- public static final CounterImpl COUNTER_0_1 = SINGLETONS[0][1];
-
- /**
- * Mutable version of the counter.
- */
- private static class Var extends CounterImpl {
- public Var(final int missed, final int covered) {
- super(missed, covered);
- }
-
- @Override
- public CounterImpl increment(final int missed, final int covered) {
- this.missed += missed;
- this.covered += covered;
- return this;
- }
- }
-
- /**
- * Immutable version of the counter.
- */
- private static class Fix extends CounterImpl {
- public Fix(final int missed, final int covered) {
- super(missed, covered);
- }
-
- @Override
- public CounterImpl increment(final int missed, final int covered) {
- return getInstance(this.missed + missed, this.covered + covered);
- }
- }
-
- /**
- * Factory method to retrieve a counter with the given number of items.
- *
- * @param missed
- * number of missed items
- * @param covered
- * number of covered items
- * @return counter instance
- */
- public static CounterImpl getInstance(final int missed, final int covered) {
- if (missed <= SINGLETON_LIMIT && covered <= SINGLETON_LIMIT) {
- return SINGLETONS[missed][covered];
- } else {
- return new Var(missed, covered);
- }
- }
-
- /**
- * Factory method to retrieve a clone of the given counter.
- *
- * @param counter
- * counter to copy
- * @return counter instance
- */
- public static CounterImpl getInstance(final ICounter counter) {
- return getInstance(counter.getMissedCount(), counter.getCoveredCount());
- }
-
- /** number of missed items */
- protected int missed;
-
- /** number of covered items */
- protected int covered;
-
- /**
- * Creates a new instance with the given numbers.
- *
- * @param missed
- * number of missed items
- * @param covered
- * number of covered items
- */
- protected CounterImpl(final int missed, final int covered) {
- this.missed = missed;
- this.covered = covered;
- }
-
- /**
- * Returns a counter with values incremented by the numbers of the given
- * counter. It is up to the implementation whether this counter instance is
- * modified or a new instance is returned.
- *
- * @param counter
- * number of additional total and covered items
- * @return counter instance with incremented values
- */
- public CounterImpl increment(final ICounter counter) {
- return increment(counter.getMissedCount(), counter.getCoveredCount());
- }
-
- /**
- * Returns a counter with values incremented by the given numbers. It is up
- * to the implementation whether this counter instance is modified or a new
- * instance is returned.
- *
- * @param missed
- * number of missed items
- * @param covered
- * number of covered items
- * @return counter instance with incremented values
- */
- public abstract CounterImpl increment(int missed, int covered);
-
- // === ICounter implementation ===
-
- public int getTotalCount() {
- return missed + covered;
- }
-
- public int getCoveredCount() {
- return covered;
- }
-
- public int getMissedCount() {
- return missed;
- }
-
- public double getCoveredRatio() {
- return (double) covered / (missed + covered);
- }
-
- public double getMissedRatio() {
- return (double) missed / (missed + covered);
- }
-
- public int getStatus() {
- int status = covered > 0 ? FULLY_COVERED : EMPTY;
- if (missed > 0) {
- status |= NOT_COVERED;
- }
- return status;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (obj instanceof ICounter) {
- final ICounter that = (ICounter) obj;
- return this.missed == that.getMissedCount()
- && this.covered == that.getCoveredCount();
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return missed ^ covered * 17;
- }
-
- @Override
- public String toString() {
- final StringBuilder b = new StringBuilder("Counter["); //$NON-NLS-1$
- b.append(getMissedCount());
- b.append('/').append(getCoveredCount());
- b.append(']');
- return b.toString();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.ICounter; + +/** + * {@link ICounter} implementations. Implementing a factory pattern allows to + * share counter instances. + */ +public abstract class CounterImpl implements ICounter { + + /** Max counter value for which singletons are created */ + private static final int SINGLETON_LIMIT = 30; + + private static final CounterImpl[][] SINGLETONS = new CounterImpl[SINGLETON_LIMIT + 1][]; + + static { + for (int i = 0; i <= SINGLETON_LIMIT; i++) { + SINGLETONS[i] = new CounterImpl[SINGLETON_LIMIT + 1]; + for (int j = 0; j <= SINGLETON_LIMIT; j++) { + SINGLETONS[i][j] = new Fix(i, j); + } + } + } + + /** Constant for Counter with 0/0 values. */ + public static final CounterImpl COUNTER_0_0 = SINGLETONS[0][0]; + + /** Constant for Counter with 1/0 values. */ + public static final CounterImpl COUNTER_1_0 = SINGLETONS[1][0]; + + /** Constant for Counter with 0/1 values. */ + public static final CounterImpl COUNTER_0_1 = SINGLETONS[0][1]; + + /** + * Mutable version of the counter. + */ + private static class Var extends CounterImpl { + public Var(final int missed, final int covered) { + super(missed, covered); + } + + @Override + public CounterImpl increment(final int missed, final int covered) { + this.missed += missed; + this.covered += covered; + return this; + } + } + + /** + * Immutable version of the counter. + */ + private static class Fix extends CounterImpl { + public Fix(final int missed, final int covered) { + super(missed, covered); + } + + @Override + public CounterImpl increment(final int missed, final int covered) { + return getInstance(this.missed + missed, this.covered + covered); + } + } + + /** + * Factory method to retrieve a counter with the given number of items. + * + * @param missed + * number of missed items + * @param covered + * number of covered items + * @return counter instance + */ + public static CounterImpl getInstance(final int missed, final int covered) { + if (missed <= SINGLETON_LIMIT && covered <= SINGLETON_LIMIT) { + return SINGLETONS[missed][covered]; + } else { + return new Var(missed, covered); + } + } + + /** + * Factory method to retrieve a clone of the given counter. + * + * @param counter + * counter to copy + * @return counter instance + */ + public static CounterImpl getInstance(final ICounter counter) { + return getInstance(counter.getMissedCount(), counter.getCoveredCount()); + } + + /** number of missed items */ + protected int missed; + + /** number of covered items */ + protected int covered; + + /** + * Creates a new instance with the given numbers. + * + * @param missed + * number of missed items + * @param covered + * number of covered items + */ + protected CounterImpl(final int missed, final int covered) { + this.missed = missed; + this.covered = covered; + } + + /** + * Returns a counter with values incremented by the numbers of the given + * counter. It is up to the implementation whether this counter instance is + * modified or a new instance is returned. + * + * @param counter + * number of additional total and covered items + * @return counter instance with incremented values + */ + public CounterImpl increment(final ICounter counter) { + return increment(counter.getMissedCount(), counter.getCoveredCount()); + } + + /** + * Returns a counter with values incremented by the given numbers. It is up + * to the implementation whether this counter instance is modified or a new + * instance is returned. + * + * @param missed + * number of missed items + * @param covered + * number of covered items + * @return counter instance with incremented values + */ + public abstract CounterImpl increment(int missed, int covered); + + // === ICounter implementation === + + public int getTotalCount() { + return missed + covered; + } + + public int getCoveredCount() { + return covered; + } + + public int getMissedCount() { + return missed; + } + + public double getCoveredRatio() { + return (double) covered / (missed + covered); + } + + public double getMissedRatio() { + return (double) missed / (missed + covered); + } + + public int getStatus() { + int status = covered > 0 ? FULLY_COVERED : EMPTY; + if (missed > 0) { + status |= NOT_COVERED; + } + return status; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ICounter) { + final ICounter that = (ICounter) obj; + return this.missed == that.getMissedCount() + && this.covered == that.getCoveredCount(); + } else { + return false; + } + } + + @Override + public int hashCode() { + return missed ^ covered * 17; + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder("Counter["); //$NON-NLS-1$ + b.append(getMissedCount()); + b.append('/').append(getCoveredCount()); + b.append(']'); + return b.toString(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java index 649052f5..9313d402 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java @@ -1,149 +1,149 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.ICounter;
-import org.jacoco.core.analysis.ILine;
-
-/**
- * Implementation of {@link ILine}.
- */
-public abstract class LineImpl implements ILine {
-
- /** Max instruction counter value for which singletons are created */
- private static final int SINGLETON_INS_LIMIT = 8;
-
- /** Max branch counter value for which singletons are created */
- private static final int SINGLETON_BRA_LIMIT = 4;
-
- private static final LineImpl[][][][] SINGLETONS = new LineImpl[SINGLETON_INS_LIMIT + 1][][][];
-
- static {
- for (int i = 0; i <= SINGLETON_INS_LIMIT; i++) {
- SINGLETONS[i] = new LineImpl[SINGLETON_INS_LIMIT + 1][][];
- for (int j = 0; j <= SINGLETON_INS_LIMIT; j++) {
- SINGLETONS[i][j] = new LineImpl[SINGLETON_BRA_LIMIT + 1][];
- for (int k = 0; k <= SINGLETON_BRA_LIMIT; k++) {
- SINGLETONS[i][j][k] = new LineImpl[SINGLETON_BRA_LIMIT + 1];
- for (int l = 0; l <= SINGLETON_BRA_LIMIT; l++) {
- SINGLETONS[i][j][k][l] = new Fix(i, j, k, l);
- }
- }
- }
- }
- }
-
- /**
- * Empty line without instructions or branches.
- */
- public static final LineImpl EMPTY = SINGLETONS[0][0][0][0];
-
- private static LineImpl getInstance(final CounterImpl instructions,
- final CounterImpl branches) {
- final int im = instructions.getMissedCount();
- final int ic = instructions.getCoveredCount();
- final int bm = branches.getMissedCount();
- final int bc = branches.getCoveredCount();
- if (im <= SINGLETON_INS_LIMIT && ic <= SINGLETON_INS_LIMIT
- && bm <= SINGLETON_BRA_LIMIT && bc <= SINGLETON_BRA_LIMIT) {
- return SINGLETONS[im][ic][bm][bc];
- }
- return new Var(instructions, branches);
- }
-
- /**
- * Mutable version.
- */
- private static final class Var extends LineImpl {
- Var(final CounterImpl instructions, final CounterImpl branches) {
- super(instructions, branches);
- }
-
- @Override
- public LineImpl increment(final ICounter instructions,
- final ICounter branches) {
- this.instructions = this.instructions.increment(instructions);
- this.branches = this.branches.increment(branches);
- return this;
- }
- }
-
- /**
- * Immutable version.
- */
- private static final class Fix extends LineImpl {
- public Fix(final int im, final int ic, final int bm, final int bc) {
- super(CounterImpl.getInstance(im, ic), CounterImpl.getInstance(bm,
- bc));
- }
-
- @Override
- public LineImpl increment(final ICounter instructions,
- final ICounter branches) {
- return getInstance(this.instructions.increment(instructions),
- this.branches.increment(branches));
- }
- }
-
- /** instruction counter */
- protected CounterImpl instructions;
-
- /** branch counter */
- protected CounterImpl branches;
-
- private LineImpl(final CounterImpl instructions, final CounterImpl branches) {
- this.instructions = instructions;
- this.branches = branches;
- }
-
- /**
- * Adds the given counters to this line.
- *
- * @param instructions
- * instructions to add
- * @param branches
- * branches to add
- * @return instance with new counter values
- */
- public abstract LineImpl increment(final ICounter instructions,
- final ICounter branches);
-
- // === ILine implementation ===
-
- public int getStatus() {
- return instructions.getStatus() | branches.getStatus();
- }
-
- public ICounter getInstructionCounter() {
- return instructions;
- }
-
- public ICounter getBranchCounter() {
- return branches;
- }
-
- @Override
- public int hashCode() {
- return 23 * instructions.hashCode() ^ branches.hashCode();
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (obj instanceof ILine) {
- final ILine that = (ILine) obj;
- return this.instructions.equals(that.getInstructionCounter())
- && this.branches.equals(that.getBranchCounter());
- }
- return false;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.ILine; + +/** + * Implementation of {@link ILine}. + */ +public abstract class LineImpl implements ILine { + + /** Max instruction counter value for which singletons are created */ + private static final int SINGLETON_INS_LIMIT = 8; + + /** Max branch counter value for which singletons are created */ + private static final int SINGLETON_BRA_LIMIT = 4; + + private static final LineImpl[][][][] SINGLETONS = new LineImpl[SINGLETON_INS_LIMIT + 1][][][]; + + static { + for (int i = 0; i <= SINGLETON_INS_LIMIT; i++) { + SINGLETONS[i] = new LineImpl[SINGLETON_INS_LIMIT + 1][][]; + for (int j = 0; j <= SINGLETON_INS_LIMIT; j++) { + SINGLETONS[i][j] = new LineImpl[SINGLETON_BRA_LIMIT + 1][]; + for (int k = 0; k <= SINGLETON_BRA_LIMIT; k++) { + SINGLETONS[i][j][k] = new LineImpl[SINGLETON_BRA_LIMIT + 1]; + for (int l = 0; l <= SINGLETON_BRA_LIMIT; l++) { + SINGLETONS[i][j][k][l] = new Fix(i, j, k, l); + } + } + } + } + } + + /** + * Empty line without instructions or branches. + */ + public static final LineImpl EMPTY = SINGLETONS[0][0][0][0]; + + private static LineImpl getInstance(final CounterImpl instructions, + final CounterImpl branches) { + final int im = instructions.getMissedCount(); + final int ic = instructions.getCoveredCount(); + final int bm = branches.getMissedCount(); + final int bc = branches.getCoveredCount(); + if (im <= SINGLETON_INS_LIMIT && ic <= SINGLETON_INS_LIMIT + && bm <= SINGLETON_BRA_LIMIT && bc <= SINGLETON_BRA_LIMIT) { + return SINGLETONS[im][ic][bm][bc]; + } + return new Var(instructions, branches); + } + + /** + * Mutable version. + */ + private static final class Var extends LineImpl { + Var(final CounterImpl instructions, final CounterImpl branches) { + super(instructions, branches); + } + + @Override + public LineImpl increment(final ICounter instructions, + final ICounter branches) { + this.instructions = this.instructions.increment(instructions); + this.branches = this.branches.increment(branches); + return this; + } + } + + /** + * Immutable version. + */ + private static final class Fix extends LineImpl { + public Fix(final int im, final int ic, final int bm, final int bc) { + super(CounterImpl.getInstance(im, ic), CounterImpl.getInstance(bm, + bc)); + } + + @Override + public LineImpl increment(final ICounter instructions, + final ICounter branches) { + return getInstance(this.instructions.increment(instructions), + this.branches.increment(branches)); + } + } + + /** instruction counter */ + protected CounterImpl instructions; + + /** branch counter */ + protected CounterImpl branches; + + private LineImpl(final CounterImpl instructions, final CounterImpl branches) { + this.instructions = instructions; + this.branches = branches; + } + + /** + * Adds the given counters to this line. + * + * @param instructions + * instructions to add + * @param branches + * branches to add + * @return instance with new counter values + */ + public abstract LineImpl increment(final ICounter instructions, + final ICounter branches); + + // === ILine implementation === + + public int getStatus() { + return instructions.getStatus() | branches.getStatus(); + } + + public ICounter getInstructionCounter() { + return instructions; + } + + public ICounter getBranchCounter() { + return branches; + } + + @Override + public int hashCode() { + return 23 * instructions.hashCode() ^ branches.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ILine) { + final ILine that = (ILine) obj; + return this.instructions.equals(that.getInstructionCounter()) + && this.branches.equals(that.getBranchCounter()); + } + return false; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java index 7fd83fc1..9efe9252 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java @@ -1,77 +1,77 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.ICounter;
-import org.jacoco.core.analysis.IMethodCoverage;
-
-/**
- * Implementation of {@link IMethodCoverage}.
- */
-public class MethodCoverageImpl extends SourceNodeImpl implements
- IMethodCoverage {
-
- private final String desc;
-
- private final String signature;
-
- /**
- * Creates a method coverage data object with the given parameters.
- *
- * @param name
- * name of the method
- * @param desc
- * parameter description
- * @param signature
- * generic signature or <code>null</code>
- */
- public MethodCoverageImpl(final String name, final String desc,
- final String signature) {
- super(ElementType.METHOD, name);
- this.desc = desc;
- this.signature = signature;
- }
-
- @Override
- public void increment(final ICounter instructions, final ICounter branches,
- final int line) {
- super.increment(instructions, branches, line);
- // Additionally increment complexity counter:
- if (branches.getTotalCount() > 1) {
- final int c = Math.max(0, branches.getCoveredCount() - 1);
- final int m = Math.max(0, branches.getTotalCount() - c - 1);
- this.complexityCounter = this.complexityCounter.increment(m, c);
- }
- }
-
- /**
- * This method must be called exactly once after all instructions and
- * branches have been incremented for this method coverage node.
- */
- public void incrementMethodCounter() {
- final ICounter base = this.instructionCounter.getCoveredCount() == 0 ? CounterImpl.COUNTER_1_0
- : CounterImpl.COUNTER_0_1;
- this.methodCounter = this.methodCounter.increment(base);
- this.complexityCounter = this.complexityCounter.increment(base);
- }
-
- // === IMethodCoverage implementation ===
-
- public String getDesc() {
- return desc;
- }
-
- public String getSignature() {
- return signature;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.IMethodCoverage; + +/** + * Implementation of {@link IMethodCoverage}. + */ +public class MethodCoverageImpl extends SourceNodeImpl implements + IMethodCoverage { + + private final String desc; + + private final String signature; + + /** + * Creates a method coverage data object with the given parameters. + * + * @param name + * name of the method + * @param desc + * parameter description + * @param signature + * generic signature or <code>null</code> + */ + public MethodCoverageImpl(final String name, final String desc, + final String signature) { + super(ElementType.METHOD, name); + this.desc = desc; + this.signature = signature; + } + + @Override + public void increment(final ICounter instructions, final ICounter branches, + final int line) { + super.increment(instructions, branches, line); + // Additionally increment complexity counter: + if (branches.getTotalCount() > 1) { + final int c = Math.max(0, branches.getCoveredCount() - 1); + final int m = Math.max(0, branches.getTotalCount() - c - 1); + this.complexityCounter = this.complexityCounter.increment(m, c); + } + } + + /** + * This method must be called exactly once after all instructions and + * branches have been incremented for this method coverage node. + */ + public void incrementMethodCounter() { + final ICounter base = this.instructionCounter.getCoveredCount() == 0 ? CounterImpl.COUNTER_1_0 + : CounterImpl.COUNTER_0_1; + this.methodCounter = this.methodCounter.increment(base); + this.complexityCounter = this.complexityCounter.increment(base); + } + + // === IMethodCoverage implementation === + + public String getDesc() { + return desc; + } + + public String getSignature() { + return signature; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java index fc96d874..b62a7894 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java @@ -1,68 +1,68 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import java.util.Collection;
-
-import org.jacoco.core.analysis.CoverageNodeImpl;
-import org.jacoco.core.analysis.IClassCoverage;
-import org.jacoco.core.analysis.IPackageCoverage;
-import org.jacoco.core.analysis.ISourceFileCoverage;
-
-/**
- * Implementation of {@link IPackageCoverage}.
- */
-public class PackageCoverageImpl extends CoverageNodeImpl implements
- IPackageCoverage {
-
- private final Collection<IClassCoverage> classes;
-
- private final Collection<ISourceFileCoverage> sourceFiles;
-
- /**
- * Creates package node instance for a package with the given name.
- *
- * @param name
- * vm name of the package
- * @param classes
- * collection of all classes in this package
- * @param sourceFiles
- * collection of all source files in this package
- */
- public PackageCoverageImpl(final String name,
- final Collection<IClassCoverage> classes,
- final Collection<ISourceFileCoverage> sourceFiles) {
- super(ElementType.PACKAGE, name);
- this.classes = classes;
- this.sourceFiles = sourceFiles;
- increment(sourceFiles);
- for (final IClassCoverage c : classes) {
- // We need to add only classes without a source file reference.
- // Classes associated with a source file are already included in the
- // SourceFileCoverage objects.
- if (c.getSourceFileName() == null) {
- increment(c);
- }
- }
- }
-
- // === IPackageCoverage implementation ===
-
- public Collection<IClassCoverage> getClasses() {
- return classes;
- }
-
- public Collection<ISourceFileCoverage> getSourceFiles() {
- return sourceFiles;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import java.util.Collection; + +import org.jacoco.core.analysis.CoverageNodeImpl; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.IPackageCoverage; +import org.jacoco.core.analysis.ISourceFileCoverage; + +/** + * Implementation of {@link IPackageCoverage}. + */ +public class PackageCoverageImpl extends CoverageNodeImpl implements + IPackageCoverage { + + private final Collection<IClassCoverage> classes; + + private final Collection<ISourceFileCoverage> sourceFiles; + + /** + * Creates package node instance for a package with the given name. + * + * @param name + * vm name of the package + * @param classes + * collection of all classes in this package + * @param sourceFiles + * collection of all source files in this package + */ + public PackageCoverageImpl(final String name, + final Collection<IClassCoverage> classes, + final Collection<ISourceFileCoverage> sourceFiles) { + super(ElementType.PACKAGE, name); + this.classes = classes; + this.sourceFiles = sourceFiles; + increment(sourceFiles); + for (final IClassCoverage c : classes) { + // We need to add only classes without a source file reference. + // Classes associated with a source file are already included in the + // SourceFileCoverage objects. + if (c.getSourceFileName() == null) { + increment(c); + } + } + } + + // === IPackageCoverage implementation === + + public Collection<IClassCoverage> getClasses() { + return classes; + } + + public Collection<ISourceFileCoverage> getSourceFiles() { + return sourceFiles; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java index 734b2e27..66cf3137 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java @@ -1,43 +1,43 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.ISourceFileCoverage;
-
-/**
- * Implementation of {@link ISourceFileCoverage}.
- */
-public class SourceFileCoverageImpl extends SourceNodeImpl implements
- ISourceFileCoverage {
-
- private final String packagename;
-
- /**
- * Creates a source file data object with the given parameters.
- *
- * @param name
- * name of the source file
- * @param packagename
- * vm name of the package the source file belongs to
- */
- public SourceFileCoverageImpl(final String name, final String packagename) {
- super(ElementType.SOURCEFILE, name);
- this.packagename = packagename;
- }
-
- // === ISourceFileCoverage implementation ===
-
- public String getPackageName() {
- return packagename;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.ISourceFileCoverage; + +/** + * Implementation of {@link ISourceFileCoverage}. + */ +public class SourceFileCoverageImpl extends SourceNodeImpl implements + ISourceFileCoverage { + + private final String packagename; + + /** + * Creates a source file data object with the given parameters. + * + * @param name + * name of the source file + * @param packagename + * vm name of the package the source file belongs to + */ + public SourceFileCoverageImpl(final String name, final String packagename) { + super(ElementType.SOURCEFILE, name); + this.packagename = packagename; + } + + // === ISourceFileCoverage implementation === + + public String getPackageName() { + return packagename; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java index 2af89f7b..82aadff1 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java @@ -1,169 +1,169 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import org.jacoco.core.analysis.CoverageNodeImpl;
-import org.jacoco.core.analysis.ICounter;
-import org.jacoco.core.analysis.ILine;
-import org.jacoco.core.analysis.ISourceNode;
-
-/**
- * Implementation of {@link ISourceNode}.
- */
-public class SourceNodeImpl extends CoverageNodeImpl implements ISourceNode {
-
- private LineImpl[] lines;
-
- /** first line number in {@link #lines} */
- private int offset;
-
- /**
- * Create a new source node implementation instance.
- *
- * @param elementType
- * element type
- * @param name
- * name of the element
- */
- public SourceNodeImpl(final ElementType elementType, final String name) {
- super(elementType, name);
- lines = null;
- offset = UNKNOWN_LINE;
- }
-
- /**
- * Make sure that the internal buffer can keep lines from first to last.
- * While the buffer is also incremented automatically, this method allows
- * optimization in case the total range in known in advance.
- *
- * @param first
- * first line number or {@link ISourceNode#UNKNOWN_LINE}
- * @param last
- * last line number or {@link ISourceNode#UNKNOWN_LINE}
- */
- public void ensureCapacity(final int first, final int last) {
- if (first == UNKNOWN_LINE || last == UNKNOWN_LINE) {
- return;
- }
- if (lines == null) {
- offset = first;
- lines = new LineImpl[last - first + 1];
- } else {
- final int newFirst = Math.min(getFirstLine(), first);
- final int newLast = Math.max(getLastLine(), last);
- final int newLength = newLast - newFirst + 1;
- if (newLength > lines.length) {
- final LineImpl[] newLines = new LineImpl[newLength];
- System.arraycopy(lines, 0, newLines, offset - newFirst,
- lines.length);
- offset = newFirst;
- lines = newLines;
- }
- }
- }
-
- /**
- * Increments all counters by the values of the given child. When
- * incrementing the line counter it is assumed that the child refers to the
- * same source file.
- *
- * @param child
- * child node to add
- */
- public void increment(final ISourceNode child) {
- instructionCounter = instructionCounter.increment(child
- .getInstructionCounter());
- branchCounter = branchCounter.increment(child.getBranchCounter());
- complexityCounter = complexityCounter.increment(child
- .getComplexityCounter());
- methodCounter = methodCounter.increment(child.getMethodCounter());
- classCounter = classCounter.increment(child.getClassCounter());
- final int firstLine = child.getFirstLine();
- if (firstLine != UNKNOWN_LINE) {
- final int lastLine = child.getLastLine();
- ensureCapacity(firstLine, lastLine);
- for (int i = firstLine; i <= lastLine; i++) {
- final ILine line = child.getLine(i);
- incrementLine(line.getInstructionCounter(),
- line.getBranchCounter(), i);
- }
- }
- }
-
- /**
- * Increments instructions and branches by the given counter values. If a
- * optional line number is specified the instructions and branches are added
- * to the given line. The line counter is incremented accordingly.
- *
- * @param instructions
- * instructions to add
- * @param branches
- * branches to add
- * @param line
- * optional line number or {@link ISourceNode#UNKNOWN_LINE}
- */
- public void increment(final ICounter instructions, final ICounter branches,
- final int line) {
- if (line != UNKNOWN_LINE) {
- incrementLine(instructions, branches, line);
- }
- instructionCounter = instructionCounter.increment(instructions);
- branchCounter = branchCounter.increment(branches);
- }
-
- private void incrementLine(final ICounter instructions,
- final ICounter branches, final int line) {
- ensureCapacity(line, line);
- final LineImpl l = getLine(line);
- final int oldTotal = l.getInstructionCounter().getTotalCount();
- final int oldCovered = l.getInstructionCounter().getCoveredCount();
- lines[line - offset] = l.increment(instructions, branches);
-
- // Increment line counter:
- if (instructions.getTotalCount() > 0) {
- if (instructions.getCoveredCount() == 0) {
- if (oldTotal == 0) {
- lineCounter = lineCounter
- .increment(CounterImpl.COUNTER_1_0);
- }
- } else {
- if (oldTotal == 0) {
- lineCounter = lineCounter
- .increment(CounterImpl.COUNTER_0_1);
- } else {
- if (oldCovered == 0) {
- lineCounter = lineCounter.increment(-1, +1);
- }
- }
- }
- }
- }
-
- // === ISourceNode implementation ===
-
- public int getFirstLine() {
- return offset;
- }
-
- public int getLastLine() {
- return lines == null ? UNKNOWN_LINE : (offset + lines.length - 1);
- }
-
- public LineImpl getLine(final int nr) {
- if (lines == null || nr < getFirstLine() || nr > getLastLine()) {
- return LineImpl.EMPTY;
- }
- final LineImpl line = lines[nr - offset];
- return line == null ? LineImpl.EMPTY : line;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import org.jacoco.core.analysis.CoverageNodeImpl; +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.ILine; +import org.jacoco.core.analysis.ISourceNode; + +/** + * Implementation of {@link ISourceNode}. + */ +public class SourceNodeImpl extends CoverageNodeImpl implements ISourceNode { + + private LineImpl[] lines; + + /** first line number in {@link #lines} */ + private int offset; + + /** + * Create a new source node implementation instance. + * + * @param elementType + * element type + * @param name + * name of the element + */ + public SourceNodeImpl(final ElementType elementType, final String name) { + super(elementType, name); + lines = null; + offset = UNKNOWN_LINE; + } + + /** + * Make sure that the internal buffer can keep lines from first to last. + * While the buffer is also incremented automatically, this method allows + * optimization in case the total range in known in advance. + * + * @param first + * first line number or {@link ISourceNode#UNKNOWN_LINE} + * @param last + * last line number or {@link ISourceNode#UNKNOWN_LINE} + */ + public void ensureCapacity(final int first, final int last) { + if (first == UNKNOWN_LINE || last == UNKNOWN_LINE) { + return; + } + if (lines == null) { + offset = first; + lines = new LineImpl[last - first + 1]; + } else { + final int newFirst = Math.min(getFirstLine(), first); + final int newLast = Math.max(getLastLine(), last); + final int newLength = newLast - newFirst + 1; + if (newLength > lines.length) { + final LineImpl[] newLines = new LineImpl[newLength]; + System.arraycopy(lines, 0, newLines, offset - newFirst, + lines.length); + offset = newFirst; + lines = newLines; + } + } + } + + /** + * Increments all counters by the values of the given child. When + * incrementing the line counter it is assumed that the child refers to the + * same source file. + * + * @param child + * child node to add + */ + public void increment(final ISourceNode child) { + instructionCounter = instructionCounter.increment(child + .getInstructionCounter()); + branchCounter = branchCounter.increment(child.getBranchCounter()); + complexityCounter = complexityCounter.increment(child + .getComplexityCounter()); + methodCounter = methodCounter.increment(child.getMethodCounter()); + classCounter = classCounter.increment(child.getClassCounter()); + final int firstLine = child.getFirstLine(); + if (firstLine != UNKNOWN_LINE) { + final int lastLine = child.getLastLine(); + ensureCapacity(firstLine, lastLine); + for (int i = firstLine; i <= lastLine; i++) { + final ILine line = child.getLine(i); + incrementLine(line.getInstructionCounter(), + line.getBranchCounter(), i); + } + } + } + + /** + * Increments instructions and branches by the given counter values. If a + * optional line number is specified the instructions and branches are added + * to the given line. The line counter is incremented accordingly. + * + * @param instructions + * instructions to add + * @param branches + * branches to add + * @param line + * optional line number or {@link ISourceNode#UNKNOWN_LINE} + */ + public void increment(final ICounter instructions, final ICounter branches, + final int line) { + if (line != UNKNOWN_LINE) { + incrementLine(instructions, branches, line); + } + instructionCounter = instructionCounter.increment(instructions); + branchCounter = branchCounter.increment(branches); + } + + private void incrementLine(final ICounter instructions, + final ICounter branches, final int line) { + ensureCapacity(line, line); + final LineImpl l = getLine(line); + final int oldTotal = l.getInstructionCounter().getTotalCount(); + final int oldCovered = l.getInstructionCounter().getCoveredCount(); + lines[line - offset] = l.increment(instructions, branches); + + // Increment line counter: + if (instructions.getTotalCount() > 0) { + if (instructions.getCoveredCount() == 0) { + if (oldTotal == 0) { + lineCounter = lineCounter + .increment(CounterImpl.COUNTER_1_0); + } + } else { + if (oldTotal == 0) { + lineCounter = lineCounter + .increment(CounterImpl.COUNTER_0_1); + } else { + if (oldCovered == 0) { + lineCounter = lineCounter.increment(-1, +1); + } + } + } + } + } + + // === ISourceNode implementation === + + public int getFirstLine() { + return offset; + } + + public int getLastLine() { + return lines == null ? UNKNOWN_LINE : (offset + lines.length - 1); + } + + public LineImpl getLine(final int nr) { + if (lines == null || nr < getFirstLine() || nr > getLastLine()) { + return LineImpl.EMPTY; + } + final LineImpl line = lines[nr - offset]; + return line == null ? LineImpl.EMPTY : line; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java index 0480a2ce..090dfd83 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java @@ -1,73 +1,73 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Brock Janiczak - analysis and concept
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Utility to normalize {@link String} instances in a way that if
- * <code>equals()</code> is <code>true</code> for two strings they will be
- * represented the same instance. While this is exactly what
- * {@link String#intern()} does, this implementation avoids VM specific side
- * effects and is supposed to be faster, as neither native code is called nor
- * synchronization is required for concurrent lookup.
- */
-public final class StringPool {
-
- private static final String[] EMPTY_ARRAY = new String[0];
-
- private final Map<String, String> pool = new HashMap<String, String>(1024);
-
- /**
- * Returns a normalized instance that is equal to the given {@link String} .
- *
- * @param s
- * any string or <code>null</code>
- * @return normalized instance or <code>null</code>
- */
- public String get(final String s) {
- if (s == null) {
- return null;
- }
- final String norm = pool.get(s);
- if (norm == null) {
- pool.put(s, s);
- return s;
- }
- return norm;
- }
-
- /**
- * Returns a modified version of the array with all string slots normalized.
- * It is up to the implementation to replace strings in the array instance
- * or return a new array instance.
- *
- * @param arr
- * String array or <code>null</code>
- * @return normalized instance or <code>null</code>
- */
- public String[] get(final String[] arr) {
- if (arr == null) {
- return null;
- }
- if (arr.length == 0) {
- return EMPTY_ARRAY;
- }
- for (int i = 0; i < arr.length; i++) {
- arr[i] = get(arr[i]);
- }
- return arr;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Brock Janiczak - analysis and concept + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis; + +import java.util.HashMap; +import java.util.Map; + +/** + * Utility to normalize {@link String} instances in a way that if + * <code>equals()</code> is <code>true</code> for two strings they will be + * represented the same instance. While this is exactly what + * {@link String#intern()} does, this implementation avoids VM specific side + * effects and is supposed to be faster, as neither native code is called nor + * synchronization is required for concurrent lookup. + */ +public final class StringPool { + + private static final String[] EMPTY_ARRAY = new String[0]; + + private final Map<String, String> pool = new HashMap<String, String>(1024); + + /** + * Returns a normalized instance that is equal to the given {@link String} . + * + * @param s + * any string or <code>null</code> + * @return normalized instance or <code>null</code> + */ + public String get(final String s) { + if (s == null) { + return null; + } + final String norm = pool.get(s); + if (norm == null) { + pool.put(s, s); + return s; + } + return norm; + } + + /** + * Returns a modified version of the array with all string slots normalized. + * It is up to the implementation to replace strings in the array instance + * or return a new array instance. + * + * @param arr + * String array or <code>null</code> + * @return normalized instance or <code>null</code> + */ + public String[] get(final String[] arr) { + if (arr == null) { + return null; + } + if (arr.length == 0) { + return EMPTY_ARRAY; + } + for (int i = 0; i < arr.length; i++) { + arr[i] = get(arr[i]); + } + return arr; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java index fe84e7ca..14f9ba7b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java @@ -1,63 +1,63 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.data;
-
-/**
- * CRC64 checksum calculator based on the polynom specified in ISO 3309. The
- * implementation is based on the following publications:
- *
- * <ul>
- * <li>http://en.wikipedia.org/wiki/Cyclic_redundancy_check</li>
- * <li>http://www.geocities.com/SiliconValley/Pines/8659/crc.htm</li>
- * </ul>
- */
-public final class CRC64 {
-
- private static final long POLY64REV = 0xd800000000000000L;
-
- private static final long[] LOOKUPTABLE;
-
- static {
- LOOKUPTABLE = new long[0x100];
- for (int i = 0; i < 0x100; i++) {
- long v = i;
- for (int j = 0; j < 8; j++) {
- if ((v & 1) == 1) {
- v = (v >>> 1) ^ POLY64REV;
- } else {
- v = (v >>> 1);
- }
- }
- LOOKUPTABLE[i] = v;
- }
- }
-
- /**
- * Calculates the CRC64 checksum for the given data array.
- *
- * @param data
- * data to calculate checksum for
- * @return checksum value
- */
- public static long checksum(final byte[] data) {
- long sum = 0;
- for (int i = 0; i < data.length; i++) {
- final int lookupidx = ((int) sum ^ data[i]) & 0xff;
- sum = (sum >>> 8) ^ LOOKUPTABLE[lookupidx];
- }
- return sum;
- }
-
- private CRC64() {
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.data; + +/** + * CRC64 checksum calculator based on the polynom specified in ISO 3309. The + * implementation is based on the following publications: + * + * <ul> + * <li>http://en.wikipedia.org/wiki/Cyclic_redundancy_check</li> + * <li>http://www.geocities.com/SiliconValley/Pines/8659/crc.htm</li> + * </ul> + */ +public final class CRC64 { + + private static final long POLY64REV = 0xd800000000000000L; + + private static final long[] LOOKUPTABLE; + + static { + LOOKUPTABLE = new long[0x100]; + for (int i = 0; i < 0x100; i++) { + long v = i; + for (int j = 0; j < 8; j++) { + if ((v & 1) == 1) { + v = (v >>> 1) ^ POLY64REV; + } else { + v = (v >>> 1); + } + } + LOOKUPTABLE[i] = v; + } + } + + /** + * Calculates the CRC64 checksum for the given data array. + * + * @param data + * data to calculate checksum for + * @return checksum value + */ + public static long checksum(final byte[] data) { + long sum = 0; + for (int i = 0; i < data.length; i++) { + final int lookupidx = ((int) sum ^ data[i]) & 0xff; + sum = (sum >>> 8) ^ LOOKUPTABLE[lookupidx]; + } + return sum; + } + + private CRC64() { + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java index b4afed7b..6875a53f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java @@ -1,70 +1,70 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.data;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Additional data input methods for compact storage of data structures.
- *
- * @see CompactDataOutput
- */
-public class CompactDataInput extends DataInputStream {
-
- /**
- * Creates a new {@link CompactDataInput} that uses the specified underlying
- * input stream.
- *
- * @param in
- * underlying input stream
- */
- public CompactDataInput(final InputStream in) {
- super(in);
- }
-
- /**
- * Reads a variable length representation of an integer value.
- *
- * @return read value
- * @throws IOException
- * might be thrown by the underlying stream
- */
- public int readVarInt() throws IOException {
- final int value = 0xFF & readByte();
- if ((value & 0x80) == 0) {
- return value;
- }
- return (value & 0x7F) | (readVarInt() << 7);
- }
-
- /**
- * Reads a boolean array.
- *
- * @return boolean array
- * @throws IOException
- */
- public boolean[] readBooleanArray() throws IOException {
- final boolean[] value = new boolean[readVarInt()];
- int buffer = 0;
- for (int i = 0; i < value.length; i++) {
- if ((i % 8) == 0) {
- buffer = readByte();
- }
- value[i] = (buffer & 0x01) != 0;
- buffer >>>= 1;
- }
- return value;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.data; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Additional data input methods for compact storage of data structures. + * + * @see CompactDataOutput + */ +public class CompactDataInput extends DataInputStream { + + /** + * Creates a new {@link CompactDataInput} that uses the specified underlying + * input stream. + * + * @param in + * underlying input stream + */ + public CompactDataInput(final InputStream in) { + super(in); + } + + /** + * Reads a variable length representation of an integer value. + * + * @return read value + * @throws IOException + * might be thrown by the underlying stream + */ + public int readVarInt() throws IOException { + final int value = 0xFF & readByte(); + if ((value & 0x80) == 0) { + return value; + } + return (value & 0x7F) | (readVarInt() << 7); + } + + /** + * Reads a boolean array. + * + * @return boolean array + * @throws IOException + */ + public boolean[] readBooleanArray() throws IOException { + final boolean[] value = new boolean[readVarInt()]; + int buffer = 0; + for (int i = 0; i < value.length; i++) { + if ((i % 8) == 0) { + buffer = readByte(); + } + value[i] = (buffer & 0x01) != 0; + buffer >>>= 1; + } + return value; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java index bcc65c6f..4b8489b6 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java @@ -1,81 +1,81 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.data;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * Additional data output methods for compact storage of data structures.
- *
- * @see CompactDataInput
- */
-public class CompactDataOutput extends DataOutputStream {
-
- /**
- * Creates a new {@link CompactDataOutput} instance that writes data to the
- * specified underlying output stream
- *
- * @param out
- * underlying output stream
- */
- public CompactDataOutput(final OutputStream out) {
- super(out);
- }
-
- /**
- * Writes a variable length representation of an integer value that reduces
- * the number of written bytes for small positive values. Depending on the
- * given value 1 to 5 bytes will be written to the underlying stream.
- *
- * @param value
- * value to write
- * @throws IOException
- */
- public void writeVarInt(final int value) throws IOException {
- if ((value & 0xFFFFFF80) == 0) {
- writeByte(value);
- } else {
- writeByte(0x80 | (value & 0x7F));
- writeVarInt(value >>> 7);
- }
- }
-
- /**
- * Writes a boolean array. Internally a sequence of boolean values is packed
- * into single bits.
- *
- * @param value
- * boolean array
- * @throws IOException
- */
- public void writeBooleanArray(final boolean[] value) throws IOException {
- writeVarInt(value.length);
- int buffer = 0;
- int bufferSize = 0;
- for (final boolean b : value) {
- if (b) {
- buffer |= 0x01 << bufferSize;
- }
- if (++bufferSize == 8) {
- writeByte(buffer);
- buffer = 0;
- bufferSize = 0;
- }
- }
- if (bufferSize > 0) {
- writeByte(buffer);
- }
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.data; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Additional data output methods for compact storage of data structures. + * + * @see CompactDataInput + */ +public class CompactDataOutput extends DataOutputStream { + + /** + * Creates a new {@link CompactDataOutput} instance that writes data to the + * specified underlying output stream + * + * @param out + * underlying output stream + */ + public CompactDataOutput(final OutputStream out) { + super(out); + } + + /** + * Writes a variable length representation of an integer value that reduces + * the number of written bytes for small positive values. Depending on the + * given value 1 to 5 bytes will be written to the underlying stream. + * + * @param value + * value to write + * @throws IOException + */ + public void writeVarInt(final int value) throws IOException { + if ((value & 0xFFFFFF80) == 0) { + writeByte(value); + } else { + writeByte(0x80 | (value & 0x7F)); + writeVarInt(value >>> 7); + } + } + + /** + * Writes a boolean array. Internally a sequence of boolean values is packed + * into single bits. + * + * @param value + * boolean array + * @throws IOException + */ + public void writeBooleanArray(final boolean[] value) throws IOException { + writeVarInt(value.length); + int buffer = 0; + int bufferSize = 0; + for (final boolean b : value) { + if (b) { + buffer |= 0x01 << bufferSize; + } + if (++bufferSize == 8) { + writeByte(buffer); + buffer = 0; + bufferSize = 0; + } + } + if (bufferSize > 0) { + writeByte(buffer); + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java index e542c3d1..d342dc79 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java @@ -1,137 +1,137 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.ClassAdapter;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.commons.EmptyVisitor;
-
-/**
- * A {@link org.objectweb.asm.ClassVisitor} that calculates probes for every
- * method.
- */
-public class ClassProbesAdapter extends ClassAdapter implements
- IProbeIdGenerator {
-
- private static final IMethodProbesVisitor EMPTY_METHOD_PROBES_VISITOR;
-
- static {
- class Impl extends EmptyVisitor implements IMethodProbesVisitor {
-
- public void visitProbe(final int probeId) {
- // nothing to do
- }
-
- public void visitJumpInsnWithProbe(final int opcode,
- final Label label, final int probeId) {
- // nothing to do
- }
-
- public void visitInsnWithProbe(final int opcode, final int probeId) {
- // nothing to do
- }
-
- public void visitTableSwitchInsnWithProbes(final int min,
- final int max, final Label dflt, final Label[] labels) {
- // nothing to do
- }
-
- public void visitLookupSwitchInsnWithProbes(final Label dflt,
- final int[] keys, final Label[] labels) {
- // nothing to do
- }
- }
- EMPTY_METHOD_PROBES_VISITOR = new Impl();
- }
-
- private static class ProbeCounter implements IProbeIdGenerator {
- int count = 0;
-
- public int nextId() {
- return count++;
- }
- }
-
- private final IClassProbesVisitor cv;
-
- private int counter = 0;
-
- private boolean interfaceType;
-
- /**
- * Creates a new adapter that delegates to the given visitor.
- *
- * @param cv
- * instance to delegate to
- */
- public ClassProbesAdapter(final IClassProbesVisitor cv) {
- super(cv);
- this.cv = cv;
- }
-
- @Override
- public void visit(final int version, final int access, final String name,
- final String signature, final String superName,
- final String[] interfaces) {
- interfaceType = (access & Opcodes.ACC_INTERFACE) != 0;
- super.visit(version, access, name, signature, superName, interfaces);
- }
-
- @Override
- public final MethodVisitor visitMethod(final int access, final String name,
- final String desc, final String signature, final String[] exceptions) {
- final IMethodProbesVisitor methodProbes;
- final IMethodProbesVisitor mv = cv.visitMethod(access, name, desc,
- signature, exceptions);
- if (mv == null) {
- // We need to visit the method in any case, otherwise probe ids
- // are not reproducible
- methodProbes = EMPTY_METHOD_PROBES_VISITOR;
- } else {
- methodProbes = mv;
- }
- return new MethodSanitizer(null, access, name, desc, signature,
- exceptions) {
-
- @Override
- public void visitEnd() {
- super.visitEnd();
- this.accept(new LabelFlowAnalyzer());
- if (interfaceType) {
- final ProbeCounter probeCounter = new ProbeCounter();
- this.accept(new MethodProbesAdapter(
- EMPTY_METHOD_PROBES_VISITOR, probeCounter));
- cv.visitTotalProbeCount(probeCounter.count);
- }
- this.accept(new MethodProbesAdapter(methodProbes,
- ClassProbesAdapter.this));
- }
- };
- }
-
- @Override
- public void visitEnd() {
- if (!interfaceType) {
- cv.visitTotalProbeCount(counter);
- }
- super.visitEnd();
- }
-
- // === IProbeIdGenerator ===
-
- public int nextId() {
- return counter++;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.EmptyVisitor; + +/** + * A {@link org.objectweb.asm.ClassVisitor} that calculates probes for every + * method. + */ +public class ClassProbesAdapter extends ClassAdapter implements + IProbeIdGenerator { + + private static final IMethodProbesVisitor EMPTY_METHOD_PROBES_VISITOR; + + static { + class Impl extends EmptyVisitor implements IMethodProbesVisitor { + + public void visitProbe(final int probeId) { + // nothing to do + } + + public void visitJumpInsnWithProbe(final int opcode, + final Label label, final int probeId) { + // nothing to do + } + + public void visitInsnWithProbe(final int opcode, final int probeId) { + // nothing to do + } + + public void visitTableSwitchInsnWithProbes(final int min, + final int max, final Label dflt, final Label[] labels) { + // nothing to do + } + + public void visitLookupSwitchInsnWithProbes(final Label dflt, + final int[] keys, final Label[] labels) { + // nothing to do + } + } + EMPTY_METHOD_PROBES_VISITOR = new Impl(); + } + + private static class ProbeCounter implements IProbeIdGenerator { + int count = 0; + + public int nextId() { + return count++; + } + } + + private final IClassProbesVisitor cv; + + private int counter = 0; + + private boolean interfaceType; + + /** + * Creates a new adapter that delegates to the given visitor. + * + * @param cv + * instance to delegate to + */ + public ClassProbesAdapter(final IClassProbesVisitor cv) { + super(cv); + this.cv = cv; + } + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + interfaceType = (access & Opcodes.ACC_INTERFACE) != 0; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public final MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + final IMethodProbesVisitor methodProbes; + final IMethodProbesVisitor mv = cv.visitMethod(access, name, desc, + signature, exceptions); + if (mv == null) { + // We need to visit the method in any case, otherwise probe ids + // are not reproducible + methodProbes = EMPTY_METHOD_PROBES_VISITOR; + } else { + methodProbes = mv; + } + return new MethodSanitizer(null, access, name, desc, signature, + exceptions) { + + @Override + public void visitEnd() { + super.visitEnd(); + this.accept(new LabelFlowAnalyzer()); + if (interfaceType) { + final ProbeCounter probeCounter = new ProbeCounter(); + this.accept(new MethodProbesAdapter( + EMPTY_METHOD_PROBES_VISITOR, probeCounter)); + cv.visitTotalProbeCount(probeCounter.count); + } + this.accept(new MethodProbesAdapter(methodProbes, + ClassProbesAdapter.this)); + } + }; + } + + @Override + public void visitEnd() { + if (!interfaceType) { + cv.visitTotalProbeCount(counter); + } + super.visitEnd(); + } + + // === IProbeIdGenerator === + + public int nextId() { + return counter++; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java index 892601f3..6d457577 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IClassProbesVisitor.java @@ -1,36 +1,36 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.ClassVisitor;
-
-/**
- * A {@link ClassVisitor} with additional methods to get probe insertion
- * information for each method
- */
-public interface IClassProbesVisitor extends ClassVisitor {
-
- public IMethodProbesVisitor visitMethod(int access, String name,
- String desc, String signature, String[] exceptions);
-
- /**
- * Reports the total number of encountered probes. For classes this method
- * is called just before {@link ClassVisitor#visitEnd()}. For interfaces
- * this method is called before the first method (the static initializer) is
- * emitted.
- *
- * @param count
- * total number of probes
- */
- public void visitTotalProbeCount(int count);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +import org.objectweb.asm.ClassVisitor; + +/** + * A {@link ClassVisitor} with additional methods to get probe insertion + * information for each method + */ +public interface IClassProbesVisitor extends ClassVisitor { + + public IMethodProbesVisitor visitMethod(int access, String name, + String desc, String signature, String[] exceptions); + + /** + * Reports the total number of encountered probes. For classes this method + * is called just before {@link ClassVisitor#visitEnd()}. For interfaces + * this method is called before the first method (the static initializer) is + * emitted. + * + * @param count + * total number of probes + */ + public void visitTotalProbeCount(int count); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IMethodProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IMethodProbesVisitor.java index d4007cd7..ff66ec10 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IMethodProbesVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IMethodProbesVisitor.java @@ -1,109 +1,109 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-
-/**
- * A {@link MethodVisitor} with additional methods to get probe insertion
- * information.
- */
-public interface IMethodProbesVisitor extends MethodVisitor {
-
- /**
- * Visits an unconditional probe that should be inserted at the current
- * position.
- *
- * @param probeId
- * id of the probe to insert
- */
- public void visitProbe(int probeId);
-
- /**
- * Visits a jump instruction. A probe with the given id should be inserted
- * in a way that it is executed only when the jump to the given label is
- * executed.
- *
- * @param opcode
- * the opcode of the type instruction to be visited. This opcode
- * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
- * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
- * IF_ACMPEQ, IF_ACMPNE, GOTO, IFNULL or IFNONNULL.
- * @param label
- * the operand of the instruction to be visited. This operand is
- * a label that designates the instruction to which the jump
- * instruction may jump.
- * @param probeId
- * id of the probe
- * @see MethodVisitor#visitJumpInsn(int, Label)
- */
- void visitJumpInsnWithProbe(int opcode, Label label, int probeId);
-
- /**
- * Visits a zero operand instruction with a probe. This event is used only
- * for instructions that terminate the method. Therefore the probe must be
- * inserted before the actual instruction.
- *
- * @param opcode
- * the opcode of the instruction to be visited. This opcode is
- * either IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN or
- * ATHROW.
- * @param probeId
- * id of the probe
- * @see MethodVisitor#visitInsn(int)
- */
- void visitInsnWithProbe(int opcode, int probeId);
-
- /**
- * Visits a TABLESWITCH instruction with optional probes for each target
- * label. Implementations can be optimized based on the fact that the same
- * target labels will always have the same probe id within a call to this
- * method. The probe id for each label can be obtained with
- * {@link LabelInfo#getProbeId(Label)}.
- *
- * @param min
- * the minimum key value.
- * @param max
- * the maximum key value.
- * @param dflt
- * beginning of the default handler block.
- * @param labels
- * beginnings of the handler blocks. <code>labels[i]</code> is
- * the beginning of the handler block for the
- * <code>min + i</code> key.
- * @see MethodVisitor#visitTableSwitchInsn(int, int, Label, Label[])
- */
- public void visitTableSwitchInsnWithProbes(int min, int max, Label dflt,
- Label[] labels);
-
- /**
- * Visits a LOOKUPSWITCH instruction with optional probes for each target
- * label. Implementations can be optimized based on the fact that the same
- * target labels will always have the same probe id within a call to this
- * method. The probe id for each label can be obtained with
- * {@link LabelInfo#getProbeId(Label)}.
- *
- * @param dflt
- * beginning of the default handler block.
- * @param keys
- * the values of the keys.
- * @param labels
- * beginnings of the handler blocks. <code>labels[i]</code> is
- * the beginning of the handler block for the
- * <code>keys[i]</code> key.
- * @see MethodVisitor#visitLookupSwitchInsn(Label, int[], Label[])
- */
- public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys,
- Label[] labels);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; + +/** + * A {@link MethodVisitor} with additional methods to get probe insertion + * information. + */ +public interface IMethodProbesVisitor extends MethodVisitor { + + /** + * Visits an unconditional probe that should be inserted at the current + * position. + * + * @param probeId + * id of the probe to insert + */ + public void visitProbe(int probeId); + + /** + * Visits a jump instruction. A probe with the given id should be inserted + * in a way that it is executed only when the jump to the given label is + * executed. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be visited. This operand is + * a label that designates the instruction to which the jump + * instruction may jump. + * @param probeId + * id of the probe + * @see MethodVisitor#visitJumpInsn(int, Label) + */ + void visitJumpInsnWithProbe(int opcode, Label label, int probeId); + + /** + * Visits a zero operand instruction with a probe. This event is used only + * for instructions that terminate the method. Therefore the probe must be + * inserted before the actual instruction. + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN or + * ATHROW. + * @param probeId + * id of the probe + * @see MethodVisitor#visitInsn(int) + */ + void visitInsnWithProbe(int opcode, int probeId); + + /** + * Visits a TABLESWITCH instruction with optional probes for each target + * label. Implementations can be optimized based on the fact that the same + * target labels will always have the same probe id within a call to this + * method. The probe id for each label can be obtained with + * {@link LabelInfo#getProbeId(Label)}. + * + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. <code>labels[i]</code> is + * the beginning of the handler block for the + * <code>min + i</code> key. + * @see MethodVisitor#visitTableSwitchInsn(int, int, Label, Label[]) + */ + public void visitTableSwitchInsnWithProbes(int min, int max, Label dflt, + Label[] labels); + + /** + * Visits a LOOKUPSWITCH instruction with optional probes for each target + * label. Implementations can be optimized based on the fact that the same + * target labels will always have the same probe id within a call to this + * method. The probe id for each label can be obtained with + * {@link LabelInfo#getProbeId(Label)}. + * + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. <code>labels[i]</code> is + * the beginning of the handler block for the + * <code>keys[i]</code> key. + * @see MethodVisitor#visitLookupSwitchInsn(Label, int[], Label[]) + */ + public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys, + Label[] labels); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java index f02b77ca..5f0090d1 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java @@ -1,26 +1,26 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-/**
- * Internal interface to create probe ids unique within a class.
- */
-public interface IProbeIdGenerator {
-
- /**
- * Returns the next unique probe id.
- *
- * @return unique probe id
- */
- int nextId();
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +/** + * Internal interface to create probe ids unique within a class. + */ +public interface IProbeIdGenerator { + + /** + * Returns the next unique probe id. + * + * @return unique probe id + */ + int nextId(); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java index 3291a3b8..e6816235 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java @@ -1,98 +1,98 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-/**
- * Representation of a byte code instruction for analysis. Internally used for
- * analysis.
- */
-public class Instruction {
-
- private final int line;
-
- private int branches;
-
- private int coveredBranches;
-
- private Instruction predecessor;
-
- /**
- * New instruction at the given line.
- *
- * @param line
- * source line this instruction belongs to
- */
- public Instruction(final int line) {
- this.line = line;
- this.branches = 0;
- this.coveredBranches = 0;
- }
-
- /**
- * Adds an branch to this instruction.
- */
- public void addBranch() {
- branches++;
- }
-
- /**
- * Sets the given instruction as a predecessor of this instruction. This
- * will add an branch to the predecessor.
- *
- * @see #addBranch()
- * @param predecessor
- * predecessor instruction
- */
- public void setPredecessor(final Instruction predecessor) {
- this.predecessor = predecessor;
- predecessor.addBranch();
- }
-
- /**
- * Marks one branch of this instruction as covered. Also recursively marks
- * all predecessor instructions as covered if this is the first covered
- * branch.
- */
- public void setCovered() {
- for (Instruction i = this; i != null && i.coveredBranches++ == 0;) {
- i = i.predecessor;
- }
- }
-
- /**
- * Returns the source line this instruction belongs to.
- *
- * @return corresponding source line
- */
- public int getLine() {
- return line;
- }
-
- /**
- * Returns the total number of branches starting from this instruction.
- *
- * @return total number of branches
- */
- public int getBranches() {
- return branches;
- }
-
- /**
- * Returns the number of covered branches starting from this instruction.
- *
- * @return number of covered branches
- */
- public int getCoveredBranches() {
- return coveredBranches;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +/** + * Representation of a byte code instruction for analysis. Internally used for + * analysis. + */ +public class Instruction { + + private final int line; + + private int branches; + + private int coveredBranches; + + private Instruction predecessor; + + /** + * New instruction at the given line. + * + * @param line + * source line this instruction belongs to + */ + public Instruction(final int line) { + this.line = line; + this.branches = 0; + this.coveredBranches = 0; + } + + /** + * Adds an branch to this instruction. + */ + public void addBranch() { + branches++; + } + + /** + * Sets the given instruction as a predecessor of this instruction. This + * will add an branch to the predecessor. + * + * @see #addBranch() + * @param predecessor + * predecessor instruction + */ + public void setPredecessor(final Instruction predecessor) { + this.predecessor = predecessor; + predecessor.addBranch(); + } + + /** + * Marks one branch of this instruction as covered. Also recursively marks + * all predecessor instructions as covered if this is the first covered + * branch. + */ + public void setCovered() { + for (Instruction i = this; i != null && i.coveredBranches++ == 0;) { + i = i.predecessor; + } + } + + /** + * Returns the source line this instruction belongs to. + * + * @return corresponding source line + */ + public int getLine() { + return line; + } + + /** + * Returns the total number of branches starting from this instruction. + * + * @return total number of branches + */ + public int getBranches() { + return branches; + } + + /** + * Returns the number of covered branches starting from this instruction. + * + * @return number of covered branches + */ + public int getCoveredBranches() { + return coveredBranches; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java index f3ef877d..cf474826 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java @@ -1,201 +1,201 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.Attribute;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Method visitor to collect flow related information about the {@link Label}s
- * within a class. It calculates the properties "multitarget" and "successor"
- * that can afterwards be obtained via {@link LabelInfo}.
- */
-public final class LabelFlowAnalyzer implements MethodVisitor {
-
- /**
- * <code>true</code> if the current instruction is a potential successor of
- * the previous instruction. Accessible for testing.
- */
- boolean successor = false;
-
- /**
- * <code>true</code> for the very first instruction only. Accessible for
- * testing.
- */
- boolean first = true;
-
- public void visitTryCatchBlock(final Label start, final Label end,
- final Label handler, final String type) {
- // Enforce probes at the beginning and end of the block:
- LabelInfo.setTarget(start);
- LabelInfo.setTarget(handler);
- }
-
- public void visitJumpInsn(final int opcode, final Label label) {
- LabelInfo.setTarget(label);
- if (opcode == Opcodes.JSR) {
- throw new AssertionError("Subroutines not supported.");
- }
- successor = opcode != Opcodes.GOTO;
- first = false;
- }
-
- public void visitLabel(final Label label) {
- if (first) {
- LabelInfo.setTarget(label);
- }
- if (successor) {
- LabelInfo.setSuccessor(label);
- }
- }
-
- public void visitTableSwitchInsn(final int min, final int max,
- final Label dflt, final Label[] labels) {
- visitSwitchInsn(dflt, labels);
- }
-
- public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
- final Label[] labels) {
- visitSwitchInsn(dflt, labels);
- }
-
- private void visitSwitchInsn(final Label dflt, final Label[] labels) {
- LabelInfo.resetDone(dflt);
- LabelInfo.resetDone(labels);
- setTargetIfNotDone(dflt);
- for (final Label l : labels) {
- setTargetIfNotDone(l);
- }
- successor = false;
- first = false;
- }
-
- private static void setTargetIfNotDone(final Label label) {
- if (!LabelInfo.isDone(label)) {
- LabelInfo.setTarget(label);
- LabelInfo.setDone(label);
- }
- }
-
- public void visitInsn(final int opcode) {
- switch (opcode) {
- case Opcodes.RET:
- throw new AssertionError("Subroutines not supported.");
- case Opcodes.IRETURN:
- case Opcodes.LRETURN:
- case Opcodes.FRETURN:
- case Opcodes.DRETURN:
- case Opcodes.ARETURN:
- case Opcodes.RETURN:
- case Opcodes.ATHROW:
- successor = false;
- break;
- default:
- successor = true;
- break;
- }
- first = false;
- }
-
- public void visitIntInsn(final int opcode, final int operand) {
- successor = true;
- first = false;
- }
-
- public void visitVarInsn(final int opcode, final int var) {
- successor = true;
- first = false;
- }
-
- public void visitTypeInsn(final int opcode, final String type) {
- successor = true;
- first = false;
- }
-
- public void visitFieldInsn(final int opcode, final String owner,
- final String name, final String desc) {
- successor = true;
- first = false;
- }
-
- public void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
- successor = true;
- first = false;
- }
-
- public void visitLdcInsn(final Object cst) {
- successor = true;
- first = false;
- }
-
- public void visitIincInsn(final int var, final int increment) {
- successor = true;
- first = false;
- }
-
- public void visitMultiANewArrayInsn(final String desc, final int dims) {
- successor = true;
- first = false;
- }
-
- public void visitAttribute(final Attribute attr) {
- // nothing to do
- }
-
- public AnnotationVisitor visitAnnotationDefault() {
- return null;
- }
-
- public AnnotationVisitor visitAnnotation(final String desc,
- final boolean visible) {
- // nothing to do
- return null;
- }
-
- public AnnotationVisitor visitParameterAnnotation(final int parameter,
- final String desc, final boolean visible) {
- // nothing to do
- return null;
- }
-
- public void visitLocalVariable(final String name, final String desc,
- final String signature, final Label start, final Label end,
- final int index) {
- // nothing to do
- }
-
- public void visitCode() {
- // nothing to do
- }
-
- public void visitLineNumber(final int line, final Label start) {
- // nothing to do
- }
-
- public void visitFrame(final int type, final int nLocal,
- final Object[] local, final int nStack, final Object[] stack) {
- // nothing to do
- }
-
- public void visitMaxs(final int maxStack, final int maxLocals) {
- // nothing to do
- }
-
- public void visitEnd() {
- // nothing to do
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Attribute; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Method visitor to collect flow related information about the {@link Label}s + * within a class. It calculates the properties "multitarget" and "successor" + * that can afterwards be obtained via {@link LabelInfo}. + */ +public final class LabelFlowAnalyzer implements MethodVisitor { + + /** + * <code>true</code> if the current instruction is a potential successor of + * the previous instruction. Accessible for testing. + */ + boolean successor = false; + + /** + * <code>true</code> for the very first instruction only. Accessible for + * testing. + */ + boolean first = true; + + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { + // Enforce probes at the beginning and end of the block: + LabelInfo.setTarget(start); + LabelInfo.setTarget(handler); + } + + public void visitJumpInsn(final int opcode, final Label label) { + LabelInfo.setTarget(label); + if (opcode == Opcodes.JSR) { + throw new AssertionError("Subroutines not supported."); + } + successor = opcode != Opcodes.GOTO; + first = false; + } + + public void visitLabel(final Label label) { + if (first) { + LabelInfo.setTarget(label); + } + if (successor) { + LabelInfo.setSuccessor(label); + } + } + + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label[] labels) { + visitSwitchInsn(dflt, labels); + } + + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { + visitSwitchInsn(dflt, labels); + } + + private void visitSwitchInsn(final Label dflt, final Label[] labels) { + LabelInfo.resetDone(dflt); + LabelInfo.resetDone(labels); + setTargetIfNotDone(dflt); + for (final Label l : labels) { + setTargetIfNotDone(l); + } + successor = false; + first = false; + } + + private static void setTargetIfNotDone(final Label label) { + if (!LabelInfo.isDone(label)) { + LabelInfo.setTarget(label); + LabelInfo.setDone(label); + } + } + + public void visitInsn(final int opcode) { + switch (opcode) { + case Opcodes.RET: + throw new AssertionError("Subroutines not supported."); + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + case Opcodes.ATHROW: + successor = false; + break; + default: + successor = true; + break; + } + first = false; + } + + public void visitIntInsn(final int opcode, final int operand) { + successor = true; + first = false; + } + + public void visitVarInsn(final int opcode, final int var) { + successor = true; + first = false; + } + + public void visitTypeInsn(final int opcode, final String type) { + successor = true; + first = false; + } + + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + successor = true; + first = false; + } + + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + successor = true; + first = false; + } + + public void visitLdcInsn(final Object cst) { + successor = true; + first = false; + } + + public void visitIincInsn(final int var, final int increment) { + successor = true; + first = false; + } + + public void visitMultiANewArrayInsn(final String desc, final int dims) { + successor = true; + first = false; + } + + public void visitAttribute(final Attribute attr) { + // nothing to do + } + + public AnnotationVisitor visitAnnotationDefault() { + return null; + } + + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + // nothing to do + return null; + } + + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { + // nothing to do + return null; + } + + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + // nothing to do + } + + public void visitCode() { + // nothing to do + } + + public void visitLineNumber(final int line, final Label start) { + // nothing to do + } + + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + // nothing to do + } + + public void visitMaxs(final int maxStack, final int maxLocals) { + // nothing to do + } + + public void visitEnd() { + // nothing to do + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java index f2f0108f..17b574eb 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java @@ -1,246 +1,246 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.Label;
-
-/**
- * Data container that is attached to {@link Label#info} objects to store flow
- * and instrumentation specific information. The information is only valid
- * locally in specific contexts.
- */
-public final class LabelInfo {
-
- /**
- * Reserved ID for "no probe".
- */
- public static final int NO_PROBE = -1;
-
- private boolean target = false;
-
- private boolean multiTarget = false;
-
- private boolean successor = false;
-
- private boolean done = false;
-
- private int probeid = NO_PROBE;
-
- private Label intermediate = null;
-
- private Instruction instruction = null;
-
- // instances are only created within this class
- private LabelInfo() {
- }
-
- /**
- * Defines that the given label is a jump target.
- *
- * @param label
- * label to define
- */
- public static void setTarget(final Label label) {
- final LabelInfo info = create(label);
- if (info.target || info.successor) {
- info.multiTarget = true;
- } else {
- info.target = true;
- }
- }
-
- /**
- * Defines that the given label is the possible successor of the previous
- * instruction in the method.
- *
- * @param label
- * label to define
- */
- public static void setSuccessor(final Label label) {
- final LabelInfo info = create(label);
- info.successor = true;
- if (info.target) {
- info.multiTarget = true;
- }
- }
-
- /**
- * Checks whether multiple control paths lead to a label. Control flow path
- * to a certain label are: jump targets, exception handlers and normal
- * control flow from its predecessor instruction (unless this a
- * unconditional jump or method exit).
- *
- * @param label
- * label to check
- * @return <code>true</code> if the given multiple control paths lead to the
- * given label
- */
- public static boolean isMultiTarget(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? false : info.multiTarget;
- }
-
- /**
- * Checks whether this label is the possible successor of the previous
- * instruction in the method. This is the case if the predecessor isn't a
- * unconditional jump or method exit instruction.
- *
- * @param label
- * label to check
- * @return <code>true</code> if the label is a possible instruction
- * successor
- */
- public static boolean isSuccessor(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? false : info.successor;
- }
-
- /**
- * Mark a given label as done.
- *
- * @param label
- * label to mark
- */
- public static void setDone(final Label label) {
- create(label).done = true;
- }
-
- /**
- * Resets the "done" status of a given label.
- *
- * @param label
- * label to reset
- */
- public static void resetDone(final Label label) {
- final LabelInfo info = get(label);
- if (info != null) {
- info.done = false;
- }
- }
-
- /**
- * Resets the "done" status of all given labels.
- *
- * @param labels
- * labels to reset
- */
- public static void resetDone(final Label[] labels) {
- for (final Label label : labels) {
- resetDone(label);
- }
- }
-
- /**
- * Checks whether this label is marked as done.
- *
- * @param label
- * label to check
- * @return <code>true</code> if this label is marked as done
- */
- public static boolean isDone(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? false : info.done;
- }
-
- /**
- * Sets the given probe id to the given label.
- *
- * @param label
- * label to assign a probe to
- * @param id
- * id of the probe
- */
- public static void setProbeId(final Label label, final int id) {
- create(label).probeid = id;
- }
-
- /**
- * Returns the assigned probe id.
- *
- * @param label
- * label to check
- * @return probe id or {@link #NO_PROBE} if no probe is assigned to the
- * label
- */
- public static int getProbeId(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? NO_PROBE : info.probeid;
- }
-
- /**
- * Defines an intermediate label for the given label. Such intermediate
- * labels are required during instrumentation to add probes to jump targets.
- *
- * @param label
- * label to define for
- * @param intermediate
- * intermediate label
- */
- public static void setIntermediateLabel(final Label label,
- final Label intermediate) {
- create(label).intermediate = intermediate;
- }
-
- /**
- * Returns the intermediate label for the given label if one has been
- * defined.
- *
- * @param label
- * label to look for
- * @return intermediate label or <code>null</code>
- */
- public static Label getIntermediateLabel(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? null : info.intermediate;
- }
-
- /**
- * Sets the instruction corresponding to this label.
- *
- * @param label
- * label to set the instruction for
- * @param instruction
- * corresponding instruction
- */
- public static void setInstruction(final Label label,
- final Instruction instruction) {
- create(label).instruction = instruction;
- }
-
- /**
- * Returns the corresponding instruction for the given label if one has been
- * defined.
- *
- * @param label
- * label to look for
- * @return corresponding instruction or <code>null</code>
- */
- public static Instruction getInstruction(final Label label) {
- final LabelInfo info = get(label);
- return info == null ? null : info.instruction;
- }
-
- private static LabelInfo get(final Label label) {
- final Object info = label.info;
- return info instanceof LabelInfo ? (LabelInfo) info : null;
- }
-
- private static LabelInfo create(final Label label) {
- LabelInfo info = get(label);
- if (info == null) {
- info = new LabelInfo();
- label.info = info;
- }
- return info;
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.flow; + +import org.objectweb.asm.Label; + +/** + * Data container that is attached to {@link Label#info} objects to store flow + * and instrumentation specific information. The information is only valid + * locally in specific contexts. + */ +public final class LabelInfo { + + /** + * Reserved ID for "no probe". + */ + public static final int NO_PROBE = -1; + + private boolean target = false; + + private boolean multiTarget = false; + + private boolean successor = false; + + private boolean done = false; + + private int probeid = NO_PROBE; + + private Label intermediate = null; + + private Instruction instruction = null; + + // instances are only created within this class + private LabelInfo() { + } + + /** + * Defines that the given label is a jump target. + * + * @param label + * label to define + */ + public static void setTarget(final Label label) { + final LabelInfo info = create(label); + if (info.target || info.successor) { + info.multiTarget = true; + } else { + info.target = true; + } + } + + /** + * Defines that the given label is the possible successor of the previous + * instruction in the method. + * + * @param label + * label to define + */ + public static void setSuccessor(final Label label) { + final LabelInfo info = create(label); + info.successor = true; + if (info.target) { + info.multiTarget = true; + } + } + + /** + * Checks whether multiple control paths lead to a label. Control flow path + * to a certain label are: jump targets, exception handlers and normal + * control flow from its predecessor instruction (unless this a + * unconditional jump or method exit). + * + * @param label + * label to check + * @return <code>true</code> if the given multiple control paths lead to the + * given label + */ + public static boolean isMultiTarget(final Label label) { + final LabelInfo info = get(label); + return info == null ? false : info.multiTarget; + } + + /** + * Checks whether this label is the possible successor of the previous + * instruction in the method. This is the case if the predecessor isn't a + * unconditional jump or method exit instruction. + * + * @param label + * label to check + * @return <code>true</code> if the label is a possible instruction + * successor + */ + public static boolean isSuccessor(final Label label) { + final LabelInfo info = get(label); + return info == null ? false : info.successor; + } + + /** + * Mark a given label as done. + * + * @param label + * label to mark + */ + public static void setDone(final Label label) { + create(label).done = true; + } + + /** + * Resets the "done" status of a given label. + * + * @param label + * label to reset + */ + public static void resetDone(final Label label) { + final LabelInfo info = get(label); + if (info != null) { + info.done = false; + } + } + + /** + * Resets the "done" status of all given labels. + * + * @param labels + * labels to reset + */ + public static void resetDone(final Label[] labels) { + for (final Label label : labels) { + resetDone(label); + } + } + + /** + * Checks whether this label is marked as done. + * + * @param label + * label to check + * @return <code>true</code> if this label is marked as done + */ + public static boolean isDone(final Label label) { + final LabelInfo info = get(label); + return info == null ? false : info.done; + } + + /** + * Sets the given probe id to the given label. + * + * @param label + * label to assign a probe to + * @param id + * id of the probe + */ + public static void setProbeId(final Label label, final int id) { + create(label).probeid = id; + } + + /** + * Returns the assigned probe id. + * + * @param label + * label to check + * @return probe id or {@link #NO_PROBE} if no probe is assigned to the + * label + */ + public static int getProbeId(final Label label) { + final LabelInfo info = get(label); + return info == null ? NO_PROBE : info.probeid; + } + + /** + * Defines an intermediate label for the given label. Such intermediate + * labels are required during instrumentation to add probes to jump targets. + * + * @param label + * label to define for + * @param intermediate + * intermediate label + */ + public static void setIntermediateLabel(final Label label, + final Label intermediate) { + create(label).intermediate = intermediate; + } + + /** + * Returns the intermediate label for the given label if one has been + * defined. + * + * @param label + * label to look for + * @return intermediate label or <code>null</code> + */ + public static Label getIntermediateLabel(final Label label) { + final LabelInfo info = get(label); + return info == null ? null : info.intermediate; + } + + /** + * Sets the instruction corresponding to this label. + * + * @param label + * label to set the instruction for + * @param instruction + * corresponding instruction + */ + public static void setInstruction(final Label label, + final Instruction instruction) { + create(label).instruction = instruction; + } + + /** + * Returns the corresponding instruction for the given label if one has been + * defined. + * + * @param label + * label to look for + * @return corresponding instruction or <code>null</code> + */ + public static Instruction getInstruction(final Label label) { + final LabelInfo info = get(label); + return info == null ? null : info.instruction; + } + + private static LabelInfo get(final Label label) { + final Object info = label.info; + return info instanceof LabelInfo ? (LabelInfo) info : null; + } + + private static LabelInfo create(final Label label) { + LabelInfo info = get(label); + if (info == null) { + info = new LabelInfo(); + label.info = info; + } + return info; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java index a81f0ea2..50de87cb 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java @@ -1,246 +1,246 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import static java.lang.String.format;
-
-import org.jacoco.core.internal.flow.IClassProbesVisitor;
-import org.jacoco.core.internal.flow.IMethodProbesVisitor;
-import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
-import org.objectweb.asm.ClassAdapter;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Adapter that instruments a class for coverage tracing.
- */
-public class ClassInstrumenter extends ClassAdapter implements
- IClassProbesVisitor {
-
- private static final Object[] STACK_ARRZ = new Object[] { InstrSupport.DATAFIELD_DESC };
- private static final Object[] NO_LOCALS = new Object[0];
-
- private final long id;
-
- private final IExecutionDataAccessorGenerator accessorGenerator;
-
- private IProbeArrayStrategy probeArrayStrategy;
-
- private String className;
-
- private boolean withFrames;
-
- private int probeCount;
-
- /**
- * Emits a instrumented version of this class to the given class visitor.
- *
- * @param id
- * unique identifier given to this class
- * @param accessorGenerator
- * this generator will be used for instrumentation
- * @param cv
- * next delegate in the visitor chain will receive the
- * instrumented class
- */
- public ClassInstrumenter(final long id,
- final IExecutionDataAccessorGenerator accessorGenerator,
- final ClassVisitor cv) {
- super(cv);
- this.id = id;
- this.accessorGenerator = accessorGenerator;
- }
-
- @Override
- public void visit(final int version, final int access, final String name,
- final String signature, final String superName,
- final String[] interfaces) {
- this.className = name;
- withFrames = (version & 0xff) >= Opcodes.V1_6;
- if ((access & Opcodes.ACC_INTERFACE) == 0) {
- this.probeArrayStrategy = new ClassTypeStrategy();
- } else {
- this.probeArrayStrategy = new InterfaceTypeStrategy();
- }
- super.visit(version, access, name, signature, superName, interfaces);
- }
-
- @Override
- public FieldVisitor visitField(final int access, final String name,
- final String desc, final String signature, final Object value) {
- assertNotInstrumented(name, InstrSupport.DATAFIELD_NAME);
- return super.visitField(access, name, desc, signature, value);
- }
-
- @Override
- public IMethodProbesVisitor visitMethod(final int access,
- final String name, final String desc, final String signature,
- final String[] exceptions) {
-
- assertNotInstrumented(name, InstrSupport.INITMETHOD_NAME);
-
- final MethodVisitor mv = super.visitMethod(access, name, desc,
- signature, exceptions);
-
- if (mv == null) {
- return null;
- }
- final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv);
- final ProbeInserter probeVariableInserter = new ProbeInserter(access,
- desc, frameEliminator, probeArrayStrategy);
- final LazyFrameTracker frameTracker = new LazyFrameTracker(
- probeVariableInserter, className);
- return new MethodInstrumenter(frameTracker, probeVariableInserter,
- frameTracker);
- }
-
- public void visitTotalProbeCount(final int count) {
- probeCount = count;
- }
-
- @Override
- public void visitEnd() {
- probeArrayStrategy.addMembers(cv);
- super.visitEnd();
- }
-
- /**
- * Ensures that the given member does not correspond to a internal member
- * created by the instrumentation process. This would mean that the class
- * has been instrumented twice.
- *
- * @param member
- * name of the member to check
- * @param instrMember
- * name of a instrumentation member
- * @throws IllegalStateException
- * thrown if the member has the same name than the
- * instrumentation member
- */
- private void assertNotInstrumented(final String member,
- final String instrMember) throws IllegalStateException {
- if (member.equals(instrMember)) {
- throw new IllegalStateException(format(
- "Class %s is already instrumented.", className));
- }
- }
-
- // === probe array strategies ===
-
- private class ClassTypeStrategy implements IProbeArrayStrategy {
-
- public int storeInstance(final MethodVisitor mv, final int variable) {
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, className,
- InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC);
- mv.visitVarInsn(Opcodes.ASTORE, variable);
- return 1;
- }
-
- public void addMembers(final ClassVisitor delegate) {
- createDataField();
- createInitMethod(probeCount);
- }
-
- private void createDataField() {
- cv.visitField(InstrSupport.DATAFIELD_ACC,
- InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC,
- null, null);
- }
-
- private void createInitMethod(final int probeCount) {
- final MethodVisitor mv = cv.visitMethod(
- InstrSupport.INITMETHOD_ACC, InstrSupport.INITMETHOD_NAME,
- InstrSupport.INITMETHOD_DESC, null, null);
- mv.visitCode();
- if (withFrames) {
- mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 0, STACK_ARRZ);
- }
-
- // Load the value of the static data field:
- mv.visitFieldInsn(Opcodes.GETSTATIC, className,
- InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
- mv.visitInsn(Opcodes.DUP);
-
- // Stack[1]: [Z
- // Stack[0]: [Z
-
- // Skip initialization when we already have a data array:
- final Label alreadyInitialized = new Label();
- mv.visitJumpInsn(Opcodes.IFNONNULL, alreadyInitialized);
-
- // Stack[0]: [Z
-
- mv.visitInsn(Opcodes.POP);
- final int size = genInitializeDataField(mv, probeCount);
-
- // Stack[0]: [Z
-
- // Return the class' probe array:
- if (withFrames) {
- mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 1, STACK_ARRZ);
- }
- mv.visitLabel(alreadyInitialized);
- mv.visitInsn(Opcodes.ARETURN);
-
- mv.visitMaxs(Math.max(size, 2), 0); // Maximum local stack size is 2
- mv.visitEnd();
- }
-
- /**
- * Generates the byte code to initialize the static coverage data field
- * within this class.
- *
- * The code will push the [Z data array on the operand stack.
- *
- * @param mv
- * generator to emit code to
- */
- private int genInitializeDataField(final MethodVisitor mv,
- final int probeCount) {
- final int size = accessorGenerator.generateDataAccessor(id,
- className, probeCount, mv);
-
- // Stack[0]: [Z
-
- mv.visitInsn(Opcodes.DUP);
-
- // Stack[1]: [Z
- // Stack[0]: [Z
-
- mv.visitFieldInsn(Opcodes.PUTSTATIC, className,
- InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
-
- // Stack[0]: [Z
-
- return Math.max(size, 2); // Maximum local stack size is 2
- }
- }
-
- private class InterfaceTypeStrategy implements IProbeArrayStrategy {
-
- public int storeInstance(final MethodVisitor mv, final int variable) {
- final int maxStack = accessorGenerator.generateDataAccessor(id,
- className, probeCount, mv);
- mv.visitVarInsn(Opcodes.ASTORE, variable);
- return maxStack;
- }
-
- public void addMembers(final ClassVisitor delegate) {
- // nothing to do
- }
-
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import static java.lang.String.format; + +import org.jacoco.core.internal.flow.IClassProbesVisitor; +import org.jacoco.core.internal.flow.IMethodProbesVisitor; +import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Adapter that instruments a class for coverage tracing. + */ +public class ClassInstrumenter extends ClassAdapter implements + IClassProbesVisitor { + + private static final Object[] STACK_ARRZ = new Object[] { InstrSupport.DATAFIELD_DESC }; + private static final Object[] NO_LOCALS = new Object[0]; + + private final long id; + + private final IExecutionDataAccessorGenerator accessorGenerator; + + private IProbeArrayStrategy probeArrayStrategy; + + private String className; + + private boolean withFrames; + + private int probeCount; + + /** + * Emits a instrumented version of this class to the given class visitor. + * + * @param id + * unique identifier given to this class + * @param accessorGenerator + * this generator will be used for instrumentation + * @param cv + * next delegate in the visitor chain will receive the + * instrumented class + */ + public ClassInstrumenter(final long id, + final IExecutionDataAccessorGenerator accessorGenerator, + final ClassVisitor cv) { + super(cv); + this.id = id; + this.accessorGenerator = accessorGenerator; + } + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + this.className = name; + withFrames = (version & 0xff) >= Opcodes.V1_6; + if ((access & Opcodes.ACC_INTERFACE) == 0) { + this.probeArrayStrategy = new ClassTypeStrategy(); + } else { + this.probeArrayStrategy = new InterfaceTypeStrategy(); + } + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + assertNotInstrumented(name, InstrSupport.DATAFIELD_NAME); + return super.visitField(access, name, desc, signature, value); + } + + @Override + public IMethodProbesVisitor visitMethod(final int access, + final String name, final String desc, final String signature, + final String[] exceptions) { + + assertNotInstrumented(name, InstrSupport.INITMETHOD_NAME); + + final MethodVisitor mv = super.visitMethod(access, name, desc, + signature, exceptions); + + if (mv == null) { + return null; + } + final MethodVisitor frameEliminator = new DuplicateFrameEliminator(mv); + final ProbeInserter probeVariableInserter = new ProbeInserter(access, + desc, frameEliminator, probeArrayStrategy); + final LazyFrameTracker frameTracker = new LazyFrameTracker( + probeVariableInserter, className); + return new MethodInstrumenter(frameTracker, probeVariableInserter, + frameTracker); + } + + public void visitTotalProbeCount(final int count) { + probeCount = count; + } + + @Override + public void visitEnd() { + probeArrayStrategy.addMembers(cv); + super.visitEnd(); + } + + /** + * Ensures that the given member does not correspond to a internal member + * created by the instrumentation process. This would mean that the class + * has been instrumented twice. + * + * @param member + * name of the member to check + * @param instrMember + * name of a instrumentation member + * @throws IllegalStateException + * thrown if the member has the same name than the + * instrumentation member + */ + private void assertNotInstrumented(final String member, + final String instrMember) throws IllegalStateException { + if (member.equals(instrMember)) { + throw new IllegalStateException(format( + "Class %s is already instrumented.", className)); + } + } + + // === probe array strategies === + + private class ClassTypeStrategy implements IProbeArrayStrategy { + + public int storeInstance(final MethodVisitor mv, final int variable) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, + InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC); + mv.visitVarInsn(Opcodes.ASTORE, variable); + return 1; + } + + public void addMembers(final ClassVisitor delegate) { + createDataField(); + createInitMethod(probeCount); + } + + private void createDataField() { + cv.visitField(InstrSupport.DATAFIELD_ACC, + InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC, + null, null); + } + + private void createInitMethod(final int probeCount) { + final MethodVisitor mv = cv.visitMethod( + InstrSupport.INITMETHOD_ACC, InstrSupport.INITMETHOD_NAME, + InstrSupport.INITMETHOD_DESC, null, null); + mv.visitCode(); + if (withFrames) { + mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 0, STACK_ARRZ); + } + + // Load the value of the static data field: + mv.visitFieldInsn(Opcodes.GETSTATIC, className, + InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC); + mv.visitInsn(Opcodes.DUP); + + // Stack[1]: [Z + // Stack[0]: [Z + + // Skip initialization when we already have a data array: + final Label alreadyInitialized = new Label(); + mv.visitJumpInsn(Opcodes.IFNONNULL, alreadyInitialized); + + // Stack[0]: [Z + + mv.visitInsn(Opcodes.POP); + final int size = genInitializeDataField(mv, probeCount); + + // Stack[0]: [Z + + // Return the class' probe array: + if (withFrames) { + mv.visitFrame(Opcodes.F_NEW, 0, NO_LOCALS, 1, STACK_ARRZ); + } + mv.visitLabel(alreadyInitialized); + mv.visitInsn(Opcodes.ARETURN); + + mv.visitMaxs(Math.max(size, 2), 0); // Maximum local stack size is 2 + mv.visitEnd(); + } + + /** + * Generates the byte code to initialize the static coverage data field + * within this class. + * + * The code will push the [Z data array on the operand stack. + * + * @param mv + * generator to emit code to + */ + private int genInitializeDataField(final MethodVisitor mv, + final int probeCount) { + final int size = accessorGenerator.generateDataAccessor(id, + className, probeCount, mv); + + // Stack[0]: [Z + + mv.visitInsn(Opcodes.DUP); + + // Stack[1]: [Z + // Stack[0]: [Z + + mv.visitFieldInsn(Opcodes.PUTSTATIC, className, + InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC); + + // Stack[0]: [Z + + return Math.max(size, 2); // Maximum local stack size is 2 + } + } + + private class InterfaceTypeStrategy implements IProbeArrayStrategy { + + public int storeInstance(final MethodVisitor mv, final int variable) { + final int maxStack = accessorGenerator.generateDataAccessor(id, + className, probeCount, mv); + mv.visitVarInsn(Opcodes.ASTORE, variable); + return maxStack; + } + + public void addMembers(final ClassVisitor delegate) { + // nothing to do + } + + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java index a4c2113e..674ceadc 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java @@ -1,43 +1,43 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.MethodVisitor;
-
-/**
- * Strategies to retrieve the probe array instance for each method within a
- * type. This abstraction is required as we need to follow a different strategy
- * depending on whether the instrumented type is a class or interface.
- */
-interface IProbeArrayStrategy {
-
- /**
- * Creates code that stores the probe array instance in the given variable.
- *
- * @param mv
- * visitor to create code
- * @param variable
- * variable index to store probe array to
- * @return maximum stack size required by the generated code
- */
- int storeInstance(MethodVisitor mv, int variable);
-
- /**
- * Adds additional class members required by this strategy.
- *
- * @param delegate
- * visitor to create fields and classes
- */
- void addMembers(ClassVisitor delegate);
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; + +/** + * Strategies to retrieve the probe array instance for each method within a + * type. This abstraction is required as we need to follow a different strategy + * depending on whether the instrumented type is a class or interface. + */ +interface IProbeArrayStrategy { + + /** + * Creates code that stores the probe array instance in the given variable. + * + * @param mv + * visitor to create code + * @param variable + * variable index to store probe array to + * @return maximum stack size required by the generated code + */ + int storeInstance(MethodVisitor mv, int variable); + + /** + * Adds additional class members required by this strategy. + * + * @param delegate + * visitor to create fields and classes + */ + void addMembers(ClassVisitor delegate); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 5383a426..46972098 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -1,87 +1,87 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * Constants and utilities for byte code instrumentation.
- */
-public final class InstrSupport {
-
- private InstrSupport() {
- }
-
- // === Data Field ===
-
- /**
- * Name of the field that stores coverage information of a class.
- */
- public static final String DATAFIELD_NAME = "$jacocoData";
-
- /**
- * Access modifiers of the field that stores coverage information of a
- * class.
- */
- public static final int DATAFIELD_ACC = Opcodes.ACC_SYNTHETIC
- | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT;
-
- /**
- * Data type of the field that stores coverage information for a class (
- * <code>boolean[]</code>).
- */
- public static final String DATAFIELD_DESC = "[Z";
-
- // === Init Method ===
-
- /**
- * Name of the initialization method.
- */
- public static final String INITMETHOD_NAME = "$jacocoInit";
-
- /**
- * Descriptor of the initialization method.
- */
- public static final String INITMETHOD_DESC = "()[Z";
-
- /**
- * Access modifiers of the initialization method.
- */
- public static final int INITMETHOD_ACC = Opcodes.ACC_SYNTHETIC
- | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
-
- // === Utilities ===
-
- /**
- * Generates the instruction to push the given int value on the stack.
- * Implementation taken from
- * {@link org.objectweb.asm.commons.GeneratorAdapter#push(int)}.
- *
- * @param mv
- * visitor to emit the instruction
- * @param value
- * the value to be pushed on the stack.
- */
- public static void push(final MethodVisitor mv, final int value) {
- if (value >= -1 && value <= 5) {
- mv.visitInsn(Opcodes.ICONST_0 + value);
- } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.BIPUSH, value);
- } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
- mv.visitIntInsn(Opcodes.SIPUSH, value);
- } else {
- mv.visitLdcInsn(Integer.valueOf(value));
- }
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Constants and utilities for byte code instrumentation. + */ +public final class InstrSupport { + + private InstrSupport() { + } + + // === Data Field === + + /** + * Name of the field that stores coverage information of a class. + */ + public static final String DATAFIELD_NAME = "$jacocoData"; + + /** + * Access modifiers of the field that stores coverage information of a + * class. + */ + public static final int DATAFIELD_ACC = Opcodes.ACC_SYNTHETIC + | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT; + + /** + * Data type of the field that stores coverage information for a class ( + * <code>boolean[]</code>). + */ + public static final String DATAFIELD_DESC = "[Z"; + + // === Init Method === + + /** + * Name of the initialization method. + */ + public static final String INITMETHOD_NAME = "$jacocoInit"; + + /** + * Descriptor of the initialization method. + */ + public static final String INITMETHOD_DESC = "()[Z"; + + /** + * Access modifiers of the initialization method. + */ + public static final int INITMETHOD_ACC = Opcodes.ACC_SYNTHETIC + | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL; + + // === Utilities === + + /** + * Generates the instruction to push the given int value on the stack. + * Implementation taken from + * {@link org.objectweb.asm.commons.GeneratorAdapter#push(int)}. + * + * @param mv + * visitor to emit the instruction + * @param value + * the value to be pushed on the stack. + */ + public static void push(final MethodVisitor mv, final int value) { + if (value >= -1 && value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } else { + mv.visitLdcInsn(Integer.valueOf(value)); + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java index f203e019..9ec0b4cf 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java @@ -1,182 +1,182 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import org.jacoco.core.internal.flow.IMethodProbesVisitor;
-import org.jacoco.core.internal.flow.LabelInfo;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * This method adapter inserts probes as requested by the
- * {@link IMethodProbesVisitor} events.
- */
-class MethodInstrumenter extends MethodAdapter implements IMethodProbesVisitor {
-
- private final IProbeInserter probeInserter;
- private final IFrameInserter frameInserter;
-
- /**
- * Create a new instrumenter instance for the given method.
- *
- * @param mv
- * next method visitor in the chain
- * @param probeInserter
- * call-back to insert probes where required
- * @param frameInserter
- * call-back to insert additional frames where required
- */
- public MethodInstrumenter(final MethodVisitor mv,
- final IProbeInserter probeInserter,
- final IFrameInserter frameInserter) {
- super(mv);
- this.probeInserter = probeInserter;
- this.frameInserter = frameInserter;
- }
-
- // === IMethodProbesVisitor ===
-
- public void visitProbe(final int probeId) {
- probeInserter.insertProbe(probeId);
- }
-
- public void visitInsnWithProbe(final int opcode, final int probeId) {
- probeInserter.insertProbe(probeId);
- mv.visitInsn(opcode);
- }
-
- public void visitJumpInsnWithProbe(final int opcode, final Label label,
- final int probeId) {
- if (opcode == Opcodes.GOTO) {
- probeInserter.insertProbe(probeId);
- mv.visitJumpInsn(Opcodes.GOTO, label);
- } else {
- final Label intermediate = new Label();
- mv.visitJumpInsn(getInverted(opcode), intermediate);
- probeInserter.insertProbe(probeId);
- mv.visitJumpInsn(Opcodes.GOTO, label);
- mv.visitLabel(intermediate);
- frameInserter.insertFrame();
- }
- }
-
- private int getInverted(final int opcode) {
- switch (opcode) {
- case Opcodes.IFEQ:
- return Opcodes.IFNE;
- case Opcodes.IFNE:
- return Opcodes.IFEQ;
- case Opcodes.IFLT:
- return Opcodes.IFGE;
- case Opcodes.IFGE:
- return Opcodes.IFLT;
- case Opcodes.IFGT:
- return Opcodes.IFLE;
- case Opcodes.IFLE:
- return Opcodes.IFGT;
- case Opcodes.IF_ICMPEQ:
- return Opcodes.IF_ICMPNE;
- case Opcodes.IF_ICMPNE:
- return Opcodes.IF_ICMPEQ;
- case Opcodes.IF_ICMPLT:
- return Opcodes.IF_ICMPGE;
- case Opcodes.IF_ICMPGE:
- return Opcodes.IF_ICMPLT;
- case Opcodes.IF_ICMPGT:
- return Opcodes.IF_ICMPLE;
- case Opcodes.IF_ICMPLE:
- return Opcodes.IF_ICMPGT;
- case Opcodes.IF_ACMPEQ:
- return Opcodes.IF_ACMPNE;
- case Opcodes.IF_ACMPNE:
- return Opcodes.IF_ACMPEQ;
- case Opcodes.IFNULL:
- return Opcodes.IFNONNULL;
- case Opcodes.IFNONNULL:
- return Opcodes.IFNULL;
- }
- throw new IllegalArgumentException();
- }
-
- public void visitTableSwitchInsnWithProbes(final int min, final int max,
- final Label dflt, final Label[] labels) {
- // 1. Calculate intermediate labels:
- LabelInfo.resetDone(dflt);
- LabelInfo.resetDone(labels);
- final Label newDflt = createIntermediate(dflt);
- final Label[] newLabels = createIntermediates(labels);
- mv.visitTableSwitchInsn(min, max, newDflt, newLabels);
-
- // 2. Insert probes:
- insertIntermediateProbes(dflt, labels);
- }
-
- public void visitLookupSwitchInsnWithProbes(final Label dflt,
- final int[] keys, final Label[] labels) {
- // 1. Calculate intermediate labels:
- LabelInfo.resetDone(dflt);
- LabelInfo.resetDone(labels);
- final Label newDflt = createIntermediate(dflt);
- final Label[] newLabels = createIntermediates(labels);
- mv.visitLookupSwitchInsn(newDflt, keys, newLabels);
-
- // 2. Insert probes:
- insertIntermediateProbes(dflt, labels);
- }
-
- private Label[] createIntermediates(final Label[] labels) {
- final Label[] intermediates = new Label[labels.length];
- for (int i = 0; i < labels.length; i++) {
- intermediates[i] = createIntermediate(labels[i]);
- }
- return intermediates;
- }
-
- private Label createIntermediate(final Label label) {
- final Label intermediate;
- if (LabelInfo.getProbeId(label) == LabelInfo.NO_PROBE) {
- intermediate = label;
- } else {
- if (LabelInfo.isDone(label)) {
- intermediate = LabelInfo.getIntermediateLabel(label);
- } else {
- intermediate = new Label();
- LabelInfo.setIntermediateLabel(label, intermediate);
- LabelInfo.setDone(label);
- }
- }
- return intermediate;
- }
-
- private void insertIntermediateProbe(final Label label) {
- final int probeId = LabelInfo.getProbeId(label);
- if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) {
- mv.visitLabel(LabelInfo.getIntermediateLabel(label));
- frameInserter.insertFrame();
- probeInserter.insertProbe(probeId);
- mv.visitJumpInsn(Opcodes.GOTO, label);
- LabelInfo.setDone(label);
- }
- }
-
- private void insertIntermediateProbes(final Label dflt, final Label[] labels) {
- LabelInfo.resetDone(dflt);
- LabelInfo.resetDone(labels);
- insertIntermediateProbe(dflt);
- for (final Label l : labels) {
- insertIntermediateProbe(l);
- }
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import org.jacoco.core.internal.flow.IMethodProbesVisitor; +import org.jacoco.core.internal.flow.LabelInfo; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * This method adapter inserts probes as requested by the + * {@link IMethodProbesVisitor} events. + */ +class MethodInstrumenter extends MethodAdapter implements IMethodProbesVisitor { + + private final IProbeInserter probeInserter; + private final IFrameInserter frameInserter; + + /** + * Create a new instrumenter instance for the given method. + * + * @param mv + * next method visitor in the chain + * @param probeInserter + * call-back to insert probes where required + * @param frameInserter + * call-back to insert additional frames where required + */ + public MethodInstrumenter(final MethodVisitor mv, + final IProbeInserter probeInserter, + final IFrameInserter frameInserter) { + super(mv); + this.probeInserter = probeInserter; + this.frameInserter = frameInserter; + } + + // === IMethodProbesVisitor === + + public void visitProbe(final int probeId) { + probeInserter.insertProbe(probeId); + } + + public void visitInsnWithProbe(final int opcode, final int probeId) { + probeInserter.insertProbe(probeId); + mv.visitInsn(opcode); + } + + public void visitJumpInsnWithProbe(final int opcode, final Label label, + final int probeId) { + if (opcode == Opcodes.GOTO) { + probeInserter.insertProbe(probeId); + mv.visitJumpInsn(Opcodes.GOTO, label); + } else { + final Label intermediate = new Label(); + mv.visitJumpInsn(getInverted(opcode), intermediate); + probeInserter.insertProbe(probeId); + mv.visitJumpInsn(Opcodes.GOTO, label); + mv.visitLabel(intermediate); + frameInserter.insertFrame(); + } + } + + private int getInverted(final int opcode) { + switch (opcode) { + case Opcodes.IFEQ: + return Opcodes.IFNE; + case Opcodes.IFNE: + return Opcodes.IFEQ; + case Opcodes.IFLT: + return Opcodes.IFGE; + case Opcodes.IFGE: + return Opcodes.IFLT; + case Opcodes.IFGT: + return Opcodes.IFLE; + case Opcodes.IFLE: + return Opcodes.IFGT; + case Opcodes.IF_ICMPEQ: + return Opcodes.IF_ICMPNE; + case Opcodes.IF_ICMPNE: + return Opcodes.IF_ICMPEQ; + case Opcodes.IF_ICMPLT: + return Opcodes.IF_ICMPGE; + case Opcodes.IF_ICMPGE: + return Opcodes.IF_ICMPLT; + case Opcodes.IF_ICMPGT: + return Opcodes.IF_ICMPLE; + case Opcodes.IF_ICMPLE: + return Opcodes.IF_ICMPGT; + case Opcodes.IF_ACMPEQ: + return Opcodes.IF_ACMPNE; + case Opcodes.IF_ACMPNE: + return Opcodes.IF_ACMPEQ; + case Opcodes.IFNULL: + return Opcodes.IFNONNULL; + case Opcodes.IFNONNULL: + return Opcodes.IFNULL; + } + throw new IllegalArgumentException(); + } + + public void visitTableSwitchInsnWithProbes(final int min, final int max, + final Label dflt, final Label[] labels) { + // 1. Calculate intermediate labels: + LabelInfo.resetDone(dflt); + LabelInfo.resetDone(labels); + final Label newDflt = createIntermediate(dflt); + final Label[] newLabels = createIntermediates(labels); + mv.visitTableSwitchInsn(min, max, newDflt, newLabels); + + // 2. Insert probes: + insertIntermediateProbes(dflt, labels); + } + + public void visitLookupSwitchInsnWithProbes(final Label dflt, + final int[] keys, final Label[] labels) { + // 1. Calculate intermediate labels: + LabelInfo.resetDone(dflt); + LabelInfo.resetDone(labels); + final Label newDflt = createIntermediate(dflt); + final Label[] newLabels = createIntermediates(labels); + mv.visitLookupSwitchInsn(newDflt, keys, newLabels); + + // 2. Insert probes: + insertIntermediateProbes(dflt, labels); + } + + private Label[] createIntermediates(final Label[] labels) { + final Label[] intermediates = new Label[labels.length]; + for (int i = 0; i < labels.length; i++) { + intermediates[i] = createIntermediate(labels[i]); + } + return intermediates; + } + + private Label createIntermediate(final Label label) { + final Label intermediate; + if (LabelInfo.getProbeId(label) == LabelInfo.NO_PROBE) { + intermediate = label; + } else { + if (LabelInfo.isDone(label)) { + intermediate = LabelInfo.getIntermediateLabel(label); + } else { + intermediate = new Label(); + LabelInfo.setIntermediateLabel(label, intermediate); + LabelInfo.setDone(label); + } + } + return intermediate; + } + + private void insertIntermediateProbe(final Label label) { + final int probeId = LabelInfo.getProbeId(label); + if (probeId != LabelInfo.NO_PROBE && !LabelInfo.isDone(label)) { + mv.visitLabel(LabelInfo.getIntermediateLabel(label)); + frameInserter.insertFrame(); + probeInserter.insertProbe(probeId); + mv.visitJumpInsn(Opcodes.GOTO, label); + LabelInfo.setDone(label); + } + } + + private void insertIntermediateProbes(final Label dflt, final Label[] labels) { + LabelInfo.resetDone(dflt); + LabelInfo.resetDone(labels); + insertIntermediateProbe(dflt); + for (final Label l : labels) { + insertIntermediateProbe(l); + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java index aa0c1271..363c7aba 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java @@ -1,262 +1,262 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.instr;
-
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodAdapter;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.LabelNode;
-import org.objectweb.asm.tree.LineNumberNode;
-
-/**
- * Internal utility to add probes into the control flow of a method. The code
- * for a probe simply sets a certain slot of a boolean array to true. In
- * addition the probe array has to be retrieved at the beginning of the method
- * and stored in a local variable.
- */
-class ProbeInserter extends MethodAdapter implements IProbeInserter {
-
- private final IProbeArrayStrategy arrayStrategy;
-
- /** Position of the inserted variable. */
- private final int variable;
-
- /** Index the inserted variable. */
- private final int variableIdx;
-
- /** Indicated whether the probe variable has already been inserted. */
- private boolean inserted;
-
- /** Maximum stack usage of the code to access the probe array. */
- private int accessorStackSize;
-
- /** Labels and line numbers preceding the first real instruction. */
- private final InsnList prolog;
-
- /**
- * Creates a new {@link ProbeInserter}.
- *
- * @param access
- * access flags of the adapted method.
- * @param desc
- * the method's descriptor
- * @param mv
- * the method visitor to which this adapter delegates calls
- * @param arrayStrategy
- * callback to create the code that retrieves the reference to
- * the probe array
- */
- ProbeInserter(final int access, final String desc, final MethodVisitor mv,
- final IProbeArrayStrategy arrayStrategy) {
- super(mv);
- this.arrayStrategy = arrayStrategy;
- int idx = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
- int pos = idx;
- for (final Type t : Type.getArgumentTypes(desc)) {
- idx++;
- pos += t.getSize();
- }
- variableIdx = idx;
- variable = pos;
- inserted = false;
- prolog = new InsnList();
- }
-
- public void insertProbe(final int id) {
-
- checkLoad();
- // For a probe we set the corresponding position in the boolean[] array
- // to true.
-
- mv.visitVarInsn(Opcodes.ALOAD, variable);
-
- // Stack[0]: [Z
-
- InstrSupport.push(mv, id);
-
- // Stack[1]: I
- // Stack[0]: [Z
-
- mv.visitInsn(Opcodes.ICONST_1);
-
- // Stack[2]: I
- // Stack[1]: I
- // Stack[0]: [Z
-
- mv.visitInsn(Opcodes.BASTORE);
- }
-
- private void checkLoad() {
- if (!inserted) {
- accessorStackSize = arrayStrategy.storeInstance(mv, variable);
- prolog.accept(mv);
- inserted = true;
- }
- }
-
- @Override
- public final void visitLabel(final Label label) {
- if (!inserted) {
- prolog.add(new LabelNode(label));
- } else {
- mv.visitLabel(label);
- }
- }
-
- @Override
- public void visitLineNumber(final int line, final Label start) {
- if (!inserted) {
- prolog.add(new LineNumberNode(line, new LabelNode(start)));
- } else {
- mv.visitLineNumber(line, start);
- }
- }
-
- @Override
- public final void visitVarInsn(final int opcode, final int var) {
- checkLoad();
- mv.visitVarInsn(opcode, map(var));
- }
-
- @Override
- public final void visitIincInsn(final int var, final int increment) {
- checkLoad();
- mv.visitIincInsn(map(var), increment);
- }
-
- @Override
- public final void visitLocalVariable(final String name, final String desc,
- final String signature, final Label start, final Label end,
- final int index) {
- checkLoad();
- mv.visitLocalVariable(name, desc, signature, start, end, map(index));
- }
-
- @Override
- public final void visitInsn(final int opcode) {
- checkLoad();
- mv.visitInsn(opcode);
- }
-
- @Override
- public final void visitIntInsn(final int opcode, final int operand) {
- checkLoad();
- mv.visitIntInsn(opcode, operand);
- }
-
- @Override
- public final void visitTypeInsn(final int opcode, final String type) {
- checkLoad();
- mv.visitTypeInsn(opcode, type);
- }
-
- @Override
- public final void visitFieldInsn(final int opcode, final String owner,
- final String name, final String desc) {
- checkLoad();
- mv.visitFieldInsn(opcode, owner, name, desc);
- }
-
- @Override
- public final void visitMethodInsn(final int opcode, final String owner,
- final String name, final String desc) {
- checkLoad();
- mv.visitMethodInsn(opcode, owner, name, desc);
- }
-
- @Override
- public final void visitJumpInsn(final int opcode, final Label label) {
- checkLoad();
- mv.visitJumpInsn(opcode, label);
- }
-
- @Override
- public final void visitLdcInsn(final Object cst) {
- checkLoad();
- mv.visitLdcInsn(cst);
- }
-
- @Override
- public final void visitTableSwitchInsn(final int min, final int max,
- final Label dflt, final Label[] labels) {
- checkLoad();
- mv.visitTableSwitchInsn(min, max, dflt, labels);
- }
-
- @Override
- public final void visitLookupSwitchInsn(final Label dflt, final int[] keys,
- final Label[] labels) {
- checkLoad();
- mv.visitLookupSwitchInsn(dflt, keys, labels);
- }
-
- @Override
- public final void visitMultiANewArrayInsn(final String desc, final int dims) {
- checkLoad();
- mv.visitMultiANewArrayInsn(desc, dims);
- }
-
- @Override
- public void visitMaxs(final int maxStack, final int maxLocals) {
- // Max stack size of the probe code is 3 which can add to the
- // original stack size depending on the probe locations. The accessor
- // stack size is an absolute maximum, as the accessor code is inserted
- // at the very beginning of each method when the stack size is empty.
- final int increasedStack = Math.max(maxStack + 3, accessorStackSize);
- mv.visitMaxs(increasedStack, maxLocals + 1);
- }
-
- private int map(final int var) {
- if (var < variable) {
- return var;
- } else {
- return var + 1;
- }
- }
-
- @Override
- public final void visitFrame(final int type, final int nLocal,
- final Object[] local, final int nStack, final Object[] stack) {
-
- if (type != Opcodes.F_NEW) { // uncompressed frame
- throw new IllegalArgumentException(
- "ClassReader.accept() should be called with EXPAND_FRAMES flag");
- }
-
- if (inserted) {
- final int n = Math.max(nLocal, variableIdx) + 1;
- final Object[] newLocal = new Object[n];
- for (int i = 0; i < n; i++) {
- if (i < variableIdx) {
- // For dead code it is possible to specify less locals than
- // we have method parameters.
- newLocal[i] = i < nLocal ? local[i] : Opcodes.TOP;
- continue;
- }
- if (i > variableIdx) {
- newLocal[i] = local[i - 1];
- continue;
- }
- newLocal[i] = InstrSupport.DATAFIELD_DESC;
- }
- mv.visitFrame(type, n, newLocal, nStack, stack);
- } else {
- mv.visitFrame(type, nLocal, local, nStack, stack);
- }
-
- checkLoad();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodAdapter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; + +/** + * Internal utility to add probes into the control flow of a method. The code + * for a probe simply sets a certain slot of a boolean array to true. In + * addition the probe array has to be retrieved at the beginning of the method + * and stored in a local variable. + */ +class ProbeInserter extends MethodAdapter implements IProbeInserter { + + private final IProbeArrayStrategy arrayStrategy; + + /** Position of the inserted variable. */ + private final int variable; + + /** Index the inserted variable. */ + private final int variableIdx; + + /** Indicated whether the probe variable has already been inserted. */ + private boolean inserted; + + /** Maximum stack usage of the code to access the probe array. */ + private int accessorStackSize; + + /** Labels and line numbers preceding the first real instruction. */ + private final InsnList prolog; + + /** + * Creates a new {@link ProbeInserter}. + * + * @param access + * access flags of the adapted method. + * @param desc + * the method's descriptor + * @param mv + * the method visitor to which this adapter delegates calls + * @param arrayStrategy + * callback to create the code that retrieves the reference to + * the probe array + */ + ProbeInserter(final int access, final String desc, final MethodVisitor mv, + final IProbeArrayStrategy arrayStrategy) { + super(mv); + this.arrayStrategy = arrayStrategy; + int idx = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0; + int pos = idx; + for (final Type t : Type.getArgumentTypes(desc)) { + idx++; + pos += t.getSize(); + } + variableIdx = idx; + variable = pos; + inserted = false; + prolog = new InsnList(); + } + + public void insertProbe(final int id) { + + checkLoad(); + // For a probe we set the corresponding position in the boolean[] array + // to true. + + mv.visitVarInsn(Opcodes.ALOAD, variable); + + // Stack[0]: [Z + + InstrSupport.push(mv, id); + + // Stack[1]: I + // Stack[0]: [Z + + mv.visitInsn(Opcodes.ICONST_1); + + // Stack[2]: I + // Stack[1]: I + // Stack[0]: [Z + + mv.visitInsn(Opcodes.BASTORE); + } + + private void checkLoad() { + if (!inserted) { + accessorStackSize = arrayStrategy.storeInstance(mv, variable); + prolog.accept(mv); + inserted = true; + } + } + + @Override + public final void visitLabel(final Label label) { + if (!inserted) { + prolog.add(new LabelNode(label)); + } else { + mv.visitLabel(label); + } + } + + @Override + public void visitLineNumber(final int line, final Label start) { + if (!inserted) { + prolog.add(new LineNumberNode(line, new LabelNode(start))); + } else { + mv.visitLineNumber(line, start); + } + } + + @Override + public final void visitVarInsn(final int opcode, final int var) { + checkLoad(); + mv.visitVarInsn(opcode, map(var)); + } + + @Override + public final void visitIincInsn(final int var, final int increment) { + checkLoad(); + mv.visitIincInsn(map(var), increment); + } + + @Override + public final void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + checkLoad(); + mv.visitLocalVariable(name, desc, signature, start, end, map(index)); + } + + @Override + public final void visitInsn(final int opcode) { + checkLoad(); + mv.visitInsn(opcode); + } + + @Override + public final void visitIntInsn(final int opcode, final int operand) { + checkLoad(); + mv.visitIntInsn(opcode, operand); + } + + @Override + public final void visitTypeInsn(final int opcode, final String type) { + checkLoad(); + mv.visitTypeInsn(opcode, type); + } + + @Override + public final void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + checkLoad(); + mv.visitFieldInsn(opcode, owner, name, desc); + } + + @Override + public final void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + checkLoad(); + mv.visitMethodInsn(opcode, owner, name, desc); + } + + @Override + public final void visitJumpInsn(final int opcode, final Label label) { + checkLoad(); + mv.visitJumpInsn(opcode, label); + } + + @Override + public final void visitLdcInsn(final Object cst) { + checkLoad(); + mv.visitLdcInsn(cst); + } + + @Override + public final void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label[] labels) { + checkLoad(); + mv.visitTableSwitchInsn(min, max, dflt, labels); + } + + @Override + public final void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { + checkLoad(); + mv.visitLookupSwitchInsn(dflt, keys, labels); + } + + @Override + public final void visitMultiANewArrayInsn(final String desc, final int dims) { + checkLoad(); + mv.visitMultiANewArrayInsn(desc, dims); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + // Max stack size of the probe code is 3 which can add to the + // original stack size depending on the probe locations. The accessor + // stack size is an absolute maximum, as the accessor code is inserted + // at the very beginning of each method when the stack size is empty. + final int increasedStack = Math.max(maxStack + 3, accessorStackSize); + mv.visitMaxs(increasedStack, maxLocals + 1); + } + + private int map(final int var) { + if (var < variable) { + return var; + } else { + return var + 1; + } + } + + @Override + public final void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + + if (type != Opcodes.F_NEW) { // uncompressed frame + throw new IllegalArgumentException( + "ClassReader.accept() should be called with EXPAND_FRAMES flag"); + } + + if (inserted) { + final int n = Math.max(nLocal, variableIdx) + 1; + final Object[] newLocal = new Object[n]; + for (int i = 0; i < n; i++) { + if (i < variableIdx) { + // For dead code it is possible to specify less locals than + // we have method parameters. + newLocal[i] = i < nLocal ? local[i] : Opcodes.TOP; + continue; + } + if (i > variableIdx) { + newLocal[i] = local[i - 1]; + continue; + } + newLocal[i] = InstrSupport.DATAFIELD_DESC; + } + mv.visitFrame(type, n, newLocal, nStack, stack); + } else { + mv.visitFrame(type, nLocal, local, nStack, stack); + } + + checkLoad(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/jacoco.properties b/org.jacoco.core/src/org/jacoco/core/jacoco.properties index 6f5972e7..d9c32698 100644 --- a/org.jacoco.core/src/org/jacoco/core/jacoco.properties +++ b/org.jacoco.core/src/org/jacoco/core/jacoco.properties @@ -1,2 +1,2 @@ -VERSION=$qualified.bundle.version$
+VERSION=$qualified.bundle.version$ HOMEURL=$jacoco.home.url$
\ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java index c1462eb1..63d89a57 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java @@ -1,105 +1,105 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import java.lang.reflect.Field;
-import java.util.Random;
-
-import org.jacoco.core.data.ExecutionDataStore;
-import org.jacoco.core.data.IExecutionDataVisitor;
-import org.jacoco.core.data.ISessionInfoVisitor;
-import org.jacoco.core.data.SessionInfo;
-import org.jacoco.core.internal.instr.InstrSupport;
-
-/**
- * Base {@link IRuntime} implementation.
- */
-public abstract class AbstractRuntime implements IRuntime {
-
- /** store for execution data */
- protected final ExecutionDataStore store;
-
- /** access for this runtime instance */
- protected final ExecutionDataAccess access;
-
- private long startTimeStamp;
-
- private String sessionId;
-
- /**
- * Creates a new runtime.
- */
- protected AbstractRuntime() {
- store = new ExecutionDataStore();
- access = new ExecutionDataAccess(store);
- sessionId = createRandomId();
- }
-
- /**
- * Subclasses need to call this method in their {@link #startup()}
- * implementation to record the timestamp of session startup.
- */
- protected final void setStartTimeStamp() {
- startTimeStamp = System.currentTimeMillis();
- }
-
- public void setSessionId(final String id) {
- sessionId = id;
- }
-
- public String getSessionId() {
- return sessionId;
- }
-
- public final void collect(final IExecutionDataVisitor executionDataVisitor,
- final ISessionInfoVisitor sessionInfoVisitor, final boolean reset) {
- synchronized (store) {
- if (sessionInfoVisitor != null) {
- final SessionInfo info = new SessionInfo(sessionId,
- startTimeStamp, System.currentTimeMillis());
- sessionInfoVisitor.visitSessionInfo(info);
- }
- store.accept(executionDataVisitor);
- if (reset) {
- reset();
- }
- }
- }
-
- public final void reset() {
- synchronized (store) {
- store.reset();
- setStartTimeStamp();
- }
- }
-
- public void disconnect(final Class<?> type) throws Exception {
- if (!type.isInterface()) {
- final Field dataField = type
- .getDeclaredField(InstrSupport.DATAFIELD_NAME);
- dataField.setAccessible(true);
- dataField.set(null, null);
- }
- }
-
- private static final Random RANDOM = new Random();
-
- /**
- * Creates a random session identifier.
- *
- * @return random session identifier
- */
- public static String createRandomId() {
- return Integer.toHexString(RANDOM.nextInt());
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import java.lang.reflect.Field; +import java.util.Random; + +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.IExecutionDataVisitor; +import org.jacoco.core.data.ISessionInfoVisitor; +import org.jacoco.core.data.SessionInfo; +import org.jacoco.core.internal.instr.InstrSupport; + +/** + * Base {@link IRuntime} implementation. + */ +public abstract class AbstractRuntime implements IRuntime { + + /** store for execution data */ + protected final ExecutionDataStore store; + + /** access for this runtime instance */ + protected final ExecutionDataAccess access; + + private long startTimeStamp; + + private String sessionId; + + /** + * Creates a new runtime. + */ + protected AbstractRuntime() { + store = new ExecutionDataStore(); + access = new ExecutionDataAccess(store); + sessionId = createRandomId(); + } + + /** + * Subclasses need to call this method in their {@link #startup()} + * implementation to record the timestamp of session startup. + */ + protected final void setStartTimeStamp() { + startTimeStamp = System.currentTimeMillis(); + } + + public void setSessionId(final String id) { + sessionId = id; + } + + public String getSessionId() { + return sessionId; + } + + public final void collect(final IExecutionDataVisitor executionDataVisitor, + final ISessionInfoVisitor sessionInfoVisitor, final boolean reset) { + synchronized (store) { + if (sessionInfoVisitor != null) { + final SessionInfo info = new SessionInfo(sessionId, + startTimeStamp, System.currentTimeMillis()); + sessionInfoVisitor.visitSessionInfo(info); + } + store.accept(executionDataVisitor); + if (reset) { + reset(); + } + } + } + + public final void reset() { + synchronized (store) { + store.reset(); + setStartTimeStamp(); + } + } + + public void disconnect(final Class<?> type) throws Exception { + if (!type.isInterface()) { + final Field dataField = type + .getDeclaredField(InstrSupport.DATAFIELD_NAME); + dataField.setAccessible(true); + dataField.set(null, null); + } + } + + private static final Random RANDOM = new Random(); + + /** + * Creates a random session identifier. + * + * @return random session identifier + */ + public static String createRandomId() { + return Integer.toHexString(RANDOM.nextInt()); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java index 16067a6c..b3744f6b 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java @@ -1,507 +1,507 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import static java.lang.String.format;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Utility to create and parse options for the runtime agent. Options are
- * represented as a string in the following format:
- *
- * <pre>
- * key1=value1,key2=value2,key3=value3
- * </pre>
- */
-public final class AgentOptions {
-
- /**
- * Specifies the output file for execution data. Default is
- * <code>jacoco.exec</code> in the working directory.
- */
- public static final String DESTFILE = "destfile";
-
- /**
- * Specifies whether execution data should be appended to the output file.
- * Default is <code>true</code>.
- */
- public static final String APPEND = "append";
-
- /**
- * Wildcard expression for class names that should be included for code
- * coverage. Default is <code>*</code> (all classes included).
- *
- * @see WildcardMatcher
- */
- public static final String INCLUDES = "includes";
-
- /**
- * Wildcard expression for class names that should be excluded from code
- * coverage. Default is the empty string (no exclusions).
- *
- * @see WildcardMatcher
- */
- public static final String EXCLUDES = "excludes";
-
- /**
- * Wildcard expression for class loaders names for classes that should be
- * excluded from code coverage. This means all classes loaded by a class
- * loader which full qualified name matches this expression will be ignored
- * for code coverage regardless of all other filtering settings. Default is
- * <code>sun.reflect.DelegatingClassLoader</code>.
- *
- * @see WildcardMatcher
- */
- public static final String EXCLCLASSLOADER = "exclclassloader";
-
- /**
- * Specifies a session identifier that is written with the execution data.
- * Without this parameter a random identifier is created by the agent.
- */
- public static final String SESSIONID = "sessionid";
-
- /**
- * Specifies whether the agent will automatically dump coverage data on VM
- * exit. Default is <code>true</code>.
- */
- public static final String DUMPONEXIT = "dumponexit";
-
- /**
- * Specifies the output mode. Default is
- * <code>{@link OutputMode#file}</code>.
- *
- * @see OutputMode#file
- * @see OutputMode#tcpserver
- * @see OutputMode#tcpclient
- */
- public static final String OUTPUT = "output";
-
- /**
- * Possible values for {@link AgentOptions#OUTPUT}.
- */
- public static enum OutputMode {
-
- /**
- * Value for the {@link AgentOptions#OUTPUT} parameter: At VM
- * termination execution data is written to the file specified by
- * {@link AgentOptions#DESTFILE}.
- */
- file,
-
- /**
- * Value for the {@link AgentOptions#OUTPUT} parameter: The agent
- * listens for incoming connections on a TCP port specified by
- * {@link AgentOptions#ADDRESS} and {@link AgentOptions#PORT}.
- */
- tcpserver,
-
- /**
- * Value for the {@link AgentOptions#OUTPUT} parameter: At startup the
- * agent connects to a TCP port specified by the
- * {@link AgentOptions#ADDRESS} and {@link AgentOptions#PORT} attribute.
- */
- tcpclient,
-
- /**
- * Value for the {@link AgentOptions#OUTPUT} parameter: At startup the
- * agent creates MBean.
- */
- mbean
-
- }
-
- /**
- * The IP address or DNS name the tcpserver binds to or the tcpclient
- * connects to. Default is defined by {@link #DEFAULT_ADDRESS}.
- */
- public static final String ADDRESS = "address";
-
- /**
- * Default value for the "address" agent option.
- */
- public static final String DEFAULT_ADDRESS = null;
-
- /**
- * The port the tcpserver binds to or the tcpclient connects to. In
- * tcpserver mode the port must be available, which means that if multiple
- * JaCoCo agents should run on the same machine, different ports have to be
- * specified. Default is defined by {@link #DEFAULT_PORT}.
- */
- public static final String PORT = "port";
-
- /**
- * Default value for the "port" agent option.
- */
- public static final int DEFAULT_PORT = 6300;
-
- /**
- * Specifies where the agent dumps all class files it encounters. The
- * location is specified as a relative path to the working directory.
- * Default is <code>null</code> (no dumps).
- */
- public static final String CLASSDUMPDIR = "classdumpdir";
-
- private static final Collection<String> VALID_OPTIONS = Arrays.asList(
- DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER, SESSIONID,
- DUMPONEXIT, OUTPUT, ADDRESS, PORT, CLASSDUMPDIR);
-
- private final Map<String, String> options;
-
- /**
- * New instance with all values set to default.
- */
- public AgentOptions() {
- this.options = new HashMap<String, String>();
- }
-
- /**
- * New instance parsed from the given option string.
- *
- * @param optionstr
- * string to parse or <code>null</code>
- */
- public AgentOptions(final String optionstr) {
- this();
- if (optionstr != null && optionstr.length() > 0) {
- for (final String entry : optionstr.split(",")) {
- final int pos = entry.indexOf('=');
- if (pos == -1) {
- throw new IllegalArgumentException(format(
- "Invalid agent option syntax \"%s\".", optionstr));
- }
- final String key = entry.substring(0, pos);
- if (!VALID_OPTIONS.contains(key)) {
- throw new IllegalArgumentException(format(
- "Unknown agent option \"%s\".", key));
- }
-
- final String value = entry.substring(pos + 1);
- setOption(key, value);
- }
-
- validateAll();
- }
- }
-
- private void validateAll() {
- validatePort(getPort());
- getOutput();
- }
-
- private void validatePort(final int port) {
- if (port < 0) {
- throw new IllegalArgumentException("port must be positive");
- }
- }
-
- /**
- * Returns the output file location.
- *
- * @return output file location
- */
- public String getDestfile() {
- return getOption(DESTFILE, "jacoco.exec");
- }
-
- /**
- * Sets the output file location.
- *
- * @param destfile
- * output file location
- */
- public void setDestfile(final String destfile) {
- setOption(DESTFILE, destfile);
- }
-
- /**
- * Returns whether the output should be appended to an existing file.
- *
- * @return <code>true</code>, when the output should be appended
- */
- public boolean getAppend() {
- return getOption(APPEND, true);
- }
-
- /**
- * Sets whether the output should be appended to an existing file.
- *
- * @param append
- * <code>true</code>, when the output should be appended
- */
- public void setAppend(final boolean append) {
- setOption(APPEND, append);
- }
-
- /**
- * Returns the wildcard expression for classes to include.
- *
- * @return wildcard expression for classes to include
- * @see WildcardMatcher
- */
- public String getIncludes() {
- return getOption(INCLUDES, "*");
- }
-
- /**
- * Sets the wildcard expression for classes to include.
- *
- * @param includes
- * wildcard expression for classes to include
- * @see WildcardMatcher
- */
- public void setIncludes(final String includes) {
- setOption(INCLUDES, includes);
- }
-
- /**
- * Returns the wildcard expression for classes to exclude.
- *
- * @return wildcard expression for classes to exclude
- * @see WildcardMatcher
- */
- public String getExcludes() {
- return getOption(EXCLUDES, "");
- }
-
- /**
- * Sets the wildcard expression for classes to exclude.
- *
- * @param excludes
- * wildcard expression for classes to exclude
- * @see WildcardMatcher
- */
- public void setExcludes(final String excludes) {
- setOption(EXCLUDES, excludes);
- }
-
- /**
- * Returns the wildcard expression for excluded class loaders.
- *
- * @return expression for excluded class loaders
- * @see WildcardMatcher
- */
- public String getExclClassloader() {
- return getOption(EXCLCLASSLOADER, "sun.reflect.DelegatingClassLoader");
- }
-
- /**
- * Sets the wildcard expression for excluded class loaders.
- *
- * @param expression
- * expression for excluded class loaders
- * @see WildcardMatcher
- */
- public void setExclClassloader(final String expression) {
- setOption(EXCLCLASSLOADER, expression);
- }
-
- /**
- * Returns the session identifier.
- *
- * @return session identifier
- */
- public String getSessionId() {
- return getOption(SESSIONID, null);
- }
-
- /**
- * Sets the session identifier.
- *
- * @param id
- * session identifier
- */
- public void setSessionId(final String id) {
- setOption(SESSIONID, id);
- }
-
- /**
- * Returns whether coverage data should be dumped on exit
- *
- * @return <code>true</code> if coverage data will be written on VM exit
- */
- public boolean getDumpOnExit() {
- return getOption(DUMPONEXIT, true);
- }
-
- /**
- * Sets whether coverage data should be dumped on exit
- *
- * @param dumpOnExit
- * <code>true</code> if coverage data should be written on VM
- * exit
- */
- public void setDumpOnExit(final boolean dumpOnExit) {
- setOption(DUMPONEXIT, dumpOnExit);
- }
-
- /**
- * Returns the port on which to listen to when the output is
- * <code>tcpserver</code> or the port to connect to when output is
- * <code>tcpclient</code>.
- *
- * @return port to listen on or connect to
- */
- public int getPort() {
- return getOption(PORT, DEFAULT_PORT);
- }
-
- /**
- * Sets the port on which to listen to when output is <code>tcpserver</code>
- * or the port to connect to when output is <code>tcpclient</code>
- *
- * @param port
- */
- public void setPort(final int port) {
- validatePort(port);
- setOption(PORT, port);
- }
-
- /**
- * Gets the hostname or IP address to listen to when output is
- * <code>tcpserver</code> or connect to when output is
- * <code>tcpclient</code>
- *
- * @return Hostname or IP address
- */
- public String getAddress() {
- return getOption(ADDRESS, DEFAULT_ADDRESS);
- }
-
- /**
- * Sets the hostname or IP address to listen to when output is
- * <code>tcpserver</cose> or connect to when output is <code>tcpclient</code>
- *
- * @param address
- * Hostname or IP address
- */
- public void setAddress(final String address) {
- setOption(ADDRESS, address);
- }
-
- /**
- * Returns the output mode
- *
- * @return current output mode
- */
- public OutputMode getOutput() {
- final String value = options.get(OUTPUT);
- return value == null ? OutputMode.file : OutputMode.valueOf(value);
- }
-
- /**
- * Sets the output mode
- *
- * @param output
- * Output mode
- */
- public void setOutput(final String output) {
- setOutput(OutputMode.valueOf(output));
- }
-
- /**
- * Sets the output mode
- *
- * @param output
- * Output mode
- */
- public void setOutput(final OutputMode output) {
- setOption(OUTPUT, output.name());
- }
-
- /**
- * Returns the location of the directory where class files should be dumped
- * to.
- *
- * @return dump location or <code>null</code> (no dumps)
- */
- public String getClassDumpDir() {
- return getOption(CLASSDUMPDIR, null);
- }
-
- /**
- * Sets the directory where class files should be dumped to.
- *
- * @param location
- * dump location or <code>null</code> (no dumps)
- */
- public void setClassDumpDir(final String location) {
- setOption(CLASSDUMPDIR, location);
- }
-
- private void setOption(final String key, final int value) {
- setOption(key, Integer.toString(value));
- }
-
- private void setOption(final String key, final boolean value) {
- setOption(key, Boolean.toString(value));
- }
-
- private void setOption(final String key, final String value) {
- if (value.contains(",")) {
- throw new IllegalArgumentException(format(
- "Invalid character in option argument \"%s\"", value));
- }
- options.put(key, value);
- }
-
- private String getOption(final String key, final String defaultValue) {
- final String value = options.get(key);
- return value == null ? defaultValue : value;
- }
-
- private boolean getOption(final String key, final boolean defaultValue) {
- final String value = options.get(key);
- return value == null ? defaultValue : Boolean.parseBoolean(value);
- }
-
- private int getOption(final String key, final int defaultValue) {
- final String value = options.get(key);
- return value == null ? defaultValue : Integer.parseInt(value);
- }
-
- /**
- * Generate required JVM argument string based on current configuration and
- * supplied agent jar location
- *
- * @param agentJarFile
- * location of the JaCoCo Agent Jar
- * @return Argument to pass to create new VM with coverage enabled
- */
- public String getVMArgument(final File agentJarFile) {
- return format("-javaagent:%s=%s", agentJarFile, this);
- }
-
- /**
- * Creates a string representation that can be passed to the agent via the
- * command line. Might be the empty string, if no options are set.
- */
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- for (final String key : VALID_OPTIONS) {
- final String value = options.get(key);
- if (value != null) {
- if (sb.length() > 0) {
- sb.append(',');
- }
- sb.append(key).append('=').append(value);
- }
- }
- return sb.toString();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import static java.lang.String.format; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Utility to create and parse options for the runtime agent. Options are + * represented as a string in the following format: + * + * <pre> + * key1=value1,key2=value2,key3=value3 + * </pre> + */ +public final class AgentOptions { + + /** + * Specifies the output file for execution data. Default is + * <code>jacoco.exec</code> in the working directory. + */ + public static final String DESTFILE = "destfile"; + + /** + * Specifies whether execution data should be appended to the output file. + * Default is <code>true</code>. + */ + public static final String APPEND = "append"; + + /** + * Wildcard expression for class names that should be included for code + * coverage. Default is <code>*</code> (all classes included). + * + * @see WildcardMatcher + */ + public static final String INCLUDES = "includes"; + + /** + * Wildcard expression for class names that should be excluded from code + * coverage. Default is the empty string (no exclusions). + * + * @see WildcardMatcher + */ + public static final String EXCLUDES = "excludes"; + + /** + * Wildcard expression for class loaders names for classes that should be + * excluded from code coverage. This means all classes loaded by a class + * loader which full qualified name matches this expression will be ignored + * for code coverage regardless of all other filtering settings. Default is + * <code>sun.reflect.DelegatingClassLoader</code>. + * + * @see WildcardMatcher + */ + public static final String EXCLCLASSLOADER = "exclclassloader"; + + /** + * Specifies a session identifier that is written with the execution data. + * Without this parameter a random identifier is created by the agent. + */ + public static final String SESSIONID = "sessionid"; + + /** + * Specifies whether the agent will automatically dump coverage data on VM + * exit. Default is <code>true</code>. + */ + public static final String DUMPONEXIT = "dumponexit"; + + /** + * Specifies the output mode. Default is + * <code>{@link OutputMode#file}</code>. + * + * @see OutputMode#file + * @see OutputMode#tcpserver + * @see OutputMode#tcpclient + */ + public static final String OUTPUT = "output"; + + /** + * Possible values for {@link AgentOptions#OUTPUT}. + */ + public static enum OutputMode { + + /** + * Value for the {@link AgentOptions#OUTPUT} parameter: At VM + * termination execution data is written to the file specified by + * {@link AgentOptions#DESTFILE}. + */ + file, + + /** + * Value for the {@link AgentOptions#OUTPUT} parameter: The agent + * listens for incoming connections on a TCP port specified by + * {@link AgentOptions#ADDRESS} and {@link AgentOptions#PORT}. + */ + tcpserver, + + /** + * Value for the {@link AgentOptions#OUTPUT} parameter: At startup the + * agent connects to a TCP port specified by the + * {@link AgentOptions#ADDRESS} and {@link AgentOptions#PORT} attribute. + */ + tcpclient, + + /** + * Value for the {@link AgentOptions#OUTPUT} parameter: At startup the + * agent creates MBean. + */ + mbean + + } + + /** + * The IP address or DNS name the tcpserver binds to or the tcpclient + * connects to. Default is defined by {@link #DEFAULT_ADDRESS}. + */ + public static final String ADDRESS = "address"; + + /** + * Default value for the "address" agent option. + */ + public static final String DEFAULT_ADDRESS = null; + + /** + * The port the tcpserver binds to or the tcpclient connects to. In + * tcpserver mode the port must be available, which means that if multiple + * JaCoCo agents should run on the same machine, different ports have to be + * specified. Default is defined by {@link #DEFAULT_PORT}. + */ + public static final String PORT = "port"; + + /** + * Default value for the "port" agent option. + */ + public static final int DEFAULT_PORT = 6300; + + /** + * Specifies where the agent dumps all class files it encounters. The + * location is specified as a relative path to the working directory. + * Default is <code>null</code> (no dumps). + */ + public static final String CLASSDUMPDIR = "classdumpdir"; + + private static final Collection<String> VALID_OPTIONS = Arrays.asList( + DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER, SESSIONID, + DUMPONEXIT, OUTPUT, ADDRESS, PORT, CLASSDUMPDIR); + + private final Map<String, String> options; + + /** + * New instance with all values set to default. + */ + public AgentOptions() { + this.options = new HashMap<String, String>(); + } + + /** + * New instance parsed from the given option string. + * + * @param optionstr + * string to parse or <code>null</code> + */ + public AgentOptions(final String optionstr) { + this(); + if (optionstr != null && optionstr.length() > 0) { + for (final String entry : optionstr.split(",")) { + final int pos = entry.indexOf('='); + if (pos == -1) { + throw new IllegalArgumentException(format( + "Invalid agent option syntax \"%s\".", optionstr)); + } + final String key = entry.substring(0, pos); + if (!VALID_OPTIONS.contains(key)) { + throw new IllegalArgumentException(format( + "Unknown agent option \"%s\".", key)); + } + + final String value = entry.substring(pos + 1); + setOption(key, value); + } + + validateAll(); + } + } + + private void validateAll() { + validatePort(getPort()); + getOutput(); + } + + private void validatePort(final int port) { + if (port < 0) { + throw new IllegalArgumentException("port must be positive"); + } + } + + /** + * Returns the output file location. + * + * @return output file location + */ + public String getDestfile() { + return getOption(DESTFILE, "jacoco.exec"); + } + + /** + * Sets the output file location. + * + * @param destfile + * output file location + */ + public void setDestfile(final String destfile) { + setOption(DESTFILE, destfile); + } + + /** + * Returns whether the output should be appended to an existing file. + * + * @return <code>true</code>, when the output should be appended + */ + public boolean getAppend() { + return getOption(APPEND, true); + } + + /** + * Sets whether the output should be appended to an existing file. + * + * @param append + * <code>true</code>, when the output should be appended + */ + public void setAppend(final boolean append) { + setOption(APPEND, append); + } + + /** + * Returns the wildcard expression for classes to include. + * + * @return wildcard expression for classes to include + * @see WildcardMatcher + */ + public String getIncludes() { + return getOption(INCLUDES, "*"); + } + + /** + * Sets the wildcard expression for classes to include. + * + * @param includes + * wildcard expression for classes to include + * @see WildcardMatcher + */ + public void setIncludes(final String includes) { + setOption(INCLUDES, includes); + } + + /** + * Returns the wildcard expression for classes to exclude. + * + * @return wildcard expression for classes to exclude + * @see WildcardMatcher + */ + public String getExcludes() { + return getOption(EXCLUDES, ""); + } + + /** + * Sets the wildcard expression for classes to exclude. + * + * @param excludes + * wildcard expression for classes to exclude + * @see WildcardMatcher + */ + public void setExcludes(final String excludes) { + setOption(EXCLUDES, excludes); + } + + /** + * Returns the wildcard expression for excluded class loaders. + * + * @return expression for excluded class loaders + * @see WildcardMatcher + */ + public String getExclClassloader() { + return getOption(EXCLCLASSLOADER, "sun.reflect.DelegatingClassLoader"); + } + + /** + * Sets the wildcard expression for excluded class loaders. + * + * @param expression + * expression for excluded class loaders + * @see WildcardMatcher + */ + public void setExclClassloader(final String expression) { + setOption(EXCLCLASSLOADER, expression); + } + + /** + * Returns the session identifier. + * + * @return session identifier + */ + public String getSessionId() { + return getOption(SESSIONID, null); + } + + /** + * Sets the session identifier. + * + * @param id + * session identifier + */ + public void setSessionId(final String id) { + setOption(SESSIONID, id); + } + + /** + * Returns whether coverage data should be dumped on exit + * + * @return <code>true</code> if coverage data will be written on VM exit + */ + public boolean getDumpOnExit() { + return getOption(DUMPONEXIT, true); + } + + /** + * Sets whether coverage data should be dumped on exit + * + * @param dumpOnExit + * <code>true</code> if coverage data should be written on VM + * exit + */ + public void setDumpOnExit(final boolean dumpOnExit) { + setOption(DUMPONEXIT, dumpOnExit); + } + + /** + * Returns the port on which to listen to when the output is + * <code>tcpserver</code> or the port to connect to when output is + * <code>tcpclient</code>. + * + * @return port to listen on or connect to + */ + public int getPort() { + return getOption(PORT, DEFAULT_PORT); + } + + /** + * Sets the port on which to listen to when output is <code>tcpserver</code> + * or the port to connect to when output is <code>tcpclient</code> + * + * @param port + */ + public void setPort(final int port) { + validatePort(port); + setOption(PORT, port); + } + + /** + * Gets the hostname or IP address to listen to when output is + * <code>tcpserver</code> or connect to when output is + * <code>tcpclient</code> + * + * @return Hostname or IP address + */ + public String getAddress() { + return getOption(ADDRESS, DEFAULT_ADDRESS); + } + + /** + * Sets the hostname or IP address to listen to when output is + * <code>tcpserver</cose> or connect to when output is <code>tcpclient</code> + * + * @param address + * Hostname or IP address + */ + public void setAddress(final String address) { + setOption(ADDRESS, address); + } + + /** + * Returns the output mode + * + * @return current output mode + */ + public OutputMode getOutput() { + final String value = options.get(OUTPUT); + return value == null ? OutputMode.file : OutputMode.valueOf(value); + } + + /** + * Sets the output mode + * + * @param output + * Output mode + */ + public void setOutput(final String output) { + setOutput(OutputMode.valueOf(output)); + } + + /** + * Sets the output mode + * + * @param output + * Output mode + */ + public void setOutput(final OutputMode output) { + setOption(OUTPUT, output.name()); + } + + /** + * Returns the location of the directory where class files should be dumped + * to. + * + * @return dump location or <code>null</code> (no dumps) + */ + public String getClassDumpDir() { + return getOption(CLASSDUMPDIR, null); + } + + /** + * Sets the directory where class files should be dumped to. + * + * @param location + * dump location or <code>null</code> (no dumps) + */ + public void setClassDumpDir(final String location) { + setOption(CLASSDUMPDIR, location); + } + + private void setOption(final String key, final int value) { + setOption(key, Integer.toString(value)); + } + + private void setOption(final String key, final boolean value) { + setOption(key, Boolean.toString(value)); + } + + private void setOption(final String key, final String value) { + if (value.contains(",")) { + throw new IllegalArgumentException(format( + "Invalid character in option argument \"%s\"", value)); + } + options.put(key, value); + } + + private String getOption(final String key, final String defaultValue) { + final String value = options.get(key); + return value == null ? defaultValue : value; + } + + private boolean getOption(final String key, final boolean defaultValue) { + final String value = options.get(key); + return value == null ? defaultValue : Boolean.parseBoolean(value); + } + + private int getOption(final String key, final int defaultValue) { + final String value = options.get(key); + return value == null ? defaultValue : Integer.parseInt(value); + } + + /** + * Generate required JVM argument string based on current configuration and + * supplied agent jar location + * + * @param agentJarFile + * location of the JaCoCo Agent Jar + * @return Argument to pass to create new VM with coverage enabled + */ + public String getVMArgument(final File agentJarFile) { + return format("-javaagent:%s=%s", agentJarFile, this); + } + + /** + * Creates a string representation that can be passed to the agent via the + * command line. Might be the empty string, if no options are set. + */ + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + for (final String key : VALID_OPTIONS) { + final String value = options.get(key); + if (value != null) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append(key).append('=').append(value); + } + } + return sb.toString(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ExecutionDataAccess.java b/org.jacoco.core/src/org/jacoco/core/runtime/ExecutionDataAccess.java index 4c531f49..be526719 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/ExecutionDataAccess.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/ExecutionDataAccess.java @@ -1,172 +1,172 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import org.jacoco.core.data.ExecutionDataStore;
-import org.jacoco.core.internal.instr.InstrSupport;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * This class implements the access from instrumented classes to execution data
- * storage in the runtime. Instead of directly referencing JaCoCo implementation
- * classes the access is decoupled through a JRE API. This avoids dependencies
- * from instrumented classes on JaCoCo APIs.
- *
- * The JRE interface method used is {@link Object#equals(Object)} where the
- * passed argument is an {@link Object} array containing the class id (
- * {@link Long}), the class vm name ({@link String}) and the probe count (
- * {@link Integer}). After the method call the probe array instance is stored in
- * the first slot of the {@link Object} array.
- */
-class ExecutionDataAccess {
-
- private final ExecutionDataStore store;
-
- ExecutionDataAccess(final ExecutionDataStore store) {
- this.store = store;
- }
-
- /**
- * Retrieves the execution probe array for a given class. The passed
- * {@link Object} array instance is used for parameters and the return value
- * as follows. Call parameters:
- *
- * <ul>
- * <li>args[0]: class id ({@link Long})
- * <li>args[1]: vm class name ({@link String})
- * <li>args[2]: probe count ({@link Integer})
- * </ul>
- *
- * Return value:
- *
- * <ul>
- * <li>args[0]: probe array (<code>boolean[]</code>)
- * </ul>
- *
- * @param args
- * parameter array of length 3
- */
- public void getExecutionData(final Object[] args) {
- final Long classid = (Long) args[0];
- final String name = (String) args[1];
- final int probecount = ((Integer) args[2]).intValue();
- synchronized (store) {
- args[0] = store.get(classid, name, probecount).getData();
- }
- }
-
- /**
- * Generates code that creates the argument array for the
- * <code>getExecutionData()</code> method. The array instance is left on the
- * operand stack. The generated code requires a stack size of 5.
- *
- * @param classid
- * class identifier
- * @param classname
- * VM class name
- * @param probecount
- * probe count for this class
- * @param mv
- * visitor to emit generated code
- */
- public static void generateArgumentArray(final long classid,
- final String classname, final int probecount, final MethodVisitor mv) {
- mv.visitInsn(Opcodes.ICONST_3);
- mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
-
- // Class Id:
- mv.visitInsn(Opcodes.DUP);
- mv.visitInsn(Opcodes.ICONST_0);
- mv.visitLdcInsn(Long.valueOf(classid));
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf",
- "(J)Ljava/lang/Long;");
- mv.visitInsn(Opcodes.AASTORE);
-
- // Class Name:
- mv.visitInsn(Opcodes.DUP);
- mv.visitInsn(Opcodes.ICONST_1);
- mv.visitLdcInsn(classname);
- mv.visitInsn(Opcodes.AASTORE);
-
- // Probe Count:
- mv.visitInsn(Opcodes.DUP);
- mv.visitInsn(Opcodes.ICONST_2);
- InstrSupport.push(mv, probecount);
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer",
- "valueOf", "(I)Ljava/lang/Integer;");
- mv.visitInsn(Opcodes.AASTORE);
- }
-
- /**
- * Generates the code that calls the runtime data access through the JRE API
- * method {@link Object#equals(Object)}. The code pops a {@link Object}
- * instance from the stack and pushes the probe array of type
- * <code>boolean[]</code> on the operand stack. The generated code requires
- * a stack size of 6.
- *
- * @param classid
- * @param classname
- * @param probecount
- * @param mv
- */
- public static void generateAccessCall(final long classid,
- final String classname, final int probecount, final MethodVisitor mv) {
- // stack[0]: Ljava/lang/Object;
-
- generateArgumentArray(classid, classname, probecount, mv);
-
- // stack[1]: [Ljava/lang/Object;
- // stack[0]: Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.DUP_X1);
-
- // stack[2]: [Ljava/lang/Object;
- // stack[1]: Ljava/lang/Object;
- // stack[0]: [Ljava/lang/Object;
-
- mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
- "(Ljava/lang/Object;)Z");
- mv.visitInsn(Opcodes.POP);
-
- // stack[0]: [Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.ICONST_0);
- mv.visitInsn(Opcodes.AALOAD);
-
- // stack[0]: [Z
-
- mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC);
- }
-
- /**
- * In violation of the regular semantic of {@link Object#equals(Object)}
- * this implementation is used as the interface to the execution data store.
- *
- * @param args
- * the arguments as an {@link Object} array
- * @return has no meaning
- */
- @Override
- public boolean equals(final Object args) {
- if (args instanceof Object[]) {
- getExecutionData((Object[]) args);
- }
- return super.equals(args);
- }
-
- @Override
- public int hashCode() {
- return super.hashCode();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.internal.instr.InstrSupport; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * This class implements the access from instrumented classes to execution data + * storage in the runtime. Instead of directly referencing JaCoCo implementation + * classes the access is decoupled through a JRE API. This avoids dependencies + * from instrumented classes on JaCoCo APIs. + * + * The JRE interface method used is {@link Object#equals(Object)} where the + * passed argument is an {@link Object} array containing the class id ( + * {@link Long}), the class vm name ({@link String}) and the probe count ( + * {@link Integer}). After the method call the probe array instance is stored in + * the first slot of the {@link Object} array. + */ +class ExecutionDataAccess { + + private final ExecutionDataStore store; + + ExecutionDataAccess(final ExecutionDataStore store) { + this.store = store; + } + + /** + * Retrieves the execution probe array for a given class. The passed + * {@link Object} array instance is used for parameters and the return value + * as follows. Call parameters: + * + * <ul> + * <li>args[0]: class id ({@link Long}) + * <li>args[1]: vm class name ({@link String}) + * <li>args[2]: probe count ({@link Integer}) + * </ul> + * + * Return value: + * + * <ul> + * <li>args[0]: probe array (<code>boolean[]</code>) + * </ul> + * + * @param args + * parameter array of length 3 + */ + public void getExecutionData(final Object[] args) { + final Long classid = (Long) args[0]; + final String name = (String) args[1]; + final int probecount = ((Integer) args[2]).intValue(); + synchronized (store) { + args[0] = store.get(classid, name, probecount).getData(); + } + } + + /** + * Generates code that creates the argument array for the + * <code>getExecutionData()</code> method. The array instance is left on the + * operand stack. The generated code requires a stack size of 5. + * + * @param classid + * class identifier + * @param classname + * VM class name + * @param probecount + * probe count for this class + * @param mv + * visitor to emit generated code + */ + public static void generateArgumentArray(final long classid, + final String classname, final int probecount, final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_3); + mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); + + // Class Id: + mv.visitInsn(Opcodes.DUP); + mv.visitInsn(Opcodes.ICONST_0); + mv.visitLdcInsn(Long.valueOf(classid)); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", + "(J)Ljava/lang/Long;"); + mv.visitInsn(Opcodes.AASTORE); + + // Class Name: + mv.visitInsn(Opcodes.DUP); + mv.visitInsn(Opcodes.ICONST_1); + mv.visitLdcInsn(classname); + mv.visitInsn(Opcodes.AASTORE); + + // Probe Count: + mv.visitInsn(Opcodes.DUP); + mv.visitInsn(Opcodes.ICONST_2); + InstrSupport.push(mv, probecount); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", + "valueOf", "(I)Ljava/lang/Integer;"); + mv.visitInsn(Opcodes.AASTORE); + } + + /** + * Generates the code that calls the runtime data access through the JRE API + * method {@link Object#equals(Object)}. The code pops a {@link Object} + * instance from the stack and pushes the probe array of type + * <code>boolean[]</code> on the operand stack. The generated code requires + * a stack size of 6. + * + * @param classid + * @param classname + * @param probecount + * @param mv + */ + public static void generateAccessCall(final long classid, + final String classname, final int probecount, final MethodVisitor mv) { + // stack[0]: Ljava/lang/Object; + + generateArgumentArray(classid, classname, probecount, mv); + + // stack[1]: [Ljava/lang/Object; + // stack[0]: Ljava/lang/Object; + + mv.visitInsn(Opcodes.DUP_X1); + + // stack[2]: [Ljava/lang/Object; + // stack[1]: Ljava/lang/Object; + // stack[0]: [Ljava/lang/Object; + + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals", + "(Ljava/lang/Object;)Z"); + mv.visitInsn(Opcodes.POP); + + // stack[0]: [Ljava/lang/Object; + + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.AALOAD); + + // stack[0]: [Z + + mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC); + } + + /** + * In violation of the regular semantic of {@link Object#equals(Object)} + * this implementation is used as the interface to the execution data store. + * + * @param args + * the arguments as an {@link Object} array + * @return has no meaning + */ + @Override + public boolean equals(final Object args) { + if (args instanceof Object[]) { + getExecutionData((Object[]) args); + } + return super.equals(args); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java index e045d91c..7d0d5e8c 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java @@ -1,95 +1,95 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import org.jacoco.core.data.IExecutionDataVisitor;
-import org.jacoco.core.data.ISessionInfoVisitor;
-
-/**
- * This interface represents a particular mechanism to collect execution
- * information in the target VM at runtime.
- */
-public interface IRuntime extends IExecutionDataAccessorGenerator {
-
- /**
- * Sets a session identifier for this runtime. The identifier is used when
- * execution data is collected. If no identifier is explicitly set a
- * identifier is generated from the host name and a random number. This
- * method can be called at any time.
- *
- * @see #collect(IExecutionDataVisitor, ISessionInfoVisitor, boolean)
- * @param id
- * new session identifier
- */
- public void setSessionId(String id);
-
- /**
- * Get the current a session identifier for this runtime.
- *
- * @see #setSessionId(String)
- * @return current session identifier
- */
- public String getSessionId();
-
- /**
- * Starts the coverage runtime. This method MUST be called before any class
- * instrumented for this runtime is loaded.
- *
- * @throws Exception
- * any internal problem during startup
- */
- public void startup() throws Exception;
-
- /**
- * Allows the coverage runtime to cleanup internals. This class should be
- * called when classes instrumented for this runtime are not used any more.
- */
- public void shutdown();
-
- /**
- * Collects the current execution data and writes it to the given
- * {@link IExecutionDataVisitor} object. This method must only be called
- * between {@link #startup()} and {@link #shutdown()}.
- *
- * @param executionDataVisitor
- * handler to write coverage data to
- * @param sessionInfoVisitor
- * optional visitor to write session information to or
- * <code>null</code> if session information is not required
- * @param reset
- * if <code>true</code> the current coverage information is also
- * cleared
- */
- public void collect(IExecutionDataVisitor executionDataVisitor,
- ISessionInfoVisitor sessionInfoVisitor, boolean reset);
-
- /**
- * Resets all coverage information. This method must only be called between
- * {@link #startup()} and {@link #shutdown()}.
- */
- public void reset();
-
- /**
- * Clears the execution data buffered in the given instrumented type. It
- * forces the class to re-connect to the runtime the next time it is
- * executed. This method is used by the agent and is required when a class
- * has been redefined. Note that a call to this method does not actually
- * reset the data that is already stored in the runtime.
- *
- * @param type
- * class to clear
- * @throws Exception
- * if clearing the data is not possible
- */
- public void disconnect(final Class<?> type) throws Exception;
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import org.jacoco.core.data.IExecutionDataVisitor; +import org.jacoco.core.data.ISessionInfoVisitor; + +/** + * This interface represents a particular mechanism to collect execution + * information in the target VM at runtime. + */ +public interface IRuntime extends IExecutionDataAccessorGenerator { + + /** + * Sets a session identifier for this runtime. The identifier is used when + * execution data is collected. If no identifier is explicitly set a + * identifier is generated from the host name and a random number. This + * method can be called at any time. + * + * @see #collect(IExecutionDataVisitor, ISessionInfoVisitor, boolean) + * @param id + * new session identifier + */ + public void setSessionId(String id); + + /** + * Get the current a session identifier for this runtime. + * + * @see #setSessionId(String) + * @return current session identifier + */ + public String getSessionId(); + + /** + * Starts the coverage runtime. This method MUST be called before any class + * instrumented for this runtime is loaded. + * + * @throws Exception + * any internal problem during startup + */ + public void startup() throws Exception; + + /** + * Allows the coverage runtime to cleanup internals. This class should be + * called when classes instrumented for this runtime are not used any more. + */ + public void shutdown(); + + /** + * Collects the current execution data and writes it to the given + * {@link IExecutionDataVisitor} object. This method must only be called + * between {@link #startup()} and {@link #shutdown()}. + * + * @param executionDataVisitor + * handler to write coverage data to + * @param sessionInfoVisitor + * optional visitor to write session information to or + * <code>null</code> if session information is not required + * @param reset + * if <code>true</code> the current coverage information is also + * cleared + */ + public void collect(IExecutionDataVisitor executionDataVisitor, + ISessionInfoVisitor sessionInfoVisitor, boolean reset); + + /** + * Resets all coverage information. This method must only be called between + * {@link #startup()} and {@link #shutdown()}. + */ + public void reset(); + + /** + * Clears the execution data buffered in the given instrumented type. It + * forces the class to re-connect to the runtime the next time it is + * executed. This method is used by the agent and is required when a class + * has been redefined. Note that a call to this method does not actually + * reset the data that is already stored in the runtime. + * + * @param type + * class to clear + * @throws Exception + * if clearing the data is not possible + */ + public void disconnect(final Class<?> type) throws Exception; + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java index a44fb4df..c8851aba 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java @@ -1,188 +1,188 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-
-import org.jacoco.core.internal.instr.InstrSupport;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * This {@link IRuntime} implementation uses the Java logging API to report
- * coverage data.
- * <p>
- *
- * The implementation uses a dedicated log channel. Instrumented classes call
- * {@link Logger#log(Level, String, Object[])} with the class identifier in the
- * first slot of the parameter array. The runtime implements a {@link Handler}
- * for this channel that puts the probe data structure into the first slot of
- * the parameter array.
- */
-public class LoggerRuntime extends AbstractRuntime {
-
- private static final String CHANNEL = "jacoco-runtime";
-
- private final String key;
-
- private final Logger logger;
-
- private final Handler handler;
-
- /**
- * Creates a new runtime.
- */
- public LoggerRuntime() {
- super();
- this.key = Integer.toHexString(hashCode());
- this.logger = configureLogger();
- this.handler = new RuntimeHandler();
- }
-
- private Logger configureLogger() {
- final Logger l = Logger.getLogger(CHANNEL);
- l.setUseParentHandlers(false);
- l.setLevel(Level.ALL);
- return l;
- }
-
- public int generateDataAccessor(final long classid, final String classname,
- final int probecount, final MethodVisitor mv) {
-
- // The data accessor performs the following steps:
- //
- // final Object[] args = new Object[3];
- // args[0] = Long.valueOf(classid);
- // args[1] = classname;
- // args[2] = Integer.valueOf(probecount);
- // Logger.getLogger(CHANNEL).log(Level.INFO, key, args);
- // final byte[] probedata = (byte[]) args[0];
- //
- // Note that local variable 'args' is used at two places. As were not
- // allowed to allocate local variables we have to keep this value with
- // DUP and SWAP operations on the operand stack.
-
- // 1. Create parameter array:
-
- ExecutionDataAccess.generateArgumentArray(classid, classname,
- probecount, mv);
-
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.DUP);
-
- // Stack[1]: [Ljava/lang/Object;
- // Stack[0]: [Ljava/lang/Object;
-
- // 2. Call Logger:
-
- mv.visitLdcInsn(CHANNEL);
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/logging/Logger",
- "getLogger", "(Ljava/lang/String;)Ljava/util/logging/Logger;");
-
- // Stack[2]: Ljava/util/logging/Logger;
- // Stack[1]: [Ljava/lang/Object;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.SWAP);
-
- // Stack[2]: [Ljava/lang/Object;
- // Stack[1]: Ljava/util/logging/Logger;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitFieldInsn(Opcodes.GETSTATIC, "java/util/logging/Level", "INFO",
- "Ljava/util/logging/Level;");
-
- // Stack[3]: Ljava/util/logging/Level;
- // Stack[2]: [Ljava/lang/Object;
- // Stack[1]: Ljava/util/logging/Logger;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.SWAP);
-
- // Stack[3]: [Ljava/lang/Object;
- // Stack[2]: Ljava/util/logging/Level;
- // Stack[1]: Ljava/util/logging/Logger;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitLdcInsn(key);
-
- // Stack[4]: Ljava/lang/String;
- // Stack[3]: [Ljava/lang/Object;
- // Stack[2]: Ljava/util/logging/Level;
- // Stack[1]: Ljava/util/logging/Logger;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitInsn(Opcodes.SWAP);
-
- // Stack[4]: [Ljava/lang/Object;
- // Stack[3]: Ljava/lang/String;
- // Stack[2]: Ljava/util/logging/Level;
- // Stack[1]: Ljava/util/logging/Logger;
- // Stack[0]: [Ljava/lang/Object;
-
- mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/logging/Logger",
- "log",
- "(Ljava/util/logging/Level;Ljava/lang/String;[Ljava/lang/Object;)V");
-
- // Stack[0]: [Ljava/lang/Object;
-
- // 3. Load data structure from parameter array:
-
- mv.visitInsn(Opcodes.ICONST_0);
- mv.visitInsn(Opcodes.AALOAD);
- mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC);
-
- // Stack[0]: [Z
-
- return 5; // Maximum local stack size is 5
- }
-
- public void startup() {
- setStartTimeStamp();
- this.logger.addHandler(handler);
- }
-
- public void shutdown() {
- this.logger.removeHandler(handler);
- }
-
- private class RuntimeHandler extends Handler {
-
- @Override
- public void publish(final LogRecord record) {
- if (key.equals(record.getMessage())) {
- access.getExecutionData(record.getParameters());
- }
- }
-
- @Override
- public void flush() {
- // nothing to do
- }
-
- @Override
- public void close() throws SecurityException {
- // The Java logging framework removes and closes all handlers on JVM
- // shutdown. As soon as our handler has been removed, all classes
- // that might get instrumented during shutdown (e.g. loaded by other
- // shutdown hooks) will fail to initialize. Therefore we add ourself
- // again here. This is a nasty hack that might fail in some Java
- // implementations.
- logger.addHandler(handler);
- }
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * This {@link IRuntime} implementation uses the Java logging API to report + * coverage data. + * <p> + * + * The implementation uses a dedicated log channel. Instrumented classes call + * {@link Logger#log(Level, String, Object[])} with the class identifier in the + * first slot of the parameter array. The runtime implements a {@link Handler} + * for this channel that puts the probe data structure into the first slot of + * the parameter array. + */ +public class LoggerRuntime extends AbstractRuntime { + + private static final String CHANNEL = "jacoco-runtime"; + + private final String key; + + private final Logger logger; + + private final Handler handler; + + /** + * Creates a new runtime. + */ + public LoggerRuntime() { + super(); + this.key = Integer.toHexString(hashCode()); + this.logger = configureLogger(); + this.handler = new RuntimeHandler(); + } + + private Logger configureLogger() { + final Logger l = Logger.getLogger(CHANNEL); + l.setUseParentHandlers(false); + l.setLevel(Level.ALL); + return l; + } + + public int generateDataAccessor(final long classid, final String classname, + final int probecount, final MethodVisitor mv) { + + // The data accessor performs the following steps: + // + // final Object[] args = new Object[3]; + // args[0] = Long.valueOf(classid); + // args[1] = classname; + // args[2] = Integer.valueOf(probecount); + // Logger.getLogger(CHANNEL).log(Level.INFO, key, args); + // final byte[] probedata = (byte[]) args[0]; + // + // Note that local variable 'args' is used at two places. As were not + // allowed to allocate local variables we have to keep this value with + // DUP and SWAP operations on the operand stack. + + // 1. Create parameter array: + + ExecutionDataAccess.generateArgumentArray(classid, classname, + probecount, mv); + + // Stack[0]: [Ljava/lang/Object; + + mv.visitInsn(Opcodes.DUP); + + // Stack[1]: [Ljava/lang/Object; + // Stack[0]: [Ljava/lang/Object; + + // 2. Call Logger: + + mv.visitLdcInsn(CHANNEL); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/logging/Logger", + "getLogger", "(Ljava/lang/String;)Ljava/util/logging/Logger;"); + + // Stack[2]: Ljava/util/logging/Logger; + // Stack[1]: [Ljava/lang/Object; + // Stack[0]: [Ljava/lang/Object; + + mv.visitInsn(Opcodes.SWAP); + + // Stack[2]: [Ljava/lang/Object; + // Stack[1]: Ljava/util/logging/Logger; + // Stack[0]: [Ljava/lang/Object; + + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/util/logging/Level", "INFO", + "Ljava/util/logging/Level;"); + + // Stack[3]: Ljava/util/logging/Level; + // Stack[2]: [Ljava/lang/Object; + // Stack[1]: Ljava/util/logging/Logger; + // Stack[0]: [Ljava/lang/Object; + + mv.visitInsn(Opcodes.SWAP); + + // Stack[3]: [Ljava/lang/Object; + // Stack[2]: Ljava/util/logging/Level; + // Stack[1]: Ljava/util/logging/Logger; + // Stack[0]: [Ljava/lang/Object; + + mv.visitLdcInsn(key); + + // Stack[4]: Ljava/lang/String; + // Stack[3]: [Ljava/lang/Object; + // Stack[2]: Ljava/util/logging/Level; + // Stack[1]: Ljava/util/logging/Logger; + // Stack[0]: [Ljava/lang/Object; + + mv.visitInsn(Opcodes.SWAP); + + // Stack[4]: [Ljava/lang/Object; + // Stack[3]: Ljava/lang/String; + // Stack[2]: Ljava/util/logging/Level; + // Stack[1]: Ljava/util/logging/Logger; + // Stack[0]: [Ljava/lang/Object; + + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/logging/Logger", + "log", + "(Ljava/util/logging/Level;Ljava/lang/String;[Ljava/lang/Object;)V"); + + // Stack[0]: [Ljava/lang/Object; + + // 3. Load data structure from parameter array: + + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.AALOAD); + mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC); + + // Stack[0]: [Z + + return 5; // Maximum local stack size is 5 + } + + public void startup() { + setStartTimeStamp(); + this.logger.addHandler(handler); + } + + public void shutdown() { + this.logger.removeHandler(handler); + } + + private class RuntimeHandler extends Handler { + + @Override + public void publish(final LogRecord record) { + if (key.equals(record.getMessage())) { + access.getExecutionData(record.getParameters()); + } + } + + @Override + public void flush() { + // nothing to do + } + + @Override + public void close() throws SecurityException { + // The Java logging framework removes and closes all handlers on JVM + // shutdown. As soon as our handler has been removed, all classes + // that might get instrumented during shutdown (e.g. loaded by other + // shutdown hooks) will fail to initialize. Therefore we add ourself + // again here. This is a nasty hack that might fail in some Java + // implementations. + logger.addHandler(handler); + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java index a09190a0..f2960289 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java @@ -1,178 +1,178 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import static java.lang.String.format;
-
-import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
-import java.lang.instrument.Instrumentation;
-import java.lang.reflect.Field;
-import java.security.ProtectionDomain;
-
-import org.objectweb.asm.ClassAdapter;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * This {@link IRuntime} implementation works with a modified system class. A
- * new static method is added to a bootstrap class that will be used by
- * instrumented classes. As the system class itself needs to be instrumented
- * this runtime requires a Java agent.
- */
-public class ModifiedSystemClassRuntime extends AbstractRuntime {
-
- private static final String ACCESS_FIELD_TYPE = "Ljava/lang/Object;";
-
- private final Class<?> systemClass;
-
- private final String systemClassName;
-
- private final String accessFieldName;
-
- /**
- * Creates a new runtime based on the given class and members.
- *
- * @param systemClass
- * system class that contains the execution data
- * @param accessFieldName
- * name of the public static runtime access field
- *
- */
- public ModifiedSystemClassRuntime(final Class<?> systemClass,
- final String accessFieldName) {
- super();
- this.systemClass = systemClass;
- this.systemClassName = systemClass.getName().replace('.', '/');
- this.accessFieldName = accessFieldName;
- }
-
- public void startup() throws Exception {
- setStartTimeStamp();
- final Field field = systemClass.getField(accessFieldName);
- field.set(null, new ExecutionDataAccess(store));
- }
-
- public void shutdown() {
- // nothing to do
- }
-
- public int generateDataAccessor(final long classid, final String classname,
- final int probecount, final MethodVisitor mv) {
-
- mv.visitFieldInsn(Opcodes.GETSTATIC, systemClassName, accessFieldName,
- ACCESS_FIELD_TYPE);
-
- ExecutionDataAccess.generateAccessCall(classid, classname, probecount,
- mv);
-
- return 6;
- }
-
- /**
- * Creates a new {@link ModifiedSystemClassRuntime} using the given class as
- * the data container. Members are creates with internal default names. The
- * given class must not have been loaded before by the agent.
- *
- * @param inst
- * instrumentation interface
- * @param className
- * VM name of the class to use
- * @return new runtime instance
- *
- * @throws ClassNotFoundException
- * id the given class can not be found
- */
- public static IRuntime createFor(final Instrumentation inst,
- final String className) throws ClassNotFoundException {
- return createFor(inst, className, "$jacocoAccess");
- }
-
- /**
- * Creates a new {@link ModifiedSystemClassRuntime} using the given class as
- * the data container. The given class must not have been loaded before by
- * the agent.
- *
- * @param inst
- * instrumentation interface
- * @param className
- * VM name of the class to use
- * @param accessFieldName
- * name of the added runtime access field
- * @return new runtime instance
- *
- * @throws ClassNotFoundException
- * id the given class can not be found
- */
- public static IRuntime createFor(final Instrumentation inst,
- final String className, final String accessFieldName)
- throws ClassNotFoundException {
- final ClassFileTransformer transformer = new ClassFileTransformer() {
- public byte[] transform(final ClassLoader loader,
- final String name, final Class<?> classBeingRedefined,
- final ProtectionDomain protectionDomain, final byte[] source)
- throws IllegalClassFormatException {
- if (name.equals(className)) {
- return instrument(source, accessFieldName);
- }
- return null;
- }
- };
- inst.addTransformer(transformer);
- final Class<?> clazz = Class.forName(className.replace('/', '.'));
- inst.removeTransformer(transformer);
- try {
- clazz.getField(accessFieldName);
- } catch (final NoSuchFieldException e) {
- throw new RuntimeException(format(
- "Class %s could not be instrumented.", className), e);
- }
- return new ModifiedSystemClassRuntime(clazz, accessFieldName);
- }
-
- /**
- * Adds the static access method and data field to the given class
- * definition.
- *
- * @param source
- * class definition source
- * @param accessFieldName
- * name of the runtime access field
- * @return instrumented version with added members
- */
- public static byte[] instrument(final byte[] source,
- final String accessFieldName) {
- final ClassReader reader = new ClassReader(source);
- final ClassWriter writer = new ClassWriter(reader, 0);
- reader.accept(new ClassAdapter(writer) {
-
- @Override
- public void visitEnd() {
- createDataField(cv, accessFieldName);
- super.visitEnd();
- }
-
- }, ClassReader.EXPAND_FRAMES);
- return writer.toByteArray();
- }
-
- private static void createDataField(final ClassVisitor visitor,
- final String dataField) {
- visitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC
- | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, dataField,
- ACCESS_FIELD_TYPE, null, null);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import static java.lang.String.format; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Field; +import java.security.ProtectionDomain; + +import org.objectweb.asm.ClassAdapter; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * This {@link IRuntime} implementation works with a modified system class. A + * new static method is added to a bootstrap class that will be used by + * instrumented classes. As the system class itself needs to be instrumented + * this runtime requires a Java agent. + */ +public class ModifiedSystemClassRuntime extends AbstractRuntime { + + private static final String ACCESS_FIELD_TYPE = "Ljava/lang/Object;"; + + private final Class<?> systemClass; + + private final String systemClassName; + + private final String accessFieldName; + + /** + * Creates a new runtime based on the given class and members. + * + * @param systemClass + * system class that contains the execution data + * @param accessFieldName + * name of the public static runtime access field + * + */ + public ModifiedSystemClassRuntime(final Class<?> systemClass, + final String accessFieldName) { + super(); + this.systemClass = systemClass; + this.systemClassName = systemClass.getName().replace('.', '/'); + this.accessFieldName = accessFieldName; + } + + public void startup() throws Exception { + setStartTimeStamp(); + final Field field = systemClass.getField(accessFieldName); + field.set(null, new ExecutionDataAccess(store)); + } + + public void shutdown() { + // nothing to do + } + + public int generateDataAccessor(final long classid, final String classname, + final int probecount, final MethodVisitor mv) { + + mv.visitFieldInsn(Opcodes.GETSTATIC, systemClassName, accessFieldName, + ACCESS_FIELD_TYPE); + + ExecutionDataAccess.generateAccessCall(classid, classname, probecount, + mv); + + return 6; + } + + /** + * Creates a new {@link ModifiedSystemClassRuntime} using the given class as + * the data container. Members are creates with internal default names. The + * given class must not have been loaded before by the agent. + * + * @param inst + * instrumentation interface + * @param className + * VM name of the class to use + * @return new runtime instance + * + * @throws ClassNotFoundException + * id the given class can not be found + */ + public static IRuntime createFor(final Instrumentation inst, + final String className) throws ClassNotFoundException { + return createFor(inst, className, "$jacocoAccess"); + } + + /** + * Creates a new {@link ModifiedSystemClassRuntime} using the given class as + * the data container. The given class must not have been loaded before by + * the agent. + * + * @param inst + * instrumentation interface + * @param className + * VM name of the class to use + * @param accessFieldName + * name of the added runtime access field + * @return new runtime instance + * + * @throws ClassNotFoundException + * id the given class can not be found + */ + public static IRuntime createFor(final Instrumentation inst, + final String className, final String accessFieldName) + throws ClassNotFoundException { + final ClassFileTransformer transformer = new ClassFileTransformer() { + public byte[] transform(final ClassLoader loader, + final String name, final Class<?> classBeingRedefined, + final ProtectionDomain protectionDomain, final byte[] source) + throws IllegalClassFormatException { + if (name.equals(className)) { + return instrument(source, accessFieldName); + } + return null; + } + }; + inst.addTransformer(transformer); + final Class<?> clazz = Class.forName(className.replace('/', '.')); + inst.removeTransformer(transformer); + try { + clazz.getField(accessFieldName); + } catch (final NoSuchFieldException e) { + throw new RuntimeException(format( + "Class %s could not be instrumented.", className), e); + } + return new ModifiedSystemClassRuntime(clazz, accessFieldName); + } + + /** + * Adds the static access method and data field to the given class + * definition. + * + * @param source + * class definition source + * @param accessFieldName + * name of the runtime access field + * @return instrumented version with added members + */ + public static byte[] instrument(final byte[] source, + final String accessFieldName) { + final ClassReader reader = new ClassReader(source); + final ClassWriter writer = new ClassWriter(reader, 0); + reader.accept(new ClassAdapter(writer) { + + @Override + public void visitEnd() { + createDataField(cv, accessFieldName); + super.visitEnd(); + } + + }, ClassReader.EXPAND_FRAMES); + return writer.toByteArray(); + } + + private static void createDataField(final ClassVisitor visitor, + final String dataField) { + visitor.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC + | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, dataField, + ACCESS_FIELD_TYPE, null, null); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java index 456fccfe..c293b20b 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java @@ -1,69 +1,69 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.jacoco.core.data.ExecutionDataReader;
-
-/**
- * {@link ExecutionDataReader} with commands added for runtime remote control.
- */
-public class RemoteControlReader extends ExecutionDataReader {
-
- private IRemoteCommandVisitor remoteCommandVisitor;
-
- /**
- * Create a new read based on the given input stream.
- *
- * @param input
- * input stream to read commands from
- * @throws IOException
- * if the stream does not have a valid header
- */
- public RemoteControlReader(final InputStream input) throws IOException {
- super(input);
- }
-
- @Override
- protected boolean readBlock(final byte blockid) throws IOException {
- switch (blockid) {
- case RemoteControlWriter.BLOCK_CMDDUMP:
- readDumpCommand();
- return true;
- case RemoteControlWriter.BLOCK_CMDOK:
- return false;
- default:
- return super.readBlock(blockid);
- }
- }
-
- /**
- * Sets an listener for agent commands.
- *
- * @param visitor
- */
- public void setRemoteCommandVisitor(final IRemoteCommandVisitor visitor) {
- this.remoteCommandVisitor = visitor;
- }
-
- private void readDumpCommand() throws IOException {
- if (remoteCommandVisitor == null) {
- throw new IOException("No remote command visitor.");
- }
- final boolean dump = in.readBoolean();
- final boolean reset = in.readBoolean();
- remoteCommandVisitor.visitDumpCommand(dump, reset);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import java.io.IOException; +import java.io.InputStream; + +import org.jacoco.core.data.ExecutionDataReader; + +/** + * {@link ExecutionDataReader} with commands added for runtime remote control. + */ +public class RemoteControlReader extends ExecutionDataReader { + + private IRemoteCommandVisitor remoteCommandVisitor; + + /** + * Create a new read based on the given input stream. + * + * @param input + * input stream to read commands from + * @throws IOException + * if the stream does not have a valid header + */ + public RemoteControlReader(final InputStream input) throws IOException { + super(input); + } + + @Override + protected boolean readBlock(final byte blockid) throws IOException { + switch (blockid) { + case RemoteControlWriter.BLOCK_CMDDUMP: + readDumpCommand(); + return true; + case RemoteControlWriter.BLOCK_CMDOK: + return false; + default: + return super.readBlock(blockid); + } + } + + /** + * Sets an listener for agent commands. + * + * @param visitor + */ + public void setRemoteCommandVisitor(final IRemoteCommandVisitor visitor) { + this.remoteCommandVisitor = visitor; + } + + private void readDumpCommand() throws IOException { + if (remoteCommandVisitor == null) { + throw new IOException("No remote command visitor."); + } + final boolean dump = in.readBoolean(); + final boolean reset = in.readBoolean(); + remoteCommandVisitor.visitDumpCommand(dump, reset); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java index 5a204d85..b3b4527d 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java @@ -1,61 +1,61 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.jacoco.core.data.ExecutionDataWriter;
-
-/**
- * {@link ExecutionDataWriter} with commands added for runtime remote control.
- */
-public class RemoteControlWriter extends ExecutionDataWriter implements
- IRemoteCommandVisitor {
-
- /** Block identifier to confirm successful command execution. */
- public static final byte BLOCK_CMDOK = 0x20;
-
- /** Block identifier for dump command */
- public static final byte BLOCK_CMDDUMP = 0x40;
-
- /**
- * Creates a new writer based on the given output stream.
- *
- * @param output
- * stream to write commands to
- * @throws IOException
- * if the header can't be written
- */
- public RemoteControlWriter(final OutputStream output) throws IOException {
- super(output);
- }
-
- /**
- * Sends a confirmation that a commands has been successfully executed and
- * the response is completed.
- *
- * @throws IOException
- * in case of problems with the remote connection
- */
- public void sendCmdOk() throws IOException {
- out.writeByte(RemoteControlWriter.BLOCK_CMDOK);
- }
-
- public void visitDumpCommand(final boolean dump, final boolean reset)
- throws IOException {
- out.writeByte(RemoteControlWriter.BLOCK_CMDDUMP);
- out.writeBoolean(dump);
- out.writeBoolean(reset);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import java.io.IOException; +import java.io.OutputStream; + +import org.jacoco.core.data.ExecutionDataWriter; + +/** + * {@link ExecutionDataWriter} with commands added for runtime remote control. + */ +public class RemoteControlWriter extends ExecutionDataWriter implements + IRemoteCommandVisitor { + + /** Block identifier to confirm successful command execution. */ + public static final byte BLOCK_CMDOK = 0x20; + + /** Block identifier for dump command */ + public static final byte BLOCK_CMDDUMP = 0x40; + + /** + * Creates a new writer based on the given output stream. + * + * @param output + * stream to write commands to + * @throws IOException + * if the header can't be written + */ + public RemoteControlWriter(final OutputStream output) throws IOException { + super(output); + } + + /** + * Sends a confirmation that a commands has been successfully executed and + * the response is completed. + * + * @throws IOException + * in case of problems with the remote connection + */ + public void sendCmdOk() throws IOException { + out.writeByte(RemoteControlWriter.BLOCK_CMDOK); + } + + public void visitDumpCommand(final boolean dump, final boolean reset) + throws IOException { + out.writeByte(RemoteControlWriter.BLOCK_CMDDUMP); + out.writeBoolean(dump); + out.writeBoolean(reset); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java index 4d010d8a..196872d6 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java @@ -1,75 +1,75 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-/**
- * This {@link IRuntime} implementation makes the execution data available
- * through a special entry in the {@link System#getProperties()} hash table. The
- * advantage is, that the instrumented classes do not get dependencies to other
- * classes than the JRE library itself.
- *
- * This runtime may cause problems in environments with security restrictions,
- * in applications that replace the system properties or in applications that
- * fail if non-String values are placed in the system properties.
- */
-public class SystemPropertiesRuntime extends AbstractRuntime {
-
- private static final String KEYPREFIX = "jacoco-";
-
- private final String key;
-
- /**
- * Creates a new runtime.
- */
- public SystemPropertiesRuntime() {
- super();
- this.key = KEYPREFIX + Integer.toHexString(hashCode());
- }
-
- public int generateDataAccessor(final long classid, final String classname,
- final int probecount, final MethodVisitor mv) {
- mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System",
- "getProperties", "()Ljava/util/Properties;");
-
- // Stack[0]: Ljava/util/Properties;
-
- mv.visitLdcInsn(key);
-
- // Stack[1]: Ljava/lang/String;
- // Stack[0]: Ljava/util/Properties;
-
- mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties",
- "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
-
- // Stack[0]: Ljava/lang/Object;
-
- ExecutionDataAccess.generateAccessCall(classid, classname, probecount,
- mv);
-
- // Stack[0]: [Z
-
- return 6; // Maximum local stack size is 3
- }
-
- public void startup() {
- setStartTimeStamp();
- System.getProperties().put(key, access);
- }
-
- public void shutdown() {
- System.getProperties().remove(key);
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * This {@link IRuntime} implementation makes the execution data available + * through a special entry in the {@link System#getProperties()} hash table. The + * advantage is, that the instrumented classes do not get dependencies to other + * classes than the JRE library itself. + * + * This runtime may cause problems in environments with security restrictions, + * in applications that replace the system properties or in applications that + * fail if non-String values are placed in the system properties. + */ +public class SystemPropertiesRuntime extends AbstractRuntime { + + private static final String KEYPREFIX = "jacoco-"; + + private final String key; + + /** + * Creates a new runtime. + */ + public SystemPropertiesRuntime() { + super(); + this.key = KEYPREFIX + Integer.toHexString(hashCode()); + } + + public int generateDataAccessor(final long classid, final String classname, + final int probecount, final MethodVisitor mv) { + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", + "getProperties", "()Ljava/util/Properties;"); + + // Stack[0]: Ljava/util/Properties; + + mv.visitLdcInsn(key); + + // Stack[1]: Ljava/lang/String; + // Stack[0]: Ljava/util/Properties; + + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Properties", + "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); + + // Stack[0]: Ljava/lang/Object; + + ExecutionDataAccess.generateAccessCall(classid, classname, probecount, + mv); + + // Stack[0]: [Z + + return 6; // Maximum local stack size is 3 + } + + public void startup() { + setStartTimeStamp(); + System.getProperties().put(key, access); + } + + public void shutdown() { + System.getProperties().remove(key); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java index 9951d20b..70fb8b5d 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java @@ -1,73 +1,73 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.runtime;
-
-import java.util.regex.Pattern;
-
-/**
- * Matches strings against <code>?</code>/<code>*</code> wildcard expressions.
- * Multiple expressions can be separated with a colon (:). In this case the
- * expression matches if at least one part matches.
- */
-public class WildcardMatcher {
-
- private final Pattern pattern;
-
- /**
- * Creates a new matcher with the given expression.
- *
- * @param expression
- * wildcard expressions
- */
- public WildcardMatcher(final String expression) {
- final String[] parts = expression.split("\\:");
- final StringBuilder regex = new StringBuilder(expression.length() * 2);
- boolean next = false;
- for (final String part : parts) {
- if (next) {
- regex.append('|');
- }
- regex.append('(').append(toRegex(part)).append(')');
- next = true;
- }
- pattern = Pattern.compile(regex.toString());
- }
-
- private static CharSequence toRegex(final String expression) {
- final StringBuilder regex = new StringBuilder(expression.length() * 2);
- for (final char c : expression.toCharArray()) {
- switch (c) {
- case '?':
- regex.append(".?");
- break;
- case '*':
- regex.append(".*");
- break;
- default:
- regex.append(Pattern.quote(String.valueOf(c)));
- }
- }
- return regex;
- }
-
- /**
- * Matches the given string against the expressions of this matcher.
- *
- * @param s
- * string to test
- * @return <code>true</code>, if the expression matches
- */
- public boolean matches(final String s) {
- return pattern.matcher(s).matches();
- }
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.runtime; + +import java.util.regex.Pattern; + +/** + * Matches strings against <code>?</code>/<code>*</code> wildcard expressions. + * Multiple expressions can be separated with a colon (:). In this case the + * expression matches if at least one part matches. + */ +public class WildcardMatcher { + + private final Pattern pattern; + + /** + * Creates a new matcher with the given expression. + * + * @param expression + * wildcard expressions + */ + public WildcardMatcher(final String expression) { + final String[] parts = expression.split("\\:"); + final StringBuilder regex = new StringBuilder(expression.length() * 2); + boolean next = false; + for (final String part : parts) { + if (next) { + regex.append('|'); + } + regex.append('(').append(toRegex(part)).append(')'); + next = true; + } + pattern = Pattern.compile(regex.toString()); + } + + private static CharSequence toRegex(final String expression) { + final StringBuilder regex = new StringBuilder(expression.length() * 2); + for (final char c : expression.toCharArray()) { + switch (c) { + case '?': + regex.append(".?"); + break; + case '*': + regex.append(".*"); + break; + default: + regex.append(Pattern.quote(String.valueOf(c))); + } + } + return regex; + } + + /** + * Matches the given string against the expressions of this matcher. + * + * @param s + * string to test + * @return <code>true</code>, if the expression matches + */ + public boolean matches(final String s) { + return pattern.matcher(s).matches(); + } + +} |