@@ -15,6 +15,8 @@ enum RuleNames {
15
15
Mismatched_Parameter_Value_Type
16
16
}
17
17
18
+ $global :UtilityOutputTypePair = @ {" ConvertTo-Json" = [string ]; " ConvertFrom-Json" = [hashtable ]}
19
+
18
20
<#
19
21
. SYNOPSIS
20
22
Gets the actual name of the parameter, not alias.
@@ -35,20 +37,40 @@ function Get-ParameterNameNotAlias {
35
37
Gets the final actual value from ast.
36
38
#>
37
39
function Get-FinalVariableValue {
38
- param ([System.Management.Automation.Language.Ast ]$CommandElementAst )
39
-
40
+ param ([System.Management.Automation.Language.Ast ]$CommandElementAst ,
41
+ [ System.Management.Automation.Language.VariableExpressionAst ] $VariableExpressionAst = $null )
40
42
while ($true ) {
41
43
if ($null -ne $CommandElementAst.Expression ) {
42
44
$CommandElementAst = $CommandElementAst.Expression
43
45
}
46
+ elseif ($null -ne $CommandElementAst.Left ) {
47
+ if ($CommandElementAst.Left -eq $VariableExpressionAst ){
48
+ if ($CommandElementAst.Right -eq $VariableExpressionAst ){
49
+ $CommandElementAst = $null
50
+ }
51
+ else {
52
+ $CommandElementAst = $CommandElementAst.Right
53
+ }
54
+ }
55
+ else {
56
+ $CommandElementAst = $CommandElementAst.Left
57
+ }
58
+ }
44
59
elseif ($null -ne $CommandElementAst.Target ) {
45
60
$CommandElementAst = $CommandElementAst.Target
46
61
}
47
62
elseif ($null -ne $CommandElementAst.Pipeline ) {
48
63
$CommandElementAst = $CommandElementAst.Pipeline
49
64
}
50
65
elseif ($null -ne $CommandElementAst.PipelineElements ) {
51
- $CommandElementAst = $CommandElementAst.PipelineElements [-1 ]
66
+ $LastElement = $CommandElementAst.PipelineElements [-1 ].Extent.Text
67
+ # If the LastElement contains "where" or "sort", then the type isnot changed.
68
+ if ($LastElement -match " where" -or $LastElement -match " sort" ){
69
+ $CommandElementAst = $CommandElementAst.PipelineElements [0 ]
70
+ }
71
+ else {
72
+ $CommandElementAst = $CommandElementAst.PipelineElements [-1 ]
73
+ }
52
74
}
53
75
elseif ($null -ne $CommandElementAst.Elements ){
54
76
$CommandElementAst = $CommandElementAst.Elements [0 ]
@@ -98,12 +120,23 @@ function Get-RecoveredValueType{
98
120
}
99
121
}
100
122
else {
123
+ if ($Items [$j ].Value -eq " new" ){
124
+ return $Type
125
+ }
101
126
$Member = $Type.GetMembers () | Where-Object {$_.Name -eq $Items [$j ]}
102
- if ($Member -is [array ]){
103
- $Member = $Member [0 ]
127
+ if ($null -eq $Member -and $null -ne $Type.ImplementedInterfaces ){
128
+ for ($i = 0 ; $i -lt $Type.ImplementedInterfaces.Length ; $i ++ ){
129
+ $Member = $Type.ImplementedInterfaces [$i ].GetMembers() | Where-Object {$_.Name -eq $Items [$j ]}
130
+ if ($null -ne $Member ){
131
+ break
132
+ }
133
+ }
104
134
}
105
135
if ($null -eq $Member ){
106
- return $null
136
+ return $null
137
+ }
138
+ if ($Member -is [array ]){
139
+ $Member = $Member [0 ]
107
140
}
108
141
if ($null -ne $Member.PropertyType ){
109
142
$Type = $Member.PropertyType
@@ -119,6 +152,36 @@ function Get-RecoveredValueType{
119
152
return $Type
120
153
}
121
154
155
+ <#
156
+ . SYNOPSIS
157
+ Measure whether the actual type matches the expected type.
158
+ #>
159
+ function Measure-IsTypeMatched {
160
+ param (
161
+ [System.Reflection.TypeInfo ]$ExpectedType ,
162
+ [System.Reflection.TypeInfo ]$ActualType
163
+ )
164
+ if ($ActualType.IsArray ) {
165
+ $ActualType = $ActualType.GetElementType ()
166
+ }
167
+ if ($ActualType.IsGenericType ){
168
+ $ActualType = $ActualType.GetGenericArguments ()[0 ]
169
+ }
170
+ $Converter = [System.ComponentModel.TypeDescriptor ]::GetConverter($ExpectedType )
171
+ if ($ActualType -eq $ExpectedType -or
172
+ $ActualType.GetInterfaces ().Contains($ExpectedType ) -or
173
+ $ExpectedType.GetInterfaces ().Contains($ActualType ) -or
174
+ $ActualType.IsSubclassOf ($ExpectedType ) -or
175
+ $Converter.CanConvertFrom ($ActualType )) {
176
+ return $true
177
+ }
178
+ return $false
179
+ }
180
+
181
+ <#
182
+ . SYNOPSIS
183
+ Gets the expression's actual value and type, if the parameter is assigned with a value.
184
+ #>
122
185
function Get-AssignedParameterExpression {
123
186
param (
124
187
[System.Management.Automation.CommandInfo ]$GetCommand ,
@@ -134,24 +197,45 @@ function Get-AssignedParameterExpression {
134
197
break
135
198
}
136
199
# Get the actual value
137
- $CommandElement_Copy = Get-FinalVariableValue $global :AssignmentLeftAndRight .($CommandElement_Copy.Extent.Text )
200
+ $CommandElement_Copy = Get-FinalVariableValue $global :AssignmentLeftAndRight .($CommandElement_Copy.Extent.Text ) $CommandElement_Copy
138
201
if ($null -eq $CommandElement_Copy ) {
139
202
# Variable is not assigned with a value.
140
203
# Unassigned_Variable
141
204
$ExpressionToParameter = $CommandElement.Extent.Text + " is a null-valued parameter value."
142
205
return $ExpressionToParameter
143
206
}
144
207
}
208
+ if ($CommandElement_Copy.Extent.Text -match " foreach" -or $CommandElement_Copy.Extent.Text -match " select" ){
209
+ Write-Debug " The CommandElement contains 'foreach' or 'select'. This situation can not be handled now."
210
+ return $null
211
+ }
212
+ $ExpectedType = $GetCommand.Parameters .$ParameterNameNotAlias.ParameterType
213
+ if ($CommandElement_Copy -is [System.Management.Automation.Language.HashtableAst ]){
214
+ # If ExpectedType is ValueType, then it cannot be created by Hashtable.
215
+ if ($ExpectedType.IsValueType ){
216
+ # Mismatched_Parameter_Value_Type
217
+ $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType , created by hashtable but is value type."
218
+ return $ExpressionToParameter
219
+ }
220
+ return $null
221
+ }
222
+ while ($ExpectedType.IsArray ) {
223
+ $ExpectedType = $ExpectedType.GetElementType ()
224
+ }
225
+ if ($ExpectedType.IsGenericType ){
226
+ $ExpectedType = $ExpectedType.GetGenericArguments ()[0 ]
227
+ }
145
228
if ($CommandElement_Copy -is [System.Management.Automation.Language.CommandAst ]) {
146
229
# Value is an command
147
230
# If the value is created by "New-Object", then get the type behind "New-Object".
148
231
if ($CommandElement_Copy.CommandElements [0 ].Extent.Text -eq " New-Object" ){
149
232
if ($CommandElement_Copy.CommandElements [1 ].Extent.Text -eq " -TypeName" ){
150
- $OutputType = $CommandElement_Copy.CommandElements [2 ].Extent.Text -as [ Type ]
233
+ $TypeName = $CommandElement_Copy.CommandElements [2 ].Extent.Text -replace " `" "
151
234
}
152
235
else {
153
- $OutputType = $CommandElement_Copy.CommandElements [1 ].Extent.Text -as [ Type ]
236
+ $TypeName = $CommandElement_Copy.CommandElements [1 ].Extent.Text
154
237
}
238
+ $OutputType = $TypeName -as [Type ]
155
239
$OutputTypes = @ () + $OutputType
156
240
}
157
241
else {
@@ -162,10 +246,16 @@ function Get-AssignedParameterExpression {
162
246
return $null
163
247
}
164
248
$OutputTypes = @ ()
165
- $j = 0
166
- while ($GetElementCommand.OutputType [$j ]){
167
- $OutputTypes += $GetElementCommand.OutputType [$j ].Type
168
- $j ++
249
+ if ($global :UtilityOutputTypePair.ContainsKey ($GetElementCommand.Name )){
250
+ $OutputType = $global :UtilityOutputTypePair .($GetElementCommand.Name )
251
+ $OutputTypes += $OutputType
252
+ }
253
+ else {
254
+ $j = 0
255
+ while ($GetElementCommand.OutputType [$j ]){
256
+ $OutputTypes += $GetElementCommand.OutputType [$j ].Type
257
+ $j ++
258
+ }
169
259
}
170
260
}
171
261
$flag = $true
@@ -174,63 +264,43 @@ function Get-AssignedParameterExpression {
174
264
$ReturnType = $OutputTypes [$j ]
175
265
$j ++
176
266
$ActualType = Get-RecoveredValueType $CommandElement $ReturnType
177
- $ExpectedType = $GetCommand.Parameters .$ParameterNameNotAlias.ParameterType
178
267
if ($null -eq $ActualType ){
179
268
Continue
180
269
}
181
- if ($ExpectedType.IsArray ) {
182
- $ExpectedType = $ExpectedType.GetElementType ()
183
- }
184
- if ($ActualType.IsArray ) {
185
- $ActualType = $ActualType.GetElementType ()
186
- }
187
- if ($ActualType.IsGenericType ){
188
- $ActualType = $ActualType.GetGenericArguments ()[0 ]
189
- }
190
- if ($ExpectedType.IsGenericType ){
191
- $ExpectedType = $ExpectedType.GetGenericArguments ()[0 ]
192
- }
193
- if ($ActualType -eq $ExpectedType -or $ActualType -is $ExpectedType -or
194
- $ActualType.GetInterfaces ().Contains($ExpectedType ) -or $ExpectedType.GetInterfaces ().Contains($ActualType )) {
270
+ if (Measure-IsTypeMatched $ExpectedType $ActualType ){
195
271
$flag = $false
272
+ break
196
273
}
197
274
}
198
275
if ($flag ){
199
276
# Mismatched_Parameter_Value_Type
200
- $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType "
277
+ $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType . Now the type is $ActualType .(Command) "
201
278
return $ExpressionToParameter
202
279
}
203
-
204
280
}
205
- elseif ($CommandElement_Copy -is [System.Management.Automation.Language.HashtableAst ]){
206
- # If ExpectedType is ValueType, then it cannot be created by Hashtable.
207
- if ($ExpectedType.IsValueType ){
281
+ elseif ($CommandElement_Copy -is [System.Management.Automation.Language.TypeExpressionAst ] -or
282
+ $CommandElement_Copy -is [System.Management.Automation.Language.TypeConstraintAst ]){
283
+ $ReturnType = $CommandElement_Copy.TypeName.ToString () -as [Type ]
284
+ $ActualType = Get-RecoveredValueType $CommandElement $ReturnType
285
+ if (! (Measure-IsTypeMatched $ExpectedType $ActualType )) {
208
286
# Mismatched_Parameter_Value_Type
209
- $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType "
287
+ $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType . Now the type is $ActualType .(Type) "
210
288
return $ExpressionToParameter
211
289
}
212
290
}
213
291
elseif ($CommandElement_Copy -is [System.Management.Automation.Language.ExpressionAst ]) {
214
- # Value is a constant expression
215
- $ExpectedType = $GetCommand.Parameters .$ParameterNameNotAlias.ParameterType
292
+ # Value is a constant expression
216
293
$ConvertedObject = $CommandElement_Copy.Extent.text -as $ExpectedType
217
- $StaticType = $CommandElement_Copy.StaticType
218
- if ($ExpectedType.IsGenericType ){
219
- $ExpectedType = $ExpectedType.GetGenericArguments ()[0 ]
220
- }
221
- if ($StaticType.IsGenericType ){
222
- $StaticType = $StaticType.GetGenericArguments ()[0 ]
223
- }
224
- if ($ExpectedType.IsArray ){
225
- $ExpectedType = $ExpectedType.GetElementType ()
226
- }
227
- if ($StaticType.IsArray ){
228
- $StaticType = $StaticType.GetElementType ()
294
+ if ($null -eq $ConvertedObject ){
295
+ if ($null -ne (Get-Variable | Where-Object {$_.Name -eq $CommandElement_Copy.VariablePath })){
296
+ $value = (Get-Variable | Where-Object {$_.Name -eq $CommandElement_Copy.VariablePath }).Value
297
+ }
298
+ $ConvertedObject = $value -as $ExpectedType
229
299
}
230
- if ( $StaticType -ne $ExpectedType -and $null -eq $ConvertedObject -and
231
- ! $StaticType .GetInterfaces ().Contains( $ExpectedType ) -and ! $ExpectedType .GetInterfaces ().Contains( $StaticType ) ) {
300
+ $StaticType = $CommandElement_Copy .StaticType
301
+ if ( ! ( Measure-IsTypeMatched $ExpectedType $StaticType ) -and $null -eq $ConvertedObject ) {
232
302
# Mismatched_Parameter_Value_Type
233
- $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType "
303
+ $ExpressionToParameter = " $ ( $CommandElement.Extent.Text ) -#-$ExpectedType . Now the type is $StaticType .(Static) "
234
304
return $ExpressionToParameter
235
305
}
236
306
}
@@ -272,7 +342,12 @@ function Measure-ParameterNameAndValue {
272
342
273
343
if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst ]) {
274
344
[System.Management.Automation.Language.AssignmentStatementAst ]$AssignmentStatementAst = $Ast
275
- $global :AssignmentLeftAndRight .($AssignmentStatementAst.Left.Extent.Text ) = $AssignmentStatementAst.Right
345
+ if ($AssignmentStatementAst.Left -is [System.Management.Automation.Language.ConvertExpressionAst ]){
346
+ $global :AssignmentLeftAndRight .($AssignmentStatementAst.Left.Child.Extent.Text ) = $AssignmentStatementAst.Left.Type
347
+ }
348
+ elseif ($AssignmentStatementAst.Left -is [System.Management.Automation.Language.VariableExpressionAst ]){
349
+ $global :AssignmentLeftAndRight .($AssignmentStatementAst.Left.Extent.Text ) = $AssignmentStatementAst.Right
350
+ }
276
351
}
277
352
278
353
if ($Ast -is [System.Management.Automation.Language.CommandElementAst ] -and $Ast.Parent -is [System.Management.Automation.Language.CommandAst ]) {
@@ -669,4 +744,4 @@ function Measure-ParameterNameAndValue {
669
744
}
670
745
}
671
746
672
- Export-ModuleMember - Function Measure-*
747
+ Export-ModuleMember - Function Measure-*
0 commit comments