mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
129 lines
5.1 KiB
V
129 lines
5.1 KiB
V
// Copyright (c) 2024 Felipe Pena and Delyan Angelov. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module c
|
|
|
|
import os
|
|
import rand
|
|
import v.ast
|
|
import v.token
|
|
import v.util.version
|
|
import hash
|
|
|
|
// V coverage info
|
|
@[heap]
|
|
struct CoverageInfo {
|
|
mut:
|
|
idx int // index
|
|
points []u64 // code point line nr
|
|
file &ast.File = unsafe { nil }
|
|
fhash string // hash(fpath, build_options), prevents collisions for runs with different options, like `-os windows` or `-gc none`, which may affect the points, due to `$if ... {` etc
|
|
build_options string
|
|
}
|
|
|
|
fn (mut g Gen) write_coverage_point(pos token.Pos) {
|
|
if g.unique_file_path_hash !in g.coverage_files {
|
|
build_options := g.pref.build_options.join(' ')
|
|
fhash := hash.sum64_string('${build_options}:${g.unique_file_path_hash}', 32).hex_full()
|
|
g.coverage_files[g.unique_file_path_hash] = &CoverageInfo{
|
|
points: []
|
|
file: g.file
|
|
fhash: fhash
|
|
build_options: build_options
|
|
}
|
|
}
|
|
if g.fn_decl != unsafe { nil } {
|
|
curr_line := u64(pos.line_nr)
|
|
mut curr_cov := unsafe { g.coverage_files[g.unique_file_path_hash] }
|
|
if curr_line !in curr_cov.points {
|
|
curr_cov.points << curr_line
|
|
}
|
|
stmt_str := g.go_before_last_stmt().trim_space()
|
|
g.empty_line = true
|
|
g.writeln('_v_cov[_v_cov_file_offset_${g.unique_file_path_hash}+${curr_cov.points.len - 1}]++;')
|
|
g.set_current_pos_as_last_stmt_pos()
|
|
g.write(stmt_str)
|
|
}
|
|
}
|
|
|
|
fn (mut g Gen) write_coverage_stats() {
|
|
build_options := g.pref.build_options.join(' ')
|
|
coverage_dir := os.real_path(g.pref.coverage_dir).replace('\\', '/')
|
|
coverage_meta_folder := '${coverage_dir}/meta'
|
|
if !os.exists(coverage_meta_folder) {
|
|
os.mkdir_all(coverage_meta_folder) or {}
|
|
}
|
|
counter_ulid := rand.ulid() // rand.ulid provides a hash+timestamp, so that a collision is extremely unlikely
|
|
g.cov_declarations.writeln('')
|
|
g.cov_declarations.writeln('void vprint_coverage_stats() {')
|
|
g.cov_declarations.writeln('\tchar cov_filename[2048];')
|
|
covdir := cesc(coverage_dir)
|
|
g.cov_declarations.writeln('\tchar *cov_dir = "${covdir}";')
|
|
for _, mut cov in g.coverage_files {
|
|
metadata_coverage_fpath := '${coverage_meta_folder}/${cov.fhash}.json'
|
|
filepath := os.real_path(cov.file.path).replace('\\', '/')
|
|
if os.exists(metadata_coverage_fpath) {
|
|
continue
|
|
}
|
|
mut fmeta := os.create(metadata_coverage_fpath) or { continue }
|
|
fmeta.writeln('{') or { continue }
|
|
jfilepath := jesc(filepath)
|
|
jfhash := jesc(cov.fhash)
|
|
jversion := jesc(version.full_v_version(true))
|
|
jboptions := jesc(cov.build_options)
|
|
fmeta.writeln(' "file": "${jfilepath}", "fhash": "${jfhash}",') or { continue }
|
|
fmeta.writeln(' "v_version": "${jversion}",') or { continue }
|
|
fmeta.writeln(' "build_options": "${jboptions}",') or { continue }
|
|
fmeta.writeln(' "npoints": ${cov.points.len},') or { continue }
|
|
fmeta.write_string(' "points": [ ') or { continue }
|
|
for idx, p in cov.points {
|
|
fmeta.write_string('${p + 1}') or { continue }
|
|
if idx < cov.points.len - 1 {
|
|
fmeta.write_string(',') or { continue }
|
|
}
|
|
}
|
|
fmeta.writeln(' ]') or { continue }
|
|
fmeta.writeln('}') or { continue }
|
|
fmeta.close()
|
|
}
|
|
g.cov_declarations.writeln('\tint secs = 0;')
|
|
g.cov_declarations.writeln('\tint nsecs = 0;')
|
|
g.cov_declarations.writeln('\t#if defined(_WIN32)')
|
|
g.cov_declarations.writeln('\tint ticks_passed = GetTickCount();')
|
|
g.cov_declarations.writeln('\nsecs = ticks_passed / 1000;')
|
|
g.cov_declarations.writeln('\nnsecs = (ticks_passed % 1000) * 1000000;')
|
|
g.cov_declarations.writeln('\t#endif')
|
|
g.cov_declarations.writeln('\t#if !defined(_WIN32)')
|
|
g.cov_declarations.writeln('\tstruct timespec ts;')
|
|
g.cov_declarations.writeln('\tclock_gettime(CLOCK_MONOTONIC, &ts);')
|
|
g.cov_declarations.writeln('\tsecs = ts.tv_sec;')
|
|
g.cov_declarations.writeln('\nsecs = ts.tv_nsec;')
|
|
g.cov_declarations.writeln('\t#endif')
|
|
g.cov_declarations.writeln('\tsnprintf(cov_filename, sizeof(cov_filename), "%s/vcounters_${counter_ulid}.%07ld.%09ld.csv", cov_dir, secs, nsecs);')
|
|
g.cov_declarations.writeln('\tFILE *fp = fopen(cov_filename, "wb+");')
|
|
cprefpath := cesc(os.real_path(g.pref.path))
|
|
cboptions := cesc(build_options)
|
|
g.cov_declarations.writeln('\tfprintf(fp, "# path: ${cprefpath}\\n");')
|
|
g.cov_declarations.writeln('\tfprintf(fp, "# build_options: ${cboptions}\\n");')
|
|
g.cov_declarations.writeln('\tfprintf(fp, "meta,point,hits\\n");')
|
|
for k, cov in g.coverage_files {
|
|
nr_points := cov.points.len
|
|
g.cov_declarations.writeln('\t{')
|
|
g.cov_declarations.writeln('\t\tfor (${ast.int_type_name} i = 0; i < ${nr_points}; ++i) {')
|
|
g.cov_declarations.writeln('\t\t\tif (_v_cov[_v_cov_file_offset_${k}+i]) {')
|
|
g.cov_declarations.writeln("\t\t\t\tfprintf(fp, \"%s,%d,%ld\\n\", \"${cov.fhash}\", i, _v_cov[_v_cov_file_offset_${k}+i]);")
|
|
g.cov_declarations.writeln('\t\t\t}')
|
|
g.cov_declarations.writeln('\t\t}')
|
|
g.cov_declarations.writeln('\t}')
|
|
}
|
|
g.cov_declarations.writeln('\tfclose(fp);')
|
|
g.cov_declarations.writeln('}')
|
|
}
|
|
|
|
fn cesc(s string) string {
|
|
return cescape_nonascii(cestring(s))
|
|
}
|
|
|
|
fn jesc(s string) string {
|
|
return escape_quotes(s)
|
|
}
|