Repository: PowerShell/PowerShell
File: src/System.Management.Automation/engine/CommandCompletion/CompletionAnalysis.cs (C#)

Code before:
            // Must be a string constant
            if (!(lastAst is StringConstantExpressionAst stringAst))
            {
                return null;
            }

            Ast targetAst = null;

            // Check for method invocation: $PSBoundParameters.ContainsKey('...') or $PSBoundParameters.Remove('...')
            if (lastAst.Parent is InvokeMemberExpressionAst invokeMemberAst)
            {
                var memberName = invokeMemberAst.Member as StringConstantExpressionAst;
                if (memberName != null &&
                    (memberName.Value.Equals("ContainsKey", StringComparison.OrdinalIgnoreCase) ||
                     memberName.Value.Equals("Remove", StringComparison.OrdinalIgnoreCase)))
                {
                    targetAst = invokeMemberAst.Expression;
                }
            }
            // Check for indexer: $PSBoundParameters['...']
            else if (lastAst.Parent is IndexExpressionAst indexAst)
            {
                targetAst = indexAst.Target;
            }

            if (targetAst == null)
            {
                return null;
            }

            // Check if target is $PSBoundParameters
            var variableAst = targetAst as VariableExpressionAst;
            if (variableAst == null ||
                !variableAst.VariablePath.UserPath.Equals("PSBoundParameters", StringComparison.OrdinalIgnoreCase))
            {
                return null;
            }

            // Find the nearest param block
            ParamBlockAst paramBlockAst = null;
            Ast current = lastAst.Parent;
            while (current != null)
            {
                if (current is FunctionDefinitionAst functionDefinitionAst)
                {
                    paramBlockAst = functionDefinitionAst.Body?.ParamBlock;
                    break;
                }
                else if (current is ScriptBlockAst scriptBlockAst)
                {
                    paramBlockAst = scriptBlockAst.ParamBlock;

Review comment (suggestion):
```suggestion
            if (targetAst is null)
```

Code after:
            if (paramBlockAst == null || paramBlockAst.Parameters.Count == 0)
            {
                return null;
            }

            // Generate completion results from parameter names
            var wordToComplete = completionContext.WordToComplete ?? string.Empty;

            // Determine quote style based on the string constant type
            string quoteChar = string.Empty;
            if (stringAst.StringConstantType == StringConstantType.SingleQuoted)
            {
                quoteChar = "'";
            }
            else if (stringAst.StringConstantType == StringConstantType.DoubleQuoted)
            {
                quoteChar = "\"";
            }

            return CreateParameterCompletionResults(paramBlockAst, wordToComplete, quoteChar);
        }

        /// <summary>
        /// Finds the nearest ParamBlockAst by traversing up the AST hierarchy.
        /// </summary>
        /// <param name="startAst">The AST node to start searching from.</param>
        /// <returns>The nearest ParamBlockAst if found; otherwise, null.</returns>
        private static ParamBlockAst FindNearestParamBlock(Ast startAst)
        {
            Ast current = startAst;
            while (current != null)
            {
                if (current is FunctionDefinitionAst functionDefinitionAst)
                {
                    return functionDefinitionAst.Body?.ParamBlock;
                }
                else if (current is ScriptBlockAst scriptBlockAst)
                {
                    var paramBlock = scriptBlockAst.ParamBlock;
                    if (paramBlock != null)
                    {
                        return paramBlock;
                    }
                }

                current = current.Parent;
            }

            return null;
        }