mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-03 07:54:40 +08:00
Count each statement once in coverage however often it lowers (#1366)
This commit is contained in:
@@ -4598,8 +4598,7 @@ function lowerStaticFieldInitsInner(lowerer: Lowerer, info: ClassInfo): IrStmt[]
|
||||
continue;
|
||||
}
|
||||
const f = item.f;
|
||||
lowerer.stats.statementsTotal++;
|
||||
lowerer.bumpFileStat(locOf(f.initializer).file, "total");
|
||||
lowerer.countStatement(f.initializer, locOf(f.initializer).file);
|
||||
const diagsBefore = lowerer.diags.length;
|
||||
const sinkMark = lowerer.diagSinkMark();
|
||||
try {
|
||||
@@ -4635,8 +4634,7 @@ function lowerStaticFieldInitsInner(lowerer: Lowerer, info: ClassInfo): IrStmt[]
|
||||
out.push({ kind: "assign", localId: f.globalId, value, loc: locOf(f.initializer) });
|
||||
} catch (e) {
|
||||
if (!(e instanceof PoisonError)) throw e;
|
||||
lowerer.stats.statementsFailed++;
|
||||
lowerer.bumpFileStat(locOf(f.initializer).file, "failed");
|
||||
lowerer.countStatementFailed(f.initializer, locOf(f.initializer).file);
|
||||
if (isJsSourceFile(f.initializer.getSourceFile())) {
|
||||
const fence =
|
||||
lowerer.diagSink === null
|
||||
@@ -7764,8 +7762,7 @@ export function fieldInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrL
|
||||
});
|
||||
}
|
||||
if (!f.initializer) continue;
|
||||
lowerer.stats.statementsTotal++;
|
||||
lowerer.bumpFileStat(locOf(f.initializer).file, "total");
|
||||
lowerer.countStatement(f.initializer, locOf(f.initializer).file);
|
||||
const diagsBefore = lowerer.diags.length;
|
||||
const sinkMark = lowerer.diagSinkMark();
|
||||
try {
|
||||
@@ -7780,8 +7777,7 @@ export function fieldInitStmts(lowerer: Lowerer, info: ClassInfo, thisLocal: IrL
|
||||
});
|
||||
} catch (e) {
|
||||
if (!(e instanceof PoisonError)) throw e;
|
||||
lowerer.stats.statementsFailed++;
|
||||
lowerer.bumpFileStat(locOf(f.initializer).file, "failed");
|
||||
lowerer.countStatementFailed(f.initializer, locOf(f.initializer).file);
|
||||
if (isJsSourceFile(f.initializer.getSourceFile())) {
|
||||
const fence =
|
||||
lowerer.diagSink === null
|
||||
|
||||
@@ -689,10 +689,7 @@ export function lowerStmts(lowerer: Lowerer, stmts: readonly ts.Statement[]): Ir
|
||||
entry.index = i;
|
||||
if (unreachable && skipsWhenUnreachable(stmt)) continue;
|
||||
if (inFunction && isAbruptStatement(stmt)) unreachable = true;
|
||||
if (!lowerer.suppressStats) {
|
||||
lowerer.stats.statementsTotal++;
|
||||
if (sf !== undefined) lowerer.bumpFileStat(sf.fileName, "total");
|
||||
}
|
||||
if (!lowerer.suppressStats) lowerer.countStatement(stmt, sf?.fileName);
|
||||
const diagsBefore = lowerer.diags.length;
|
||||
const sinkMark = lowerer.diagSinkMark();
|
||||
try {
|
||||
@@ -757,10 +754,7 @@ export function lowerStmts(lowerer: Lowerer, stmts: readonly ts.Statement[]): Ir
|
||||
} else if (!(e instanceof PoisonError)) {
|
||||
throw e;
|
||||
}
|
||||
if (!lowerer.suppressStats) {
|
||||
lowerer.stats.statementsFailed++;
|
||||
if (sf !== undefined) lowerer.bumpFileStat(sf.fileName, "failed");
|
||||
}
|
||||
if (!lowerer.suppressStats) lowerer.countStatementFailed(stmt, sf?.fileName);
|
||||
lowerer.noteBlockedBindings(stmt);
|
||||
// The runtime-fence conversion (JS sources, direct diagnostics
|
||||
// only — a capture wrapper in force means collection owns the
|
||||
|
||||
@@ -2925,6 +2925,32 @@ export class Lowerer {
|
||||
* pass skips it (attribution describes the build). */
|
||||
readonly statsByFile = new Map<string, { total: number; failed: number }>();
|
||||
|
||||
/** Statements and field initializers already in the coverage totals, and
|
||||
* those already counted as failed. Speculative lowering can lower one
|
||||
* function body several times: each receiver probe of
|
||||
* `(function () { ... }).call(this)` lowers it. A source statement counts
|
||||
* once however many times it lowers. */
|
||||
private readonly countedStatements = new Set<ts.Node>();
|
||||
private readonly failedStatements = new Set<ts.Node>();
|
||||
|
||||
/** Adds `node` to the coverage totals unless it is already counted (the
|
||||
* caller checks suppressStats). */
|
||||
countStatement(node: ts.Node, file: string | undefined): void {
|
||||
if (this.countedStatements.has(node)) return;
|
||||
this.countedStatements.add(node);
|
||||
this.stats.statementsTotal++;
|
||||
if (file !== undefined) this.bumpFileStat(file, "total");
|
||||
}
|
||||
|
||||
/** Counts `node` as failed unless it already is (the caller checks
|
||||
* suppressStats). */
|
||||
countStatementFailed(node: ts.Node, file: string | undefined): void {
|
||||
if (this.failedStatements.has(node)) return;
|
||||
this.failedStatements.add(node);
|
||||
this.stats.statementsFailed++;
|
||||
if (file !== undefined) this.bumpFileStat(file, "failed");
|
||||
}
|
||||
|
||||
/** Bumps the per-file attribution counter (no-op unless provenance is
|
||||
* active and this is the emit/discovery lane — mirror the CALLER's
|
||||
* suppressStats guard, this method only gates remainder). */
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
// and `typeof module.exports` compile; a statement with no static lowering
|
||||
// (here `module.exports` passed as a value in the class base) compiles to
|
||||
// its runtime fence instead of vanishing. It never runs, so the binary
|
||||
// matches Node. Coverage counts that one fenced statement once: the class
|
||||
// base's body is lowered once.
|
||||
// matches Node.
|
||||
const verbose = process.argv.length > 99;
|
||||
(function () {
|
||||
var root = this;
|
||||
|
||||
Reference in New Issue
Block a user