Skip to content

Commit 278d4fd

Browse files
author
Kapil Borle
authored
Fix PSShouldProcess rule violation extents (#668)
* Fix PSShouldProcess rule violation extents For the case when only the SupportsShouldProcess attribute is present but the call ShouldProcess is absent the violation extent covers only the attribute. For the case when only the ShouldProcess call is present but not the SupportsShouldProcess attribute, the violation extent covers only the ShouldProcess call. * Add tests to check PSShouldProcess violation extent
1 parent f87274d commit 278d4fd

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

Rules/UseShouldProcessCorrectly.cs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ public SourceType GetSourceType()
107107
return SourceType.Builtin;
108108
}
109109

110+
/// <summary>
111+
/// GetSourceName: Retrieves the module/assembly name the rule is from.
112+
/// </summary>
113+
public string GetSourceName()
114+
{
115+
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
116+
}
117+
110118
/// <summary>
111119
/// GetSeverity: Retrieves the severity of the rule: error, warning of information.
112120
/// </summary>
@@ -116,12 +124,9 @@ public RuleSeverity GetSeverity()
116124
return RuleSeverity.Warning;
117125
}
118126

119-
/// <summary>
120-
/// GetSourceName: Retrieves the module/assembly name the rule is from.
121-
/// </summary>
122-
public string GetSourceName()
127+
private DiagnosticSeverity GetDianosticSeverity()
123128
{
124-
return string.Format(CultureInfo.CurrentCulture,Strings.SourceName);
129+
return DiagnosticSeverity.Warning;
125130
}
126131

127132
/// <summary>
@@ -164,9 +169,9 @@ private DiagnosticRecord GetViolation(Vertex v)
164169
CultureInfo.CurrentCulture,
165170
Strings.ShouldProcessErrorHasAttribute,
166171
fast.Name),
167-
ast.Extent,
172+
Helper.Instance.GetShouldProcessAttributeAst(fast.Body.ParamBlock.Attributes).Extent,
168173
GetName(),
169-
DiagnosticSeverity.Warning,
174+
GetDianosticSeverity(),
170175
ast.Extent.File);
171176
}
172177
}
@@ -187,16 +192,55 @@ private DiagnosticRecord GetViolation(Vertex v)
187192
CultureInfo.CurrentCulture,
188193
Strings.ShouldProcessErrorHasCmdlet,
189194
fast.Name),
190-
v.Ast.Extent,
195+
GetShouldProcessCallExtent(fast),
191196
GetName(),
192-
DiagnosticSeverity.Warning,
197+
GetDianosticSeverity(),
193198
fileName);
194199
}
195200
}
196201

197202
return null;
198203
}
199204

205+
/// <summary>
206+
/// Gets the extent of ShouldProcess call
207+
/// </summary>
208+
private static IScriptExtent GetShouldProcessCallExtent(FunctionDefinitionAst functionDefinitionAst)
209+
{
210+
var invokeMemberExpressionAstFound = functionDefinitionAst.Find(IsShouldProcessCall, true);
211+
if (invokeMemberExpressionAstFound == null)
212+
{
213+
return functionDefinitionAst.Extent;
214+
}
215+
216+
return (invokeMemberExpressionAstFound as InvokeMemberExpressionAst).Member.Extent;
217+
}
218+
219+
/// <summary>
220+
/// Returns true if ast if of the form $PSCmdlet.PSShouldProcess()
221+
/// </summary>
222+
private static bool IsShouldProcessCall(Ast ast)
223+
{
224+
var invokeMemberExpressionAst = ast as InvokeMemberExpressionAst;
225+
if (invokeMemberExpressionAst == null)
226+
{
227+
return false;
228+
}
229+
230+
var memberExprAst = invokeMemberExpressionAst.Member as StringConstantExpressionAst;
231+
if (memberExprAst == null)
232+
{
233+
return false;
234+
}
235+
236+
if ("ShouldProcess".Equals(memberExprAst.Value, StringComparison.OrdinalIgnoreCase))
237+
{
238+
return true;
239+
}
240+
241+
return false;
242+
}
243+
200244
private bool callsShouldProcessDirectly(Vertex vertex)
201245
{
202246
return funcDigraph.GetNeighbors(vertex).Contains(shouldProcessVertex);

Tests/Rules/UseShouldProcessCorrectly.tests.ps1

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,31 @@ function Install-ModuleWithDeps {
246246
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -IncludeRule PSShouldProcess
247247
$violations.Count | Should Be 0
248248
}
249+
}
250+
251+
Context "Violation Extent" {
252+
It "should mark only the SupportsShouldProcess attribute" {
253+
$scriptDef = @'
254+
function Foo
255+
{
256+
[CmdletBinding(SupportsShouldProcess)]
257+
param()
258+
}
259+
'@
260+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -IncludeRule PSShouldProcess
261+
$violations[0].Extent.Text | Should Be 'SupportsShouldProcess'
262+
}
249263

264+
It "should mark only the ShouldProcess call" {
265+
$scriptDef = @'
266+
function Foo
267+
{
268+
param()
269+
if ($PSCmdlet.ShouldProcess('','')) { Write-Output "Should Process" }
270+
}
271+
'@
272+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -IncludeRule PSShouldProcess
273+
$violations[0].Extent.Text | Should Be 'ShouldProcess'
274+
}
250275
}
251276
}

0 commit comments

Comments
 (0)