comparison druntime/src/compiler/dmd/cover.d @ 759:d3eb054172f9

Added copy of druntime from DMD 2.020 modified for LDC.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:52:37 +0100
parents
children
comparison
equal deleted inserted replaced
758:f04dde6e882c 759:d3eb054172f9
1 /**
2 * Code coverage analyzer.
3 *
4 * Bugs:
5 * $(UL
6 * $(LI the execution counters are 32 bits in size, and can overflow)
7 * $(LI inline asm statements are not counted)
8 * )
9 *
10 * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. All rights reserved.
11 * License: BSD style: $(LICENSE)
12 * Authors: Walter Bright, Sean Kelly
13 */
14
15 module rt.cover;
16
17 private
18 {
19 version( Windows )
20 import sys.windows.windows;
21 else version( Posix )
22 {
23 import stdc.posix.fcntl;
24 import stdc.posix.unistd;
25 }
26 import core.bitmanip;
27 import stdc.stdio;
28 import util.utf;
29
30 struct BitArray
31 {
32 size_t len;
33 uint* ptr;
34
35 bool opIndex( size_t i )
36 in
37 {
38 assert( i < len );
39 }
40 body
41 {
42 return cast(bool) bt( ptr, i );
43 }
44 }
45
46 struct Cover
47 {
48 char[] filename;
49 BitArray valid;
50 uint[] data;
51 }
52
53 Cover[] gdata;
54 char[] srcpath;
55 char[] dstpath;
56 bool merge;
57 }
58
59
60 /**
61 * Set path to where source files are located.
62 *
63 * Params:
64 * pathname = The new path name.
65 */
66 extern (C) void dmd_coverSourcePath( char[] pathname )
67 {
68 srcpath = pathname;
69 }
70
71
72 /**
73 * Set path to where listing files are to be written.
74 *
75 * Params:
76 * pathname = The new path name.
77 */
78 extern (C) void dmd_coverDestPath( char[] pathname )
79 {
80 dstpath = pathname;
81 }
82
83
84 /**
85 * Set merge mode.
86 *
87 * Params:
88 * flag = true means new data is summed with existing data in the listing
89 * file; false means a new listing file is always created.
90 */
91 extern (C) void dmd_coverSetMerge( bool flag )
92 {
93 merge = flag;
94 }
95
96
97 /**
98 * The coverage callback.
99 *
100 * Params:
101 * filename = The name of the coverage file.
102 * valid = ???
103 * data = ???
104 */
105 extern (C) void _d_cover_register( char[] filename, BitArray valid, uint[] data )
106 {
107 Cover c;
108
109 c.filename = filename;
110 c.valid = valid;
111 c.data = data;
112 gdata ~= c;
113 }
114
115
116 static ~this()
117 {
118 const NUMLINES = 16384 - 1;
119 const NUMCHARS = 16384 * 16 - 1;
120
121 char[] srcbuf = new char[NUMCHARS];
122 char[][] srclines = new char[][NUMLINES];
123 char[] lstbuf = new char[NUMCHARS];
124 char[][] lstlines = new char[][NUMLINES];
125
126 foreach( Cover c; gdata )
127 {
128 if( !readFile( appendFN( srcpath, c.filename ), srcbuf ) )
129 continue;
130 splitLines( srcbuf, srclines );
131
132 if( merge )
133 {
134 if( !readFile( c.filename ~ ".lst", lstbuf ) )
135 break;
136 splitLines( lstbuf, lstlines );
137
138 for( size_t i = 0; i < lstlines.length; ++i )
139 {
140 if( i >= c.data.length )
141 break;
142
143 int count = 0;
144
145 foreach( char c2; lstlines[i] )
146 {
147 switch( c2 )
148 {
149 case ' ':
150 continue;
151 case '0': case '1': case '2': case '3': case '4':
152 case '5': case '6': case '7': case '8': case '9':
153 count = count * 10 + c2 - '0';
154 continue;
155 default:
156 break;
157 }
158 }
159 c.data[i] += count;
160 }
161 }
162
163 FILE* flst = fopen( (c.filename ~ ".lst").ptr, "wb" );
164
165 if( !flst )
166 continue; //throw new Exception( "Error opening file for write: " ~ lstfn );
167
168 uint nno;
169 uint nyes;
170
171 for( int i = 0; i < c.data.length; i++ )
172 {
173 if( i < srclines.length )
174 {
175 uint n = c.data[i];
176 char[] line = srclines[i];
177
178 line = expandTabs( line );
179
180 if( n == 0 )
181 {
182 if( c.valid[i] )
183 {
184 nno++;
185 fprintf( flst, "0000000|%.*s\n", line );
186 }
187 else
188 {
189 fprintf( flst, " |%.*s\n", line );
190 }
191 }
192 else
193 {
194 nyes++;
195 fprintf( flst, "%7u|%.*s\n", n, line );
196 }
197 }
198 }
199 if( nyes + nno ) // no divide by 0 bugs
200 {
201 fprintf( flst, "%.*s is %d%% covered\n", c.filename, ( nyes * 100 ) / ( nyes + nno ) );
202 }
203 fclose( flst );
204 }
205 }
206
207
208 char[] appendFN( char[] path, char[] name )
209 {
210 version( Windows )
211 const char sep = '\\';
212 else
213 const char sep = '/';
214
215 char[] dest = path;
216
217 if( dest && dest[$ - 1] != sep )
218 dest ~= sep;
219 dest ~= name;
220 return dest;
221 }
222
223
224 bool readFile( char[] name, inout char[] buf )
225 {
226 version( Windows )
227 {
228 auto wnamez = toUTF16z( name );
229 HANDLE file = CreateFileW( wnamez,
230 GENERIC_READ,
231 FILE_SHARE_READ,
232 null,
233 OPEN_EXISTING,
234 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
235 cast(HANDLE) null );
236
237 delete wnamez;
238 if( file == INVALID_HANDLE_VALUE )
239 return false;
240 scope( exit ) CloseHandle( file );
241
242 DWORD num = 0;
243 DWORD pos = 0;
244
245 buf.length = 4096;
246 while( true )
247 {
248 if( !ReadFile( file, &buf[pos], cast(DWORD)( buf.length - pos ), &num, null ) )
249 return false;
250 if( !num )
251 break;
252 pos += num;
253 buf.length = pos * 2;
254 }
255 buf.length = pos;
256 return true;
257 }
258 else version( linux )
259 {
260 char[] namez = new char[name.length + 1];
261 namez[0 .. name.length] = name;
262 namez[$ - 1] = 0;
263 int file = open( namez.ptr, O_RDONLY );
264
265 delete namez;
266 if( file == -1 )
267 return false;
268 scope( exit ) close( file );
269
270 int num = 0;
271 uint pos = 0;
272
273 buf.length = 4096;
274 while( true )
275 {
276 num = read( file, &buf[pos], cast(uint)( buf.length - pos ) );
277 if( num == -1 )
278 return false;
279 if( !num )
280 break;
281 pos += num;
282 buf.length = pos * 2;
283 }
284 buf.length = pos;
285 return true;
286 }
287 }
288
289
290 void splitLines( char[] buf, inout char[][] lines )
291 {
292 size_t beg = 0,
293 pos = 0;
294
295 lines.length = 0;
296 for( ; pos < buf.length; ++pos )
297 {
298 char c = buf[pos];
299
300 switch( buf[pos] )
301 {
302 case '\r':
303 case '\n':
304 lines ~= buf[beg .. pos];
305 beg = pos + 1;
306 if( buf[pos] == '\r' && pos < buf.length - 1 && buf[pos + 1] == '\n' )
307 ++pos, ++beg;
308 default:
309 continue;
310 }
311 }
312 if( beg != pos )
313 {
314 lines ~= buf[beg .. pos];
315 }
316 }
317
318
319 char[] expandTabs( char[] string, int tabsize = 8 )
320 {
321 const dchar LS = '\u2028'; // UTF line separator
322 const dchar PS = '\u2029'; // UTF paragraph separator
323
324 bool changes = false;
325 char[] result = string;
326 int column;
327 int nspaces;
328
329 foreach( size_t i, dchar c; string )
330 {
331 switch( c )
332 {
333 case '\t':
334 nspaces = tabsize - (column % tabsize);
335 if( !changes )
336 {
337 changes = true;
338 result = null;
339 result.length = string.length + nspaces - 1;
340 result.length = i + nspaces;
341 result[0 .. i] = string[0 .. i];
342 result[i .. i + nspaces] = ' ';
343 }
344 else
345 { int j = result.length;
346 result.length = j + nspaces;
347 result[j .. j + nspaces] = ' ';
348 }
349 column += nspaces;
350 break;
351
352 case '\r':
353 case '\n':
354 case PS:
355 case LS:
356 column = 0;
357 goto L1;
358
359 default:
360 column++;
361 L1:
362 if (changes)
363 {
364 if (c <= 0x7F)
365 result ~= c;
366 else
367 encode(result, c);
368 }
369 break;
370 }
371 }
372 return result;
373 }