aboutsummaryrefslogtreecommitdiff
path: root/org.jacoco.core/src/org/jacoco/core/internal/analysis
diff options
context:
space:
mode:
authorMarc R. Hoffmann <hoffmann@mountainminds.com>2011-01-08 20:09:23 +0000
committerMarc R. Hoffmann <hoffmann@mountainminds.com>2011-01-08 20:09:23 +0000
commitebad55ad1f8f33ad500dbc4f7091e51731f6c597 (patch)
treeca19cd2e2d463353ca7348e38810670ed9fd1b72 /org.jacoco.core/src/org/jacoco/core/internal/analysis
parent805be218b948d40ba5c6796ff98d3ab108034727 (diff)
downloadjacoco-ebad55ad1f8f33ad500dbc4f7091e51731f6c597.tar.gz
Trac 133: Remove internal classes from API package.
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal/analysis')
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java129
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java106
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java303
3 files changed, 538 insertions, 0 deletions
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
new file mode 100644
index 00000000..d880b11a
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.ClassCoverage;
+import org.jacoco.core.analysis.MethodCoverage;
+import org.jacoco.core.analysis.StringPool;
+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.
+ *
+ * @author Marc R. Hoffmann
+ * @version $qualified.bundle.version$
+ */
+public class ClassAnalyzer implements IClassProbesVisitor {
+
+ private final long classid;
+ private final boolean executionData[];
+ private final StringPool stringPool;
+
+ private ClassCoverage 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 ClassCoverage 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 ClassCoverage(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 MethodCoverage methodCoverage = getCoverage();
+ if (methodCoverage.getInstructionCounter().getTotalCount() > 0) {
+ // Only consider methods that actually contain code
+ coverage.addMethod(methodCoverage);
+ }
+ }
+ };
+ }
+
+ // Nothing to do here:
+
+ public void visitTotalProbeCount(final int count) {
+ }
+
+ public AnnotationVisitor visitAnnotation(final String desc,
+ final boolean visible) {
+ return null;
+ }
+
+ public void visitAttribute(final Attribute attr) {
+ }
+
+ public FieldVisitor visitField(final int access, final String name,
+ final String desc, final String signature, final Object value) {
+ return null;
+ }
+
+ public void visitInnerClass(final String name, final String outerName,
+ final String innerName, final int access) {
+ }
+
+ public void visitOuterClass(final String owner, final String name,
+ final String desc) {
+ }
+
+ public void visitEnd() {
+ }
+
+}
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
new file mode 100644
index 00000000..847d906d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ContentTypeDetector.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.
+ *
+ * @author Marc R. Hoffmann
+ * @version $qualified.bundle.version$
+ */
+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/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
new file mode 100644
index 00000000..3cf0ce24
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.List;
+
+import org.jacoco.core.analysis.CounterImpl;
+import org.jacoco.core.analysis.ICounter;
+import org.jacoco.core.analysis.MethodCoverage;
+import org.jacoco.core.internal.flow.IMethodProbesVisitor;
+import org.jacoco.core.internal.flow.Instruction;
+import org.jacoco.core.internal.flow.LabelInfo;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Label;
+
+/**
+ * A {@link IMethodProbesVisitor} that analyzes which statements and branches of
+ * a method has been executed based on given probe data.
+ *
+ * @author Marc R. Hoffmann
+ * @version $qualified.bundle.version$
+ */
+public class MethodAnalyzer implements IMethodProbesVisitor {
+
+ private final boolean[] executionData;
+
+ private final MethodCoverage coverage;
+
+ private int currentLine = MethodCoverage.UNKNOWN_LINE;
+
+ private Label currentLabel = null;
+
+ /** List of all analyzed instructions */
+ private final List<Instruction> instructions = new ArrayList<Instruction>();
+
+ /** List of all predecessors of covered probes */
+ private final List<Instruction> coveredProbes = new ArrayList<Instruction>();
+
+ /** List of all jumps encountered */
+ private final List<Jump> jumps = new ArrayList<Jump>();
+
+ /** Last instruction in byte code sequence */
+ private Instruction lastInsn;
+
+ /**
+ * New Method analyzer for the given probe data.
+ *
+ * @param name
+ * method name
+ * @param desc
+ * description of the method
+ * @param signature
+ * optional parameterized signature
+ *
+ * @param executionData
+ * recorded probe date of the containing class or
+ * <code>null</code> if the class is not executed at all
+ */
+ public MethodAnalyzer(final String name, final String desc,
+ final String signature, final boolean[] executionData) {
+ this.executionData = executionData;
+ this.coverage = new MethodCoverage(name, desc, signature);
+ }
+
+ /**
+ * Returns the coverage data for this method after this visitor has been
+ * processed.
+ *
+ * @return coverage data for this method
+ */
+ public MethodCoverage getCoverage() {
+ return coverage;
+ }
+
+ public void visitLabel(final Label label) {
+ currentLabel = label;
+ if (!LabelInfo.isSuccessor(label)) {
+ lastInsn = null;
+ }
+ }
+
+ public void visitLineNumber(final int line, final Label start) {
+ currentLine = line;
+ }
+
+ private void visitInsn() {
+ final Instruction insn = new Instruction(currentLine);
+ instructions.add(insn);
+ if (lastInsn != null) {
+ insn.setPredecessor(lastInsn);
+ }
+ if (currentLabel != null) {
+ LabelInfo.setInstruction(currentLabel, insn);
+ currentLabel = null;
+ }
+ lastInsn = insn;
+ }
+
+ public void visitInsn(final int opcode) {
+ visitInsn();
+ }
+
+ public void visitIntInsn(final int opcode, final int operand) {
+ visitInsn();
+ }
+
+ public void visitVarInsn(final int opcode, final int var) {
+ visitInsn();
+ }
+
+ public void visitTypeInsn(final int opcode, final String type) {
+ visitInsn();
+ }
+
+ public void visitFieldInsn(final int opcode, final String owner,
+ final String name, final String desc) {
+ visitInsn();
+ }
+
+ public void visitMethodInsn(final int opcode, final String owner,
+ final String name, final String desc) {
+ visitInsn();
+ }
+
+ public void visitJumpInsn(final int opcode, final Label label) {
+ visitInsn();
+ jumps.add(new Jump(lastInsn, label));
+ }
+
+ public void visitLdcInsn(final Object cst) {
+ visitInsn();
+ }
+
+ public void visitIincInsn(final int var, final int increment) {
+ visitInsn();
+ }
+
+ 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) {
+ visitInsn();
+ LabelInfo.resetDone(labels);
+ jumps.add(new Jump(lastInsn, dflt));
+ LabelInfo.setDone(dflt);
+ for (final Label l : labels) {
+ if (!LabelInfo.isDone(l)) {
+ jumps.add(new Jump(lastInsn, l));
+ LabelInfo.setDone(l);
+ }
+ }
+ }
+
+ public void visitMultiANewArrayInsn(final String desc, final int dims) {
+ visitInsn();
+ }
+
+ public void visitTryCatchBlock(final Label start, final Label end,
+ final Label handler, final String type) {
+ visitInsn();
+ }
+
+ public void visitProbe(final int probeId) {
+ addProbe(lastInsn, probeId);
+ lastInsn = null;
+ }
+
+ public void visitJumpInsnWithProbe(final int opcode, final Label label,
+ final int probeId) {
+ visitInsn();
+ addProbe(lastInsn, probeId);
+ }
+
+ public void visitInsnWithProbe(final int opcode, final int probeId) {
+ visitInsn();
+ addProbe(lastInsn, probeId);
+ }
+
+ public void visitTableSwitchInsnWithProbes(final int min, final int max,
+ final Label dflt, final Label[] labels) {
+ visitSwitchInsnWithProbes(dflt, labels);
+ }
+
+ public void visitLookupSwitchInsnWithProbes(final Label dflt,
+ final int[] keys, final Label[] labels) {
+ visitSwitchInsnWithProbes(dflt, labels);
+ }
+
+ private void visitSwitchInsnWithProbes(final Label dflt,
+ final Label[] labels) {
+ visitInsn();
+ LabelInfo.resetDone(dflt);
+ LabelInfo.resetDone(labels);
+ visitSwitchTarget(dflt);
+ for (final Label l : labels) {
+ visitSwitchTarget(l);
+ }
+ }
+
+ private void visitSwitchTarget(final Label label) {
+ final int id = LabelInfo.getProbeId(label);
+ if (!LabelInfo.isDone(label)) {
+ if (id == LabelInfo.NO_PROBE) {
+ jumps.add(new Jump(lastInsn, label));
+ } else {
+ addProbe(lastInsn, id);
+ }
+ LabelInfo.setDone(label);
+ }
+ }
+
+ public void visitEnd() {
+ // Wire jumps:
+ for (final Jump j : jumps) {
+ LabelInfo.getInstruction(j.target).setPredecessor(j.source);
+ }
+ // Propagate probe values:
+ for (final Instruction p : coveredProbes) {
+ p.setCovered();
+ }
+ // Report result:
+ for (final Instruction i : instructions) {
+ final int total = i.getBranches();
+ final int covered = i.getCoveredBranches();
+ final ICounter instructions = covered == 0 ? CounterImpl.COUNTER_1_0
+ : CounterImpl.COUNTER_0_1;
+ final ICounter branches = total > 1 ? CounterImpl.getInstance(total
+ - covered, covered) : CounterImpl.COUNTER_0_0;
+ coverage.increment(instructions, branches, i.getLine());
+ }
+ }
+
+ // === nothing to do here ===
+
+ public AnnotationVisitor visitAnnotationDefault() {
+ return null;
+ }
+
+ public AnnotationVisitor visitAnnotation(final String desc,
+ final boolean visible) {
+ return null;
+ }
+
+ public AnnotationVisitor visitParameterAnnotation(final int parameter,
+ final String desc, final boolean visible) {
+ return null;
+ }
+
+ public void visitAttribute(final Attribute attr) {
+ }
+
+ public void visitCode() {
+ }
+
+ public void visitFrame(final int type, final int nLocal,
+ final Object[] local, final int nStack, final Object[] stack) {
+ }
+
+ public void visitLocalVariable(final String name, final String desc,
+ final String signature, final Label start, final Label end,
+ final int index) {
+ }
+
+ public void visitMaxs(final int maxStack, final int maxLocals) {
+ }
+
+ private void addProbe(final Instruction predecessor, final int probeId) {
+ predecessor.addBranch();
+ if (executionData != null && executionData[probeId]) {
+ coveredProbes.add(predecessor);
+ }
+ }
+
+ private static class Jump {
+
+ final Instruction source;
+ final Label target;
+
+ Jump(final Instruction source, final Label target) {
+ this.source = source;
+ this.target = target;
+ }
+ }
+
+}