1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.cli.internal.commands; 13 14 import java.io.File; 15 import java.io.IOException; 16 import java.io.PrintWriter; 17 import java.util.ArrayList; 18 import java.util.Iterator; 19 import java.util.List; 20 21 import org.jacoco.cli.internal.Command; 22 import org.jacoco.core.analysis.Analyzer; 23 import org.jacoco.core.analysis.IClassCoverage; 24 import org.jacoco.core.analysis.ICounter; 25 import org.jacoco.core.analysis.ICoverageNode; 26 import org.jacoco.core.analysis.ICoverageVisitor; 27 import org.jacoco.core.analysis.ILine; 28 import org.jacoco.core.analysis.IMethodCoverage; 29 import org.jacoco.core.data.ExecutionDataStore; 30 import org.kohsuke.args4j.Argument; 31 import org.kohsuke.args4j.Option; 32 33 /** 34 * The <code>classinfo</code> command. 35 */ 36 public class ClassInfo extends Command { 37 38 @Argument(usage = "location of Java class files", metaVar = "<classlocations>") 39 List<File> classfiles = new ArrayList<File>(); 40 41 @Option(name = "--verbose", usage = "show method and line number details") 42 boolean verbose = false; 43 44 @Override 45 public String description() { 46 return "Print information about Java class files at the provided location."; 47 } 48 49 @Override 50 public int execute(final PrintWriter out, final PrintWriter err) 51 throws IOException { 52 if (classfiles.isEmpty()) { 53 out.println("[WARN] No class files provided."); 54 } else { 55 final Analyzer analyzer = new Analyzer(new ExecutionDataStore(), 56 new Printer(out)); 57 for (final File file : classfiles) { 58 analyzer.analyzeAll(file); 59 } 60 } 61 return 0; 62 } 63 64 private class Printer implements ICoverageVisitor { 65 66 private final PrintWriter out; 67 68 Printer(final PrintWriter out) { 69 this.out = out; 70 out.println(" INST BRAN LINE METH CXTY ELEMENT"); 71 } 72 73 public void visitCoverage(final IClassCoverage coverage) { 74 final String desc = String.format("class 0x%016x %s", 75 Long.valueOf(coverage.getId()), coverage.getName()); 76 printDetails(desc, coverage); 77 if (verbose) { 78 for (final Iterator<IMethodCoverage> i = coverage.getMethods() 79 .iterator(); i.hasNext();) { 80 printMethod(i.next(), i.hasNext()); 81 } 82 } 83 } 84 85 private void printMethod(final IMethodCoverage method, 86 final boolean more) { 87 final String desc = String.format("+- method %s%s", 88 method.getName(), method.getDesc()); 89 printDetails(desc, method); 90 for (int nr = method.getFirstLine(); nr <= method 91 .getLastLine(); nr++) { 92 printLine(method.getLine(nr), nr, more ? "| " : " "); 93 } 94 } 95 96 private void printLine(final ILine line, final int nr, 97 final String indent) { 98 if (line.getStatus() != ICounter.EMPTY) { 99 out.printf("%6s %6s %s +- line %s%n", 100 total(line.getInstructionCounter()), 101 total(line.getBranchCounter()), indent, 102 Integer.valueOf(nr)); 103 } 104 } 105 106 private void printDetails(final String description, 107 final ICoverageNode coverage) { 108 out.printf("%6s %6s %6s %6s %6s %s%n", 109 total(coverage.getInstructionCounter()), 110 total(coverage.getBranchCounter()), 111 total(coverage.getLineCounter()), 112 total(coverage.getMethodCounter()), 113 total(coverage.getComplexityCounter()), description); 114 } 115 116 private String total(final ICounter counter) { 117 return String.valueOf(counter.getTotalCount()); 118 } 119 120 } 121 122 } 123