/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. * * This program and the accompanying materials are made available under * the terms of the Common Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/cpl-v10.html * * $Id: ClassItem.java,v 1.1.1.1.2.1 2004/06/20 20:07:22 vlad_r Exp $ */ package com.vladium.emma.report; import java.util.Iterator; import com.vladium.util.IntObjectMap; import com.vladium.util.asserts.$assert; import com.vladium.emma.data.ClassDescriptor; import com.vladium.emma.data.MethodDescriptor; // ---------------------------------------------------------------------------- /** * @author Vlad Roubtsov, (C) 2003 */ public final class ClassItem extends Item { // public: ................................................................ public ClassItem (final IItem parent, final ClassDescriptor cls, final boolean [][] coverage) { super (parent); m_cls = cls; m_coverage = coverage; } public String getName () { return m_cls.getName (); } public String getSrcFileName () { return m_cls.getSrcFileName (); } // TODO: SrcFileItem could benefit from this method for its own getFirstLine() public int getFirstLine () { // TODO: state validation if (m_firstLine == 0) { final MethodDescriptor [] methods = m_cls.getMethods (); int firstLine = Integer.MAX_VALUE; for (int m = 0, mLimit = methods.length; m < mLimit; ++ m) { final int mFirstLine = methods [m].getFirstLine (); if ((mFirstLine > 0) && (mFirstLine < firstLine)) firstLine = mFirstLine; } m_firstLine = firstLine; return firstLine; } return m_firstLine; } public ClassDescriptor getClassDescriptor () { return m_cls; } public boolean [][] getCoverage () { return m_coverage; } public boolean loaded () { return m_coverage != null; } public int getAggregate (final int type) { final int [] aggregates = m_aggregates; int value = aggregates [type]; if (value < 0) { switch (type) { case COVERAGE_CLASS_COUNT: case TOTAL_CLASS_COUNT: { aggregates [TOTAL_CLASS_COUNT] = 1; aggregates [COVERAGE_CLASS_COUNT] = m_coverage != null ? 1 : 0; return aggregates [type]; } //break; case COVERAGE_LINE_COUNT: case TOTAL_LINE_COUNT: case COVERAGE_LINE_INSTR: { // line aggregate types are special when used on clsfile items: // unlike all others, they do not simply add up when the line // info is available; instead, lines from all methods belonging // to the same clsfile parent are set-merged final boolean [][] ccoverage = m_coverage; // this can be null final IntObjectMap /* line -> int[2] */ cldata = new IntObjectMap (); final MethodDescriptor [] methoddescs = m_cls.getMethods (); for (Iterator methods = getChildren (); methods.hasNext (); ) { final MethodItem method = (MethodItem) methods.next (); final int methodID = method.getID (); final boolean [] mcoverage = ccoverage == null ? null : ccoverage [methodID]; final MethodDescriptor methoddesc = methoddescs [methodID]; final int [] mbsizes = methoddesc.getBlockSizes (); final IntObjectMap mlineMap = methoddesc.getLineMap (); if ($assert.ENABLED) $assert.ASSERT (mlineMap != null); final int [] mlines = mlineMap.keys (); for (int ml = 0, mlLimit = mlines.length; ml < mlLimit; ++ ml) { final int mline = mlines [ml]; int [] data = (int []) cldata.get (mline); if (data == null) { data = new int [4]; // { totalcount, totalinstr, coveragecount, coverageinstr } cldata.put (mline, data); } final int [] lblocks = (int []) mlineMap.get (mline); final int bCount = lblocks.length; data [0] += bCount; for (int bID = 0; bID < bCount; ++ bID) { final int block = lblocks [bID]; final boolean bcovered = mcoverage != null && mcoverage [block]; final int instr = mbsizes [block]; data [1] += instr; if (bcovered) { ++ data [2]; data [3] += instr; } } } } aggregates [TOTAL_LINE_COUNT] = cldata.size (); int coverageLineCount = 0; int coverageLineInstr = 0; final int [] clines = cldata.keys (); for (int cl = 0, clLimit = clines.length; cl < clLimit; ++ cl) { final int cline = clines [cl]; final int [] data = (int []) cldata.get (cline); final int ltotalCount = data [0]; final int ltotalInstr = data [1]; final int lcoverageCount = data [2]; final int lcoverageInstr = data [3]; if (lcoverageInstr > 0) { coverageLineCount += (PRECISION * lcoverageCount) / ltotalCount; coverageLineInstr += (PRECISION * lcoverageInstr) / ltotalInstr; } } aggregates [COVERAGE_LINE_COUNT] = coverageLineCount; aggregates [COVERAGE_LINE_INSTR] = coverageLineInstr; return aggregates [type]; } //break; default: return super.getAggregate (type); } } return value; } public void accept (final IItemVisitor visitor, final Object ctx) { visitor.visit (this, ctx); } public final IItemMetadata getMetadata () { return METADATA; } public static IItemMetadata getTypeMetadata () { return METADATA; } // protected: ............................................................. // package: ............................................................... final ClassDescriptor m_cls; final boolean [][] m_coverage; // private: ............................................................... private int m_firstLine; private static final Item.ItemMetadata METADATA; // set in static { METADATA = new Item.ItemMetadata (IItemMetadata.TYPE_ID_CLASS, "class", 1 << IItemAttribute.ATTRIBUTE_NAME_ID | 1 << IItemAttribute.ATTRIBUTE_CLASS_COVERAGE_ID | 1 << IItemAttribute.ATTRIBUTE_METHOD_COVERAGE_ID | 1 << IItemAttribute.ATTRIBUTE_BLOCK_COVERAGE_ID | 1 << IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID); } } // end of class // ----------------------------------------------------------------------------