1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2 *
3 * This program and the accompanying materials are made available under
4 * the terms of the Common Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/cpl-v10.html
6 *
7 * $Id: ClassItem.java,v 1.1.1.1.2.1 2004/06/20 20:07:22 vlad_r Exp $
8 */
9package com.vladium.emma.report;
10
11import java.util.Iterator;
12
13import com.vladium.util.IntObjectMap;
14import com.vladium.util.asserts.$assert;
15import com.vladium.emma.data.ClassDescriptor;
16import com.vladium.emma.data.MethodDescriptor;
17
18// ----------------------------------------------------------------------------
19/**
20 * @author Vlad Roubtsov, (C) 2003
21 */
22public
23final class ClassItem extends Item
24{
25    // public: ................................................................
26
27    public ClassItem (final IItem parent, final ClassDescriptor cls, final boolean [][] coverage)
28    {
29        super (parent);
30
31        m_cls = cls;
32        m_coverage = coverage;
33    }
34
35    public String getName ()
36    {
37        return m_cls.getName ();
38    }
39
40    public String getSrcFileName ()
41    {
42        return m_cls.getSrcFileName ();
43    }
44
45    // TODO: SrcFileItem could benefit from this method for its own getFirstLine()
46    public int getFirstLine ()
47    {
48        // TODO: state validation
49
50        if (m_firstLine == 0)
51        {
52            final MethodDescriptor [] methods = m_cls.getMethods ();
53
54            int firstLine = Integer.MAX_VALUE;
55            for (int m = 0, mLimit = methods.length; m < mLimit; ++ m)
56            {
57                final int mFirstLine = methods [m].getFirstLine ();
58                if ((mFirstLine > 0) && (mFirstLine < firstLine))
59                    firstLine = mFirstLine;
60            }
61
62            m_firstLine = firstLine;
63            return firstLine;
64        }
65
66        return m_firstLine;
67    }
68
69    public ClassDescriptor getClassDescriptor ()
70    {
71        return m_cls;
72    }
73
74    public boolean [][] getCoverage ()
75    {
76        return m_coverage;
77    }
78
79    public boolean loaded ()
80    {
81        return m_coverage != null;
82    }
83
84    public int getAggregate (final int type)
85    {
86        final int [] aggregates = m_aggregates;
87
88        int value = aggregates [type];
89
90        if (value < 0)
91        {
92            switch (type)
93            {
94                case COVERAGE_CLASS_COUNT:
95                case    TOTAL_CLASS_COUNT:
96                {
97                    aggregates [TOTAL_CLASS_COUNT] = 1;
98                    aggregates [COVERAGE_CLASS_COUNT] = m_coverage != null ? 1 : 0;
99
100                    return aggregates [type];
101                }
102                //break;
103
104
105                case COVERAGE_LINE_COUNT:
106                case    TOTAL_LINE_COUNT:
107
108                case COVERAGE_LINE_INSTR:
109                {
110                    // line aggregate types are special when used on clsfile items:
111                    // unlike all others, they do not simply add up when the line
112                    // info is available; instead, lines from all methods belonging
113                    // to the same clsfile parent are set-merged
114
115                    final boolean [][] ccoverage = m_coverage; // this can be null
116
117                    final IntObjectMap /* line -> int[2] */ cldata = new IntObjectMap ();
118                    final MethodDescriptor [] methoddescs = m_cls.getMethods ();
119
120                    for (Iterator methods = getChildren (); methods.hasNext (); )
121                    {
122                        final MethodItem method = (MethodItem) methods.next ();
123                        final int methodID = method.getID ();
124
125                        final boolean [] mcoverage = ccoverage == null ? null : ccoverage [methodID];
126
127                        final MethodDescriptor methoddesc = methoddescs [methodID];
128                        final int [] mbsizes = methoddesc.getBlockSizes ();
129                        final IntObjectMap mlineMap = methoddesc.getLineMap ();
130                        if ($assert.ENABLED) $assert.ASSERT (mlineMap != null);
131
132
133                        final int [] mlines = mlineMap.keys ();
134                        for (int ml = 0, mlLimit = mlines.length; ml < mlLimit; ++ ml)
135                        {
136                            final int mline = mlines [ml];
137
138                            int [] data = (int []) cldata.get (mline);
139                            if (data == null)
140                            {
141                                data = new int [4]; // { totalcount, totalinstr, coveragecount, coverageinstr }
142                                cldata.put (mline, data);
143                            }
144
145                            final int [] lblocks = (int []) mlineMap.get (mline);
146
147                            final int bCount = lblocks.length;
148                            data [0] += bCount;
149
150                            for (int bID = 0; bID < bCount; ++ bID)
151                            {
152                                final int block = lblocks [bID];
153
154                                final boolean bcovered = mcoverage != null && mcoverage [block];
155                                final int instr = mbsizes [block];
156
157                                data [1] += instr;
158                                if (bcovered)
159                                {
160                                    ++ data [2];
161                                    data [3] += instr;
162                                }
163                            }
164                        }
165                    }
166
167                    aggregates [TOTAL_LINE_COUNT] = cldata.size ();
168
169                    int coverageLineCount = 0;
170                    int coverageLineInstr = 0;
171
172                    final int [] clines = cldata.keys ();
173                    for (int cl = 0, clLimit = clines.length; cl < clLimit; ++ cl)
174                    {
175                        final int cline = clines [cl];
176                        final int [] data = (int []) cldata.get (cline);
177
178                        final int ltotalCount = data [0];
179                        final int ltotalInstr = data [1];
180                        final int lcoverageCount = data [2];
181                        final int lcoverageInstr = data [3];
182
183                        if (lcoverageInstr > 0)
184                        {
185                            coverageLineCount += (PRECISION * lcoverageCount) / ltotalCount;
186                            coverageLineInstr += (PRECISION * lcoverageInstr) / ltotalInstr;
187                        }
188                    }
189
190                    aggregates [COVERAGE_LINE_COUNT] = coverageLineCount;
191                    aggregates [COVERAGE_LINE_INSTR] = coverageLineInstr;
192
193                    return aggregates [type];
194                }
195                //break;
196
197
198                default: return super.getAggregate (type);
199            }
200        }
201
202        return value;
203    }
204
205    public void accept (final IItemVisitor visitor, final Object ctx)
206    {
207        visitor.visit (this, ctx);
208    }
209
210    public final IItemMetadata getMetadata ()
211    {
212        return METADATA;
213    }
214
215    public static IItemMetadata getTypeMetadata ()
216    {
217        return METADATA;
218    }
219
220    // protected: .............................................................
221
222    // package: ...............................................................
223
224
225    final ClassDescriptor m_cls;
226    final boolean [][] m_coverage;
227
228    // private: ...............................................................
229
230
231    private int m_firstLine;
232
233    private static final Item.ItemMetadata METADATA; // set in <clinit>
234
235    static
236    {
237        METADATA = new Item.ItemMetadata (IItemMetadata.TYPE_ID_CLASS, "class",
238            1 << IItemAttribute.ATTRIBUTE_NAME_ID |
239            1 << IItemAttribute.ATTRIBUTE_CLASS_COVERAGE_ID |
240            1 << IItemAttribute.ATTRIBUTE_METHOD_COVERAGE_ID |
241            1 << IItemAttribute.ATTRIBUTE_BLOCK_COVERAGE_ID |
242            1 << IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID);
243    }
244
245} // end of class
246// ----------------------------------------------------------------------------