Skip to content

Commit 117fa6b

Browse files
Copilotbergmeister
andauthored
Handle arrays and casts in ValidateRange type-mismatch warnings (#2273)
* Initial plan * Fix ValidateRange analyzer review findings Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> * Restore decimal range test coverage Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com>
1 parent 7cdaee3 commit 117fa6b

2 files changed

Lines changed: 38 additions & 20 deletions

File tree

‎Rules/AvoidValidateRangeTypeMismatch.cs‎

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2121
#endif
2222
public sealed class AvoidValidateRangeTypeMismatch : IScriptRule
2323
{
24-
private static readonly HashSet<string> FloatingPointAndDecimalTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
24+
private static readonly HashSet<Type> FloatingPointAndDecimalTypes = new HashSet<Type>
2525
{
26-
"double", "System.Double",
27-
"single", "float", "System.Single",
28-
"decimal", "System.Decimal"
26+
typeof(double),
27+
typeof(float),
28+
typeof(decimal)
2929
};
3030

31-
private static readonly HashSet<string> IntegralTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
31+
private static readonly HashSet<Type> IntegralTypes = new HashSet<Type>
3232
{
33-
"byte", "System.Byte",
34-
"sbyte", "System.SByte",
35-
"short", "System.Int16",
36-
"ushort", "System.UInt16",
37-
"int", "System.Int32",
38-
"uint", "System.UInt32",
39-
"long", "System.Int64",
40-
"ulong", "System.UInt64"
33+
typeof(byte),
34+
typeof(sbyte),
35+
typeof(short),
36+
typeof(ushort),
37+
typeof(int),
38+
typeof(uint),
39+
typeof(long),
40+
typeof(ulong)
4141
};
4242

4343
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
@@ -51,7 +51,23 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
5151
foreach (ParameterAst parameterAst in parameterAsts)
5252
{
5353
TypeConstraintAst typeConstraint = parameterAst.Attributes.OfType<TypeConstraintAst>().FirstOrDefault();
54-
if (typeConstraint == null || !FloatingPointAndDecimalTypes.Contains(typeConstraint.TypeName.FullName))
54+
if (typeConstraint == null)
55+
{
56+
continue;
57+
}
58+
59+
Type parameterType = typeConstraint.TypeName.GetReflectionType();
60+
if (parameterType == null)
61+
{
62+
continue;
63+
}
64+
65+
if (parameterType.IsArray)
66+
{
67+
parameterType = parameterType.GetElementType();
68+
}
69+
70+
if (!FloatingPointAndDecimalTypes.Contains(parameterType))
5571
{
5672
continue;
5773
}
@@ -60,7 +76,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
6076
{
6177
if (!IsValidateRangeAttribute(attributeAst)
6278
|| attributeAst.PositionalArguments.Count < 2
63-
|| !attributeAst.PositionalArguments.Take(2).Any(IsIntegralBoundary))
79+
|| !attributeAst.PositionalArguments.Take(2).All(IsIntegralBoundary))
6480
{
6581
continue;
6682
}
@@ -79,14 +95,12 @@ private static bool IsIntegralBoundary(ExpressionAst expressionAst)
7995
{
8096
if (expressionAst is ConstantExpressionAst constantExpressionAst)
8197
{
82-
return constantExpressionAst.Value != null
83-
&& IntegralTypes.Contains(constantExpressionAst.Value.GetType().FullName);
98+
return constantExpressionAst.Value != null && IntegralTypes.Contains(constantExpressionAst.Value.GetType());
8499
}
85100

86101
if (expressionAst is ConvertExpressionAst convertExpressionAst)
87102
{
88-
return IntegralTypes.Contains(convertExpressionAst.Type.TypeName.FullName)
89-
&& IsIntegralBoundary(convertExpressionAst.Child);
103+
return IntegralTypes.Contains(convertExpressionAst.Type.TypeName.GetReflectionType());
90104
}
91105

92106
if (expressionAst is UnaryExpressionAst unaryExpressionAst

‎Tests/Rules/AvoidValidateRangeTypeMismatch.tests.ps1‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ Describe 'AvoidValidateRangeTypeMismatch' {
1010
$scripts = @(
1111
'function Test { param([double][ValidateRange(1, 2)]$Value) }'
1212
'function Test { param([single][ValidateRange(-1, 2)]$Value) }'
13-
'function Test { param([decimal][ValidateRange(1, 2.0)]$Value) }'
13+
'function Test { param([decimal][ValidateRange(1, 2)]$Value) }'
14+
'function Test { param([double[]][ValidateRange(1, 2)]$Values) }'
1415
'function Test { param([double][System.Management.Automation.ValidateRangeAttribute(1, 2)]$Value) }'
16+
'function Test { param([double][ValidateRange([int]0.0, [int]100.0)]$Value) }'
17+
'function Test { param([double][ValidateRange([int32]0.0, [int32]100.0)]$Value) }'
1518
)
1619

1720
foreach ($scriptDefinition in $scripts) {
@@ -26,6 +29,7 @@ Describe 'AvoidValidateRangeTypeMismatch' {
2629
'function Test { param([double][ValidateRange(1.0, 2.0)]$Value) }'
2730
'function Test { param([single][ValidateRange(1.0, 2.0)]$Value) }'
2831
'function Test { param([decimal][ValidateRange(1.0, 2.0)]$Value) }'
32+
'function Test { param([double][ValidateRange(1, 2.0)]$Value) }'
2933
'function Test { param([int][ValidateRange(1, 2)]$Value) }'
3034
)
3135

0 commit comments

Comments
 (0)