Skip to content

Commit a2fff13

Browse files
author
quoctruong
committed
Merge pull request #18 from PowerShell/suppression
Add prototype for suppressing rule
2 parents 995fb21 + c3961fb commit a2fff13

File tree

8 files changed

+442
-27
lines changed

8 files changed

+442
-27
lines changed

Engine/Commands/InvokeScriptAnalyzerCommand.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ private void AnalyzeFile(string filePath)
257257
Token[] tokens = null;
258258
ParseError[] errors = null;
259259
List<DiagnosticRecord> diagnostics = new List<DiagnosticRecord>();
260+
260261
IEnumerable<Ast> funcDefAsts;
261262

262263
// Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash
@@ -291,6 +292,8 @@ private void AnalyzeFile(string filePath)
291292
return;
292293
}
293294

295+
Dictionary<string, List<RuleSuppression>> ruleSuppressions = Helper.Instance.GetRuleSuppression(ast);
296+
294297
#region Run VariableAnalysis
295298
try
296299
{
@@ -317,11 +320,11 @@ private void AnalyzeFile(string filePath)
317320
// We want the Engine to continue functioning even if one or more Rules throws an exception
318321
try
319322
{
320-
diagnostics.AddRange(scriptRule.AnalyzeScript(ast, filePath));
323+
diagnostics.AddRange(Helper.Instance.SuppressRule(scriptRule.GetName(), ruleSuppressions, scriptRule.AnalyzeScript(ast, filePath).ToList()));
321324
}
322325
catch (Exception scriptRuleException)
323326
{
324-
WriteError(new ErrorRecord(scriptRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
327+
WriteError(new ErrorRecord(scriptRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
325328
continue;
326329
}
327330
}
@@ -382,7 +385,7 @@ private void AnalyzeFile(string filePath)
382385
}
383386
catch (Exception commandRuleException)
384387
{
385-
WriteError(new ErrorRecord(commandRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
388+
WriteError(new ErrorRecord(commandRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, fileName));
386389
continue;
387390
}
388391
}
@@ -411,7 +414,7 @@ private void AnalyzeFile(string filePath)
411414
}
412415
catch (Exception tokenRuleException)
413416
{
414-
WriteError(new ErrorRecord(tokenRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
417+
WriteError(new ErrorRecord(tokenRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, fileName));
415418
continue;
416419
}
417420
}
@@ -439,7 +442,7 @@ private void AnalyzeFile(string filePath)
439442
}
440443
catch (Exception dscResourceRuleException)
441444
{
442-
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
445+
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
443446
continue;
444447
}
445448
}
@@ -481,7 +484,7 @@ private void AnalyzeFile(string filePath)
481484
}
482485
catch (Exception dscResourceRuleException)
483486
{
484-
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
487+
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
485488
continue;
486489
}
487490
}
@@ -516,7 +519,7 @@ private void AnalyzeFile(string filePath)
516519
}
517520
catch (Exception externalRuleException)
518521
{
519-
WriteError(new ErrorRecord(externalRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
522+
WriteError(new ErrorRecord(externalRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, fileName));
520523
}
521524
}
522525
}

Engine/Generic/DiagnosticRecord.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class DiagnosticRecord
1818
private string ruleName;
1919
private DiagnosticSeverity severity;
2020
private string scriptName;
21+
private string ruleSuppressionId;
2122

2223
/// <summary>
2324
/// Represents a string from the rule about why this diagnostic was created.
@@ -62,7 +63,16 @@ public string ScriptName
6263
{
6364
get { return scriptName; }
6465
//Trim down to the leaf element of the filePath and pass it to Diagnostic Record
65-
set { scriptName = System.IO.Path.GetFileName(value); ; }
66+
set { scriptName = System.IO.Path.GetFileName(value); }
67+
}
68+
69+
/// <summary>
70+
/// Returns the rule id for this record
71+
/// </summary>
72+
public string RuleSuppressionID
73+
{
74+
get { return ruleSuppressionId; }
75+
set { ruleSuppressionId = value; }
6676
}
6777

6878
/// <summary>
@@ -81,13 +91,14 @@ public DiagnosticRecord()
8191
/// <param name="ruleName">The name of the rule that created this diagnostic</param>
8292
/// <param name="severity">The severity of this diagnostic</param>
8393
/// <param name="scriptName">The name of the script file being analyzed</param>
84-
public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptName)
94+
public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptName, string ruleId = null)
8595
{
8696
Message = string.IsNullOrEmpty(message) ? string.Empty : message;
8797
RuleName = string.IsNullOrEmpty(ruleName) ? string.Empty : ruleName;
8898
Extent = extent;
8999
Severity = severity;
90100
ScriptName = string.IsNullOrEmpty(scriptName) ? string.Empty : scriptName;
101+
ruleSuppressionId = ruleId;
91102
}
92103
}
93104

