diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs
index e7b289418f..5b00b9df42 100644
--- a/src/System.Management.Automation/engine/Attributes.cs
+++ b/src/System.Management.Automation/engine/Attributes.cs
@@ -1311,6 +1311,28 @@ namespace System.Management.Automation
return resultType;
}
+
+ ///
+ /// Returns only the elements that passed the attribute's validation.
+ ///
+ /// The objects to validate.
+ internal IEnumerable GetValidatedElements(IEnumerable elementsToValidate)
+ {
+ foreach (var el in elementsToValidate)
+ {
+ try
+ {
+ ValidateElement(el);
+ }
+ catch (ValidationMetadataException)
+ {
+ // Element was not in range - drop
+ continue;
+ }
+
+ yield return el;
+ }
+ }
}
///
diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
index 1cf7082b3c..8dae46f339 100644
--- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
+++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
@@ -1796,9 +1796,16 @@ namespace System.Management.Automation
{
RemoveLastNullCompletionResult(result);
- string enumString = LanguagePrimitives.EnumSingleTypeConverter.EnumValues(parameterType);
- string separator = CultureInfo.CurrentUICulture.TextInfo.ListSeparator;
- string[] enumArray = enumString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
+ IEnumerable enumValues = LanguagePrimitives.EnumSingleTypeConverter.GetEnumValues(parameterType);
+
+ // Exclude values not accepted by ValidateRange-attributes
+ foreach (ValidateArgumentsAttribute att in parameter.Parameter.ValidationAttributes)
+ {
+ if (att is ValidateRangeAttribute rangeAtt)
+ {
+ enumValues = rangeAtt.GetValidatedElements(enumValues);
+ }
+ }
string wordToComplete = context.WordToComplete ?? string.Empty;
string quote = HandleDoubleAndSingleQuote(ref wordToComplete);
@@ -1806,18 +1813,19 @@ namespace System.Management.Automation
var pattern = WildcardPattern.Get(wordToComplete + "*", WildcardOptions.IgnoreCase);
var enumList = new List();
- foreach (string value in enumArray)
+ foreach (Enum value in enumValues)
{
- if (wordToComplete.Equals(value, StringComparison.OrdinalIgnoreCase))
+ string name = value.ToString();
+ if (wordToComplete.Equals(name, StringComparison.OrdinalIgnoreCase))
{
- string completionText = quote == string.Empty ? value : quote + value + quote;
- fullMatch = new CompletionResult(completionText, value, CompletionResultType.ParameterValue, value);
+ string completionText = quote == string.Empty ? name : quote + name + quote;
+ fullMatch = new CompletionResult(completionText, name, CompletionResultType.ParameterValue, name);
continue;
}
- if (pattern.IsMatch(value))
+ if (pattern.IsMatch(name))
{
- enumList.Add(value);
+ enumList.Add(name);
}
}
diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs
index ac3c1c1a70..a93bd1658d 100644
--- a/src/System.Management.Automation/engine/LanguagePrimitives.cs
+++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs
@@ -2076,6 +2076,14 @@ namespace System.Management.Automation
return string.Join(CultureInfo.CurrentUICulture.TextInfo.ListSeparator, enumHashEntry.names);
}
+ ///
+ /// Returns all values for the provided enum type.
+ ///
+ /// The enum type to retrieve values from.
+ /// Array of enum values for the specified type.
+ internal static Array GetEnumValues(Type enumType)
+ => EnumSingleTypeConverter.GetEnumHashEntry(enumType).values;
+
public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase)
{
return EnumSingleTypeConverter.BaseConvertFrom(sourceValue, destinationType, formatProvider, ignoreCase, false);
diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1
index 1016650db3..fee6c8c000 100644
--- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1
+++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1
@@ -1597,6 +1597,31 @@ class InheritedClassTest : System.Attribute
$res.CompletionMatches[1].CompletionText | Should -BeExactly 'Configuration'
}
+ It 'Tab completion for enum parameter is filtered against ' -TestCases @(
+ @{ Name = 'ValidateRange with enum-values'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)]' }
+ @{ Name = 'ValidateRange with int-values'; Attribute = '[ValidateRange(9, 11)]' }
+ @{ Name = 'multiple ValidateRange-attributes'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)][ValidateRange([System.ConsoleColor]::Gray, [System.ConsoleColor]::Red)]' }
+ ) {
+ param($Name, $Attribute)
+ $functionDefinition = 'param ( {0}[consolecolor]$color )' -f $Attribute
+ Set-Item -Path function:baz -Value $functionDefinition
+ $inputStr = 'baz -color '
+ $res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
+ $res.CompletionMatches | Should -HaveCount 3
+ $res.CompletionMatches[0].CompletionText | Should -BeExactly 'Blue'
+ $res.CompletionMatches[1].CompletionText | Should -BeExactly 'Cyan'
+ $res.CompletionMatches[2].CompletionText | Should -BeExactly 'Green'
+ }
+
+ It 'Tab completion for enum parameter is filtered with ValidateRange using rangekind' {
+ $functionDefinition = 'param ( [ValidateRange([System.Management.Automation.ValidateRangeKind]::NonPositive)][consolecolor]$color )' -f $Attribute
+ Set-Item -Path function:baz -Value $functionDefinition
+ $inputStr = 'baz -color '
+ $res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
+ $res.CompletionMatches | Should -HaveCount 1
+ $res.CompletionMatches[0].CompletionText | Should -BeExactly 'Black' # 0 = NonPositive
+ }
+
It "Test [CommandCompletion]::GetNextResult" {
$inputStr = "Get-Command -Type Alias,c"
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length