Handle type inference for redirected commands (#21131)

This commit is contained in:
MartinGC94
2025-02-28 04:20:25 +00:00
committed by GitHub
parent 0f7c8de217
commit 6fbd8ba1dd
2 changed files with 108 additions and 0 deletions
@@ -1272,6 +1272,73 @@ namespace System.Management.Automation
private void InferTypesFrom(CommandAst commandAst, List<PSTypeName> inferredTypes)
{
if (commandAst.Redirections.Count > 0)
{
var mergedStreams = new HashSet<RedirectionStream>();
bool allStreamsMerged = false;
foreach (RedirectionAst streamRedirection in commandAst.Redirections)
{
if (streamRedirection is FileRedirectionAst fileRedirection)
{
if (fileRedirection.FromStream is RedirectionStream.All or RedirectionStream.Output)
{
// command output is redirected so it returns nothing.
return;
}
}
else if (streamRedirection is MergingRedirectionAst mergeRedirection && mergeRedirection.ToStream == RedirectionStream.Output)
{
if (mergeRedirection.FromStream == RedirectionStream.All)
{
allStreamsMerged = true;
continue;
}
_ = mergedStreams.Add(mergeRedirection.FromStream);
}
}
if (allStreamsMerged)
{
inferredTypes.Add(new PSTypeName(typeof(ErrorRecord)));
inferredTypes.Add(new PSTypeName(typeof(WarningRecord)));
inferredTypes.Add(new PSTypeName(typeof(VerboseRecord)));
inferredTypes.Add(new PSTypeName(typeof(DebugRecord)));
inferredTypes.Add(new PSTypeName(typeof(InformationRecord)));
}
else
{
foreach (RedirectionStream value in mergedStreams)
{
switch (value)
{
case RedirectionStream.Error:
inferredTypes.Add(new PSTypeName(typeof(ErrorRecord)));
break;
case RedirectionStream.Warning:
inferredTypes.Add(new PSTypeName(typeof(WarningRecord)));
break;
case RedirectionStream.Verbose:
inferredTypes.Add(new PSTypeName(typeof(VerboseRecord)));
break;
case RedirectionStream.Debug:
inferredTypes.Add(new PSTypeName(typeof(DebugRecord)));
break;
case RedirectionStream.Information:
inferredTypes.Add(new PSTypeName(typeof(InformationRecord)));
break;
default:
break;
}
}
}
}
PseudoBindingInfo pseudoBinding = new PseudoParameterBinder()
.DoPseudoParameterBinding(commandAst, null, null, PseudoParameterBinder.BindingType.ParameterCompletion);
@@ -1492,6 +1492,47 @@ Describe "Type inference Tests" -tags "CI" {
$null = [AstTypeInference]::InferTypeOf($FoundAst)
}
It 'Infers type of command with all streams redirected to Success stream' {
$res = [AstTypeInference]::InferTypeOf( { Get-PSDrive *>&1 }.Ast)
$ExpectedTypeNames = @(
[ErrorRecord].FullName
[WarningRecord].FullName
[VerboseRecord].FullName
[DebugRecord].FullName
[InformationRecord].FullName
[PSDriveInfo].FullName
) -join ';'
$res.Name -join ';' | Should -Be $ExpectedTypeNames
}
It 'Infers type of command with success stream redirected' {
$res = [AstTypeInference]::InferTypeOf( { Get-PSDrive *>&1 1>$null }.Ast)
$res.Count | Should -Be 0
}
It 'Infers type of command with some streams redirected to success' {
$res = [AstTypeInference]::InferTypeOf( { Get-PSDrive 3>&1 4>&1 }.Ast)
$res.Count | Should -Be 3
$ExpectedTypeNames = @(
[PSDriveInfo].FullName
[VerboseRecord].FullName
[WarningRecord].FullName
) -join ';'
($res.Name | Sort-Object) -join ';' | Should -Be $ExpectedTypeNames
}
It 'Infers type of command with other streams redirected to success' {
$res = [AstTypeInference]::InferTypeOf( { Get-PSDrive 2>&1 5>&1 6>&1 }.Ast)
$res.Count | Should -Be 4
$ExpectedTypeNames = @(
[DebugRecord].FullName
[ErrorRecord].FullName
[InformationRecord].FullName
[PSDriveInfo].FullName
) -join ';'
($res.Name | Sort-Object) -join ';' | Should -Be $ExpectedTypeNames
}
It 'Should only consider assignments wrapped in parentheses to be a part of the output in a Named block' {
$res = [AstTypeInference]::InferTypeOf( { [string]$Assignment1 = "Hello"; ([int]$Assignment2 = 42) }.Ast)
$res.Count | Should -Be 1