diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index e9a28c2a165..2b71103786d 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -5573,7 +5573,13 @@ public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst a : AstVisitAction.StopVisit; } - if (assignmentStatementAst.Left is AttributedExpressionAst attributedExpression) + ProcessAssignmentLeftSide(assignmentStatementAst.Left, assignmentStatementAst.Right); + return AstVisitAction.Continue; + } + + private void ProcessAssignmentLeftSide(ExpressionAst left, StatementAst right) + { + if (left is AttributedExpressionAst attributedExpression) { var firstConvertExpression = attributedExpression as ConvertExpressionAst; ExpressionAst child = attributedExpression.Child; @@ -5593,7 +5599,7 @@ public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst a { if (variableExpression == CompletionVariableAst || s_specialVariablesCache.Value.Contains(variableExpression.VariablePath.UserPath)) { - return AstVisitAction.Continue; + return; } if (firstConvertExpression is not null) @@ -5602,22 +5608,22 @@ public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst a } else { - PSTypeName lastAssignedType = assignmentStatementAst.Right is CommandExpressionAst commandExpression + PSTypeName lastAssignedType = right is CommandExpressionAst commandExpression ? GetInferredVarTypeFromAst(commandExpression.Expression) : null; SaveVariableInfo(variableExpression.VariablePath.UnqualifiedPath, lastAssignedType, isConstraint: false); } } } - else if (assignmentStatementAst.Left is VariableExpressionAst variableExpression) + else if (left is VariableExpressionAst variableExpression) { if (variableExpression == CompletionVariableAst || s_specialVariablesCache.Value.Contains(variableExpression.VariablePath.UserPath)) { - return AstVisitAction.Continue; + return; } PSTypeName lastAssignedType; - if (assignmentStatementAst.Right is CommandExpressionAst commandExpression) + if (right is CommandExpressionAst commandExpression) { lastAssignedType = GetInferredVarTypeFromAst(commandExpression.Expression); } @@ -5628,8 +5634,21 @@ public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst a SaveVariableInfo(variableExpression.VariablePath.UnqualifiedPath, lastAssignedType, isConstraint: false); } - - return AstVisitAction.Continue; + else if (left is ArrayLiteralAst array) + { + foreach (ExpressionAst expression in array.Elements) + { + ProcessAssignmentLeftSide(expression, right); + } + } + else if (left is ParenExpressionAst parenExpression) + { + ExpressionAst pureExpression = parenExpression.Pipeline.GetPureExpression(); + if (pureExpression is not null) + { + ProcessAssignmentLeftSide(pureExpression, right); + } + } } public override AstVisitAction VisitCommand(CommandAst commandAst) diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index c7d6ee744e0..bbef6121983 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -1044,6 +1044,17 @@ param([ValidatePattern( $res.CompletionMatches[0].CompletionText | Should -BeExactly '$TestVar1' } + It 'Should complete variable assigned in ParenExpression' { + $res = TabExpansion2 -inputScript '($ParenVar) = 1; $ParenVa' + $res.CompletionMatches[0].CompletionText | Should -BeExactly '$ParenVar' + } + + It 'Should complete variable assigned in ArrayLiteral' { + $res = TabExpansion2 -inputScript '$DemoVar1, $DemoVar2 = 1..10; $DemoVar' + $res.CompletionMatches[0].CompletionText | Should -BeExactly '$DemoVar1' + $res.CompletionMatches[1].CompletionText | Should -BeExactly '$DemoVar2' + } + Context 'Start-Process -Verb parameter completion' { BeforeAll { function GetProcessInfoVerbs([string]$path, [switch]$singleQuote, [switch]$doubleQuote) {