blob: f3423cfaf037250f7c688d71c2db3a64e0936d8f [file] [log] [blame]
/* 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 <clinit>
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
// ----------------------------------------------------------------------------