Engine/Generic/RuleSuppression.cs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Linq;
3+
using System.Management.Automation.Language;
4+
using System.Collections.Generic;
5+
6+
namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Generic
7+
{
8+
/// <summary>
9+
///
10+
/// </summary>
11+
public class RuleSuppression
12+
{
13+
/// <summary>
14+
/// The start offset of the rule suppression
15+
/// </summary>
16+
public int StartOffset
17+
{
18+
get;
19+
set;
20+
}
21+
22+
/// <summary>
23+
/// The end offset of the rule suppression
24+
/// </summary>
25+
public int EndOffset
26+
{
27+
get;
28+
set;
29+
}
30+
31+
/// <summary>
32+
/// Name of the rule being suppressed
33+
/// </summary>
34+
public string RuleName
35+
{
36+
get;
37+
set;
38+
}
39+
40+
/// <summary>
41+
/// ID of the violation instance
42+
/// </summary>
43+
public string RuleSuppressionID
44+
{
45+
get;
46+
set;
47+
}
48+
49+
/// <summary>
50+
/// Returns error occurred in trying to parse the attribute
51+
/// </summary>
52+
public string Error
53+
{
54+
get;
55+
set;
56+
}
57+
58+
/// <summary>
59+
/// Returns rule suppression from an attribute ast that has the type suppressmessageattribute
60+
/// </summary>
61+
/// <param name="attrAst"></param>
62+
/// <param name="start"></param>
63+
/// <param name="end"></param>
64+
public RuleSuppression(AttributeAst attrAst, int start, int end)
65+
{
66+
Error = String.Empty;
67+
68+
if (attrAst != null)
69+
{
70+
var positionalArguments = attrAst.PositionalArguments;
71+
var namedArguments = attrAst.NamedArguments;
72+
73+
int lastPositionalArgumentsOffset = -1;
74+
75+
if (positionalArguments != null && positionalArguments.Count != 0)
76+
{
77+
int count = positionalArguments.Count;
78+
lastPositionalArgumentsOffset = positionalArguments[positionalArguments.Count - 1].Extent.StartOffset;
79+
80+
if (positionalArguments.Any(item => !(item is StringConstantExpressionAst)))
81+
{
82+
Error = Strings.StringConstantArgumentsSuppressionAttributeError;
83+
}
84+
else
85+
{
86+
switch (count)
87+
{
88+
case 2:
89+
RuleSuppressionID = (positionalArguments[1] as StringConstantExpressionAst).Value;
90+
goto case 1;
91+
92+
case 1:
93+
RuleName = (positionalArguments[0] as StringConstantExpressionAst).Value;
94+
goto default;
95+
96+
default:
97+
break;
98+
}
99+
}
100+
}
101+
102+
if (namedArguments != null && namedArguments.Count != 0)
103+
{
104+
foreach (var name in namedArguments)
105+
{
106+
if (name.Extent.StartOffset < lastPositionalArgumentsOffset)
107+
{
108+
Error = Strings.NamedArgumentsBeforePositionalError;
109+
break;
110+
}
111+
else if (!(name.Argument is StringConstantExpressionAst))
112+
{
113+
Error = Strings.StringConstantArgumentsSuppressionAttributeError;
114+
break;
115+
}
116+
117+
switch (name.ArgumentName.ToLower())
118+
{
119+
case "rulename":
120+
if (!String.IsNullOrWhiteSpace(RuleName))
121+
{
122+
Error = String.Format(Strings.NamedAndPositionalArgumentsConflictError, name);
123+
}
124+
125+
RuleName = (name.Argument as StringConstantExpressionAst).Value;
126+
goto default;
127+
128+
case "rulesuppressionid":
129+
if (!String.IsNullOrWhiteSpace(RuleSuppressionID))
130+
{
131+
Error = String.Format(Strings.NamedAndPositionalArgumentsConflictError, name);
132+
}
133+
134+
RuleSuppressionID = (name.Argument as StringConstantExpressionAst).Value;
135+
goto default;
136+
137+
default:
138+
break;
139+
}
140+
}
141+
}
142+
}
143+
144+
StartOffset = start;
145+
EndOffset = end;
146+
}
147+
148+
/// <summary>
149+
/// Given a list of attribute asts, return a list of rule suppression
150+
/// with startoffset at start and endoffset at end
151+
/// </summary>
152+
/// <param name="attrAsts"></param>
153+
/// <param name="start"></param>
154+
/// <param name="end"></param>
155+
/// <returns></returns>
156+
public static List<RuleSuppression> GetSuppressions(IEnumerable<AttributeAst> attrAsts, int start, int end)
157+
{
158+
List<RuleSuppression> result = new List<RuleSuppression>();
159+
160+
if (attrAsts == null)
161+
{
162+
return result;
163+
}
164+
165+
IEnumerable<AttributeAst> suppressionAttribute = attrAsts.Where(
166+
item => item.TypeName.GetReflectionType() == typeof(System.Diagnostics.CodeAnalysis.SuppressMessageAttribute));
167+
168+
foreach (var attributeAst in suppressionAttribute)
169+
{
170+
RuleSuppression ruleSupp = new RuleSuppression(attributeAst, start, end);
171+
172+
if (string.IsNullOrWhiteSpace(ruleSupp.Error))
173+
{
174+
result.Add(ruleSupp);
175+
}
176+
}
177+
178+
return result;
179+
}
180+
}
181+
}

0 commit comments

Comments
 (0)