diff options
author | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2011-01-08 20:09:23 +0000 |
---|---|---|
committer | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2011-01-08 20:09:23 +0000 |
commit | ebad55ad1f8f33ad500dbc4f7091e51731f6c597 (patch) | |
tree | ca19cd2e2d463353ca7348e38810670ed9fd1b72 /org.jacoco.core/src/org/jacoco/core/internal/analysis | |
parent | 805be218b948d40ba5c6796ff98d3ab108034727 (diff) | |
download | jacoco-ebad55ad1f8f33ad500dbc4f7091e51731f6c597.tar.gz |
Trac 133: Remove internal classes from API package.
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal/analysis')
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; + } + } + +} |