Skip to content

Merge features from Development to Master #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 44 commits into from
Apr 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2fe54a4
Add rulesuppression class to store rule suppression info
Apr 8, 2015
463a9c8
Add rulesuppression class to store rule suppression info
Apr 8, 2015
f681f8a
Merge branch 'suppression' of https://github.com/PowerShell/PSScriptA…
Apr 9, 2015
51a8d37
Implement suppressing rule for function
Apr 9, 2015
1831861
Add rulesuppression class to store rule suppression info
Apr 8, 2015
14b5f18
Implement suppressing rule for function
Apr 9, 2015
509daa3
Merge branch 'suppression' of https://github.com/PowerShell/PSScriptA…
Apr 9, 2015
d3b6b75
Add rule suppression for classes and functions in classes
Apr 9, 2015
45d669f
Merge branch 'suppression' of https://github.com/PowerShell/ScriptAna…
Apr 9, 2015
4c7020f
Add rulesuppression class to store rule suppression info
Apr 8, 2015
77a0ee1
Implement suppressing rule for function
Apr 9, 2015
2f17d84
Add rulesuppression class to store rule suppression info
Apr 8, 2015
e3baed7
Implement suppressing rule for function
Apr 9, 2015
1f0927c
Add rule suppression for classes and functions in classes
Apr 9, 2015
d4e04ec
Add support for rule suppression id with uninitializedvariable
Apr 9, 2015
75d3557
merge with suppression
Apr 9, 2015
1558425
Add support for file level suppression
Apr 9, 2015
68a59ef
Add the Strings.Designer.cs class
Apr 9, 2015
c3961fb
Add null checks
Apr 9, 2015
a2fff13
Merge pull request #18 from PowerShell/suppression
Apr 9, 2015
9c868d3
Remove ICommandRule
Apr 10, 2015
99956f2
Merge pull request #21 from PowerShell/removeicommandrule
Apr 10, 2015
93f1a54
Change RuleSuppressionID of UninitializedVariable
Apr 10, 2015
0c1a1cc
Add Scope and Target argument to rule suppression
Apr 13, 2015
a79f723
Add tests for rule suppressions
Apr 13, 2015
5fea714
Write errors to the terminal when there are rule suppression errors
Apr 14, 2015
82af169
Merge pull request #24 from PowerShell/suppression
Apr 14, 2015
6e87b94
Add license to RuleSuppression
Apr 14, 2015
3567d12
Fix typo of error outputted for rule suppression
Apr 16, 2015
228b727
Apply rule suppression for DSC and Token rules
Apr 17, 2015
5597ceb
Fix rule suppression does not work when the one of the value is null
Apr 17, 2015
b8fab37
Fix a bug where rule suppression is turned off after it is applied last
Apr 20, 2015
d6d35b6
Throw error if target cannot be found for rulesuppression
Apr 20, 2015
6ab5099
Raise error if Rule Suppression ID is used but no match is found
Apr 20, 2015
cd8176e
Add RuleSuppressionIDs for rules
Apr 20, 2015
68caca9
Merge pull request #45 from PowerShell/suppression
Apr 20, 2015
048f585
Add IgnoreCase for RuleSuppression regex
Apr 21, 2015
fbbe414
Change the RuleSuppression infrastructure to support getting suppress…
Apr 21, 2015
284f527
Separate suppressed and non-suppressed records
Apr 21, 2015
f1086f5
Format suppressed messages output
Apr 22, 2015
b0fb70f
Edit format and types ps1xml files for SuppressedRecord class
Apr 22, 2015
4d64baf
Remove mandatory = false from SuppressedOnly
Apr 22, 2015
9a972fe
Merge pull request #56 from PowerShell/justificationprototype
Apr 22, 2015
dff7c8d
Merge BugFixes into development
Apr 23, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 61 additions & 92 deletions Engine/Commands/InvokeScriptAnalyzerCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,18 @@ public SwitchParameter Recurse
}
private bool recurse;

/// <summary>
/// ShowSuppressed: Show the suppressed message
/// </summary>
[Parameter(Mandatory = false)]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public SwitchParameter SuppressedOnly
{
get { return suppressedOnly; }
set { suppressedOnly = value; }
}
private bool suppressedOnly;

#endregion Parameters

#region Private Members
Expand Down Expand Up @@ -183,7 +195,6 @@ protected override void BeginProcessing()
#region Verify rules

rules = ScriptAnalyzer.Instance.ScriptRules.Union<IRule>(
ScriptAnalyzer.Instance.CommandRules).Union<IRule>(
ScriptAnalyzer.Instance.TokenRules).Union<IRule>(
ScriptAnalyzer.Instance.ExternalRules ?? Enumerable.Empty<IExternalRule>());

Expand Down Expand Up @@ -270,7 +281,7 @@ private void AnalyzeFile(string filePath)
Token[] tokens = null;
ParseError[] errors = null;
List<DiagnosticRecord> diagnostics = new List<DiagnosticRecord>();
IEnumerable<Ast> funcDefAsts;
List<SuppressedRecord> suppressed = new List<SuppressedRecord>();

// Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash
List<KeyValuePair<CommandInfo, IScriptExtent>> cmdInfoTable = new List<KeyValuePair<CommandInfo, IScriptExtent>>();
Expand Down Expand Up @@ -325,6 +336,19 @@ private void AnalyzeFile(string filePath)
return;
}

Dictionary<string, List<RuleSuppression>> ruleSuppressions = Helper.Instance.GetRuleSuppression(ast);

foreach (List<RuleSuppression> ruleSuppressionsList in ruleSuppressions.Values)
{
foreach (RuleSuppression ruleSuppression in ruleSuppressionsList)
{
if (!String.IsNullOrWhiteSpace(ruleSuppression.Error))
{
WriteError(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
}
}
}

#region Run VariableAnalysis
try
{
Expand Down Expand Up @@ -353,6 +377,7 @@ private void AnalyzeFile(string filePath)
break;
}
}

foreach (Regex exclude in excludeRegexList)
{
if (exclude.IsMatch(scriptRule.GetName()))
Expand All @@ -361,97 +386,22 @@ private void AnalyzeFile(string filePath)
break;
}
}
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))

if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
{
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, scriptRule.GetName()));

// Ensure that any unhandled errors from Rules are converted to non-terminating errors
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
diagnostics.AddRange(scriptRule.AnalyzeScript(ast, filePath));
var records = Helper.Instance.SuppressRule(scriptRule.GetName(), ruleSuppressions, scriptRule.AnalyzeScript(ast, filePath).ToList());
diagnostics.AddRange(records.Item2);
suppressed.AddRange(records.Item1);
}
catch (Exception scriptRuleException)
{
WriteError(new ErrorRecord(scriptRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
}
}
}
}

#endregion

#region Run Command Rules

funcDefAsts = ast.FindAll(new Func<Ast, bool>((testAst) => (testAst is FunctionDefinitionAst)), true);
if (funcDefAsts != null)
{
foreach (FunctionDefinitionAst funcDefAst in funcDefAsts)
{
//Create command info object here
var sb = new StringBuilder();
sb.AppendLine(funcDefAst.Extent.Text);
sb.AppendFormat("Get-Command –CommandType Function –Name {0}", funcDefAst.Name);

var funcDefPS = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
funcDefPS.AddScript(sb.ToString());

try
{
var commandInfo = funcDefPS.Invoke<CommandInfo>();

foreach (CommandInfo cmdInfo in commandInfo)
{
cmdInfoTable.Add(new KeyValuePair<CommandInfo, IScriptExtent>(cmdInfo as CommandInfo, funcDefAst.Extent));
}
}
catch (ParseException)
{
WriteError(new ErrorRecord(new CommandNotFoundException(),
string.Format(CultureInfo.CurrentCulture, Strings.CommandInfoNotFound, funcDefAst.Name),
ErrorCategory.SyntaxError, funcDefAst));
}
}
}

if (ScriptAnalyzer.Instance.CommandRules != null)
{
foreach (ICommandRule commandRule in ScriptAnalyzer.Instance.CommandRules)
{
bool includeRegexMatch = false;
bool excludeRegexMatch = false;
foreach (Regex include in includeRegexList)
{
if (include.IsMatch(commandRule.GetName()))
{
includeRegexMatch = true;
break;
}
}
foreach (Regex exclude in excludeRegexList)
{
if (exclude.IsMatch(commandRule.GetName()))
{
excludeRegexMatch = true;
break;
}
}
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
{
foreach (KeyValuePair<CommandInfo, IScriptExtent> commandInfo in cmdInfoTable)
{
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, commandRule.GetName()));

// Ensure that any unhandled errors from Rules are converted to non-terminating errors
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
diagnostics.AddRange(commandRule.AnalyzeCommand(commandInfo.Key, commandInfo.Value, fileName));
}
catch (Exception commandRuleException)
{
WriteError(new ErrorRecord(commandRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
}
WriteError(new ErrorRecord(scriptRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
}
}
}
Expand Down Expand Up @@ -491,11 +441,13 @@ private void AnalyzeFile(string filePath)
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
diagnostics.AddRange(tokenRule.AnalyzeTokens(tokens, fileName));
var records = Helper.Instance.SuppressRule(tokenRule.GetName(), ruleSuppressions, tokenRule.AnalyzeTokens(tokens, filePath).ToList());
diagnostics.AddRange(records.Item2);
suppressed.AddRange(records.Item1);
}
catch (Exception tokenRuleException)
{
WriteError(new ErrorRecord(tokenRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
WriteError(new ErrorRecord(tokenRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, fileName));
}
}
}
Expand All @@ -511,6 +463,7 @@ private void AnalyzeFile(string filePath)
{
bool includeRegexMatch = false;
bool excludeRegexMatch = false;

foreach (Regex include in includeRegexList)
{
if (include.IsMatch(dscResourceRule.GetName()))
Expand All @@ -519,6 +472,7 @@ private void AnalyzeFile(string filePath)
break;
}
}

foreach (Regex exclude in excludeRegexList)
{
if (exclude.IsMatch(dscResourceRule.GetName()))
Expand All @@ -527,6 +481,7 @@ private void AnalyzeFile(string filePath)
break;
}
}

