Add completion for values in comparisons when comparing Enums (#17654)

This commit is contained in:
MartinGC94 authored and GitHub committed 2022-08-22 15:18:49 -07:00
1 parent 99c757ff3e
commit 4051e09796
3 files changed
+154 -1

No files matched your search

@@ -500,6 +500,15 @@ namespace System.Management.Automation
return completions;
}
}
else if (lastAst.Parent is BinaryExpressionAst binaryExpression)
{
completionContext.WordToComplete = (tokenAtCursor as StringToken).Value;
result = CompletionCompleters.CompleteComparisonOperatorValues(completionContext, binaryExpression.Left);
if (result.Count > 0)
{
return result;
}
}
else if (lastAst.Parent is IndexExpressionAst indexExpressionAst)
{
// Handles quoted string inside index expression like: $PSVersionTable["<Tab>"]
@@ -911,8 +920,27 @@ namespace System.Management.Automation
{
result = GetResultForAttributeArgument(completionContext, ref replacementIndex, ref replacementLength);
}
break;
case TokenKind.Ieq:
case TokenKind.Ceq:
case TokenKind.Ine:
case TokenKind.Cne:
case TokenKind.Ilike:
case TokenKind.Clike:
case TokenKind.Inotlike:
case TokenKind.Cnotlike:
case TokenKind.Imatch:
case TokenKind.Cmatch:
case TokenKind.Inotmatch:
case TokenKind.Cnotmatch:
if (lastAst is BinaryExpressionAst binaryExpression)
{
completionContext.WordToComplete = string.Empty;
result = CompletionCompleters.CompleteComparisonOperatorValues(completionContext, binaryExpression.Left);
}
break;
case TokenKind.LBracket:
if (lastAst.Parent is IndexExpressionAst indexExpression)
{
@@ -921,6 +949,7 @@ namespace System.Management.Automation
result = CompletionCompleters.CompleteIndexExpression(completionContext, indexExpression.Target);
}
break;
default:
break;
}
@@ -991,6 +1020,26 @@ namespace System.Management.Automation
return result;
}
break;
case TokenKind.Ieq:
case TokenKind.Ceq:
case TokenKind.Ine:
case TokenKind.Cne:
case TokenKind.Ilike:
case TokenKind.Clike:
case TokenKind.Inotlike:
case TokenKind.Cnotlike:
case TokenKind.Imatch:
case TokenKind.Cmatch:
case TokenKind.Inotmatch:
case TokenKind.Cnotmatch:
if (lastAst is BinaryExpressionAst binaryExpression)
{
completionContext.WordToComplete = string.Empty;
result = CompletionCompleters.CompleteComparisonOperatorValues(completionContext, binaryExpression.Left);
}
break;
case TokenKind.LBracket:
if (lastAst.Parent is IndexExpressionAst indexExpression)
{
@@ -999,6 +1048,7 @@ namespace System.Management.Automation
result = CompletionCompleters.CompleteIndexExpression(completionContext, indexExpression.Target);
}
break;
default:
break;
}
@@ -2317,6 +2317,11 @@ namespace System.Management.Automation
{
NativeCompletionMemberName(context, result, commandAst, boundArguments?[parameterName]);
}
else if (parameterName.Equals("Value", StringComparison.OrdinalIgnoreCase)
&& boundArguments?["Property"] is AstPair pair && pair.Argument is StringConstantExpressionAst stringAst)
{
NativeCompletionMemberValue(context, result, commandAst, stringAst.Value);
}
break;
}
@@ -3994,6 +3999,38 @@ namespace System.Management.Automation
result.Add(CompletionResult.Null);
}
private static void NativeCompletionMemberValue(CompletionContext context, List<CompletionResult> result, CommandAst commandAst, string propertyName)
{
string wordToComplete = context.WordToComplete.Trim('"', '\'');
IEnumerable<PSTypeName> prevTypes = GetInferenceTypes(context, commandAst);
if (prevTypes is not null)
{
foreach (var type in prevTypes)
{
if (type.Type is null)
{
continue;
}
PropertyInfo property = type.Type.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (property is not null && property.PropertyType.IsEnum)
{
foreach (var value in property.PropertyType.GetEnumNames())
{
if (value.StartsWith(wordToComplete, StringComparison.OrdinalIgnoreCase))
{
result.Add(new CompletionResult(value, value, CompletionResultType.ParameterValue, value));
}
}
break;
}
}
}
result.Add(CompletionResult.Null);
}
/// <summary>
/// Returns all string values bound to a parameter except the one the cursor is currently at.
/// </summary>
@@ -5913,6 +5950,46 @@ namespace System.Management.Automation
return results;
}
internal static List<CompletionResult> CompleteComparisonOperatorValues(CompletionContext context, ExpressionAst operatorLeftValue)
{
var result = new List<CompletionResult>();
var resolvedTypes = new List<Type>();
if (SafeExprEvaluator.TrySafeEval(operatorLeftValue, context.ExecutionContext, out object value) && value is not null)
{
resolvedTypes.Add(value.GetType());
}
else
{
var inferredTypes = AstTypeInference.InferTypeOf(operatorLeftValue, context.TypeInferenceContext, TypeInferenceRuntimePermissions.AllowSafeEval);
foreach (var type in inferredTypes)
{
if (type.Type is not null)
{
resolvedTypes.Add(type.Type);
}
}
}
foreach (var type in resolvedTypes)
{
if (type.IsEnum)
{
foreach (var name in type.GetEnumNames())
{
if (name.StartsWith(context.WordToComplete, StringComparison.OrdinalIgnoreCase))
{
result.Add(new CompletionResult($"'{name}'", name, CompletionResultType.ParameterValue, name));
}
}
break;
}
}
return result;
}
/// <summary>
/// Complete members against extension methods 'Where' and 'ForEach'
/// </summary>