test: audit helper-mediated source reads

This commit is contained in:
Erik 2026-08-18 14:18:00 +02:00
parent dc94b0fe32
commit c5f0fbaaa4
2 changed files with 135 additions and 36 deletions

View file

@ -10,7 +10,7 @@
signals (including same-file helper calls), diagnostic output signals,
high-confidence constant-truth assertions, syntactic self-comparison
candidates, wall-clock waits, environment-variable dependencies, and
source-text reads.
source-text reads, including reads reached through same-file helper calls.
This is a candidate generator, not a semantic proof. In particular, an
output-only candidate can call a failure-capable helper declared in another
@ -192,6 +192,39 @@ function Test-DirectOutputSignal {
return $false
}
function Test-CSharpPathLiteral {
param([Parameter(Mandatory)]$Method)
foreach ($literal in @($Method.DescendantNodes() | Where-Object {
$_.GetType().Name -eq 'LiteralExpressionSyntax'
})) {
if ($literal.Token.ValueText -match '(?i)\.cs') {
return $true
}
}
foreach ($text in @($Method.DescendantNodes() | Where-Object {
$_.GetType().Name -eq 'InterpolatedStringTextSyntax'
})) {
if ($text.TextToken.ValueText -match '(?i)\.cs') {
return $true
}
}
return $false
}
function Test-TextFileRead {
param([Parameter(Mandatory)]$Method)
foreach ($member in @($Method.DescendantNodes() | Where-Object {
$_.GetType().Name -eq 'MemberAccessExpressionSyntax'
})) {
if ($member.Name.Identifier.Text -in @('ReadAllText', 'ReadAllLines')) {
return $true
}
}
return $false
}
function Get-AssertionAuditSites {
param(
[Parameter(Mandatory)]$Tree,
@ -391,6 +424,8 @@ foreach ($relativePath in $trackedFiles) {
$methodMap = @{}
$failureMap = @{}
$outputMap = @{}
$textReadMap = @{}
$csharpPathMap = @{}
$gateMap = @{}
$callMap = @{}
@ -400,6 +435,8 @@ foreach ($relativePath in $trackedFiles) {
$methodMap[$key] = $method
$failureMap[$key] = Test-DirectFailureSignal $method
$outputMap[$key] = Test-DirectOutputSignal $method
$textReadMap[$key] = Test-TextFileRead $method
$csharpPathMap[$key] = Test-CSharpPathLiteral $method
$gateMap[$key] = @(Get-EmptyReturnSites $tree $method)
$callMap[$key] = @($method.DescendantNodes() |
Where-Object { $_.GetType().Name -eq 'InvocationExpressionSyntax' } |
@ -425,6 +462,11 @@ foreach ($relativePath in $trackedFiles) {
$key $methodMap $failureMap $callMap @{}
$hasOutputSignal = Test-RecursiveSignal `
$key $methodMap $outputMap $callMap @{}
$readsFileText = Test-RecursiveSignal `
$key $methodMap $textReadMap $callMap @{}
$usesCsharpPath = Test-RecursiveSignal `
$key $methodMap $csharpPathMap $callMap @{}
$readsSourceText = $readsFileText -and $usesCsharpPath
$emptyReturns = @($gateMap[$key])
$helperPrerequisiteReturns = @(Get-RecursivePrerequisiteGateSites `
@ -518,8 +560,9 @@ foreach ($relativePath in $trackedFiles) {
@($waitSites | Where-Object {
-not $_.IsCancellableInfiniteDelay
}).Count -eq 0
ReadsSourceText = $bodyText -match '(ReadAllText|ReadAllLines)\s*\(' -and
$bodyText -match '\.cs'
ReadsSourceTextDirectly = [bool]($textReadMap[$key] -and
$csharpPathMap[$key])
ReadsSourceText = $readsSourceText
})
}
}
@ -668,6 +711,9 @@ $summary = [ordered]@{
DirectEnvironmentVariableMethods = @($orderedRecords | Where-Object {
$_.EnvironmentVariables.Count -gt 0
}).Count
DirectSourceTextReadMethods = @($orderedRecords | Where-Object {
$_.ReadsSourceTextDirectly
}).Count
SourceTextReadMethods = @($orderedRecords | Where-Object { $_.ReadsSourceText }).Count
}