if ((includeRule == null || includeRegexMatch) && (excludeRule == null || excludeRegexMatch))
{
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, dscResourceRule.GetName()));
Expand All @@ -535,11 +490,13 @@ private void AnalyzeFile(string filePath)
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
diagnostics.AddRange(dscResourceRule.AnalyzeDSCClass(ast, filePath));
var records = Helper.Instance.SuppressRule(dscResourceRule.GetName(), ruleSuppressions, dscResourceRule.AnalyzeDSCClass(ast, filePath).ToList());
diagnostics.AddRange(records.Item2);
suppressed.AddRange(records.Item1);
}
catch (Exception dscResourceRuleException)
{
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
}
}
}
Expand Down Expand Up @@ -592,11 +549,13 @@ private void AnalyzeFile(string filePath)
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
diagnostics.AddRange(dscResourceRule.AnalyzeDSCResource(ast, filePath));
var records = Helper.Instance.SuppressRule(dscResourceRule.GetName(), ruleSuppressions, dscResourceRule.AnalyzeDSCResource(ast, filePath).ToList());
diagnostics.AddRange(records.Item2);
suppressed.AddRange(records.Item1);
}
catch (Exception dscResourceRuleException)
{
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, filePath));
}
}
}
Expand Down Expand Up @@ -630,7 +589,7 @@ private void AnalyzeFile(string filePath)
}
catch (Exception externalRuleException)
{
WriteError(new ErrorRecord(externalRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
WriteError(new ErrorRecord(externalRuleException, Strings.RuleErrorMessage, ErrorCategory.InvalidOperation, fileName));
}
}
}
Expand All @@ -649,9 +608,19 @@ private void AnalyzeFile(string filePath)
//Output through loggers
foreach (ILogger logger in ScriptAnalyzer.Instance.Loggers)
{
foreach (DiagnosticRecord diagnostic in diagnostics)
if (SuppressedOnly)
{
logger.LogMessage(diagnostic, this);
foreach (DiagnosticRecord suppressRecord in suppressed)
{
logger.LogObject(suppressRecord, this);
}
}
else
{
foreach (DiagnosticRecord diagnostic in diagnostics)
{
logger.LogObject(diagnostic, this);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Engine/Generic/AvoidParameterGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
{
if (ParameterCondition(cmdAst, ceAst))
{
yield return new DiagnosticRecord(GetError(fileName, cmdAst), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
yield return new DiagnosticRecord(GetError(fileName, cmdAst), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, cmdAst.GetCommandName());
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions Engine/Generic/DiagnosticRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class DiagnosticRecord
private string ruleName;
private DiagnosticSeverity severity;
private string scriptName;
private string ruleSuppressionId;

/// <summary>
/// Represents a string from the rule about why this diagnostic was created.
Expand Down Expand Up @@ -74,7 +75,16 @@ public string ScriptName
{
get { return scriptName; }
//Trim down to the leaf element of the filePath and pass it to Diagnostic Record
set { scriptName = System.IO.Path.GetFileName(value); ; }
set { scriptName = System.IO.Path.GetFileName(value); }
}

/// <summary>
/// Returns the rule id for this record
/// </summary>
public string RuleSuppressionID
{
get { return ruleSuppressionId; }
set { ruleSuppressionId = value; }
}

/// <summary>
Expand All @@ -93,13 +103,14 @@ public DiagnosticRecord()
/// <param name="ruleName">The name of the rule that created this diagnostic</param>
/// <param name="severity">The severity of this diagnostic</param>
/// <param name="scriptName">The name of the script file being analyzed</param>
public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptName)
public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptName, string ruleId = null)
{
Message = string.IsNullOrEmpty(message) ? string.Empty : message;
RuleName = string.IsNullOrEmpty(ruleName) ? string.Empty : ruleName;
Extent = extent;
Severity = severity;
ScriptName = string.IsNullOrEmpty(scriptName) ? string.Empty : scriptName;
ruleSuppressionId = ruleId;
}
}

Expand Down
37 changes: 0 additions & 37 deletions Engine/Generic/ICommandRule.cs

This file was deleted.

4 changes: 2 additions & 2 deletions Engine/Generic/ILogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public interface ILogger
/// <summary>
/// LogMessage: Logs the given diagnostic, using the command for Write methods if needed.
/// </summary>
/// <param name="diagnostic">The DiagnosticRecord to be logged.</param>
/// <param name="obj">The object to be logged.</param>
/// <param name="command">The InvokePSScriptAnalyzerCommand that this logger is running off of.</param>
void LogMessage(DiagnosticRecord diagnostic, InvokeScriptAnalyzerCommand command);
void LogObject(Object obj, InvokeScriptAnalyzerCommand command);

/// <summary>
/// GetName: Retrieves the name of the logger.
Expand Down
Loading