Skip to content

Commit

Permalink
Merge pull request #298 from PowerShell/development
Browse files Browse the repository at this point in the history
Dev to Master
  • Loading branch information
raghushantha committed Aug 26, 2015
2 parents 8cbf460 + 0b0626e commit 61b8454
Show file tree
Hide file tree
Showing 32 changed files with 306 additions and 56 deletions.
File renamed without changes.
11 changes: 11 additions & 0 deletions Engine/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,17 @@ public bool IsDscResourceModule(string filePath)
return false;
}

/// <summary>
/// Given a filePath. Returns true if it is a powershell help file
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public bool IsHelpFile(string filePath)
{
return filePath != null && File.Exists(filePath) && Path.GetFileName(filePath).StartsWith("about_", StringComparison.OrdinalIgnoreCase)
&& Path.GetFileName(filePath).EndsWith(".help.txt", StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Given an AST, checks whether dsc resource is class based or not
/// </summary>
Expand Down
121 changes: 74 additions & 47 deletions Engine/ScriptAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -908,9 +908,9 @@ private void BuildScriptPathList(
bool searchRecursively,
IList<string> scriptFilePaths)
{
const string ps1Suffix = "ps1";
const string psm1Suffix = "psm1";
const string psd1Suffix = "psd1";
const string ps1Suffix = ".ps1";
const string psm1Suffix = ".psm1";
const string psd1Suffix = ".psd1";

if (Directory.Exists(path))
{
Expand All @@ -935,9 +935,14 @@ private void BuildScriptPathList(
}
else if (File.Exists(path))
{
if ((path.Length > ps1Suffix.Length && path.Substring(path.Length - ps1Suffix.Length).Equals(ps1Suffix, StringComparison.OrdinalIgnoreCase)) ||
(path.Length > psm1Suffix.Length && path.Substring(path.Length - psm1Suffix.Length).Equals(psm1Suffix, StringComparison.OrdinalIgnoreCase)) ||
(path.Length > psd1Suffix.Length && path.Substring(path.Length - psd1Suffix.Length).Equals(psd1Suffix, StringComparison.OrdinalIgnoreCase)))
String fileName = Path.GetFileName(path);
if ((fileName.Length > ps1Suffix.Length && String.Equals(Path.GetExtension(path), ps1Suffix, StringComparison.OrdinalIgnoreCase)) ||
(fileName.Length > psm1Suffix.Length && String.Equals(Path.GetExtension(path), psm1Suffix, StringComparison.OrdinalIgnoreCase)) ||
(fileName.Length > psd1Suffix.Length && String.Equals(Path.GetExtension(path), psd1Suffix, StringComparison.OrdinalIgnoreCase)))
{
scriptFilePaths.Add(path);
}
else if (Helper.Instance.IsHelpFile(path))
{
scriptFilePaths.Add(path);
}
Expand All @@ -964,7 +969,28 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
//Parse the file
if (File.Exists(filePath))
{
scriptAst = Parser.ParseFile(filePath, out scriptTokens, out errors);
// processing for non help script
if (!(Path.GetFileName(filePath).StartsWith("about_") && Path.GetFileName(filePath).EndsWith(".help.txt")))
{
scriptAst = Parser.ParseFile(filePath, out scriptTokens, out errors);

if (errors != null && errors.Length > 0)
{
foreach (ParseError error in errors)
{
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorFormat, error.Extent.File, error.Message.TrimEnd('.'), error.Extent.StartLineNumber, error.Extent.StartColumnNumber);
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, error.ErrorId));
}
}

if (errors.Length > 10)
{
string manyParseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorMessage, System.IO.Path.GetFileName(filePath));
this.outputWriter.WriteError(new ErrorRecord(new ParseException(manyParseErrorMessage), manyParseErrorMessage, ErrorCategory.ParserError, filePath));

return new List<DiagnosticRecord>();
}
}
}
else
{
Expand All @@ -975,23 +1001,6 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
return null;
}

if (errors != null && errors.Length > 0)
{
foreach (ParseError error in errors)
{
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorFormat, error.Extent.File, error.Message.TrimEnd('.'), error.Extent.StartLineNumber, error.Extent.StartColumnNumber);
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, error.ErrorId));
}
}

if (errors.Length > 10)
{
string manyParseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorMessage, System.IO.Path.GetFileName(filePath));
this.outputWriter.WriteError(new ErrorRecord(new ParseException(manyParseErrorMessage), manyParseErrorMessage, ErrorCategory.ParserError, filePath));

return new List<DiagnosticRecord>();
}

return this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath);
}

Expand All @@ -1007,36 +1016,41 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
Token[] scriptTokens,
string filePath)
{
Dictionary<string, List<RuleSuppression>> ruleSuppressions;
Dictionary<string, List<RuleSuppression>> ruleSuppressions = new Dictionary<string,List<RuleSuppression>>();
ConcurrentBag<DiagnosticRecord> diagnostics = new ConcurrentBag<DiagnosticRecord>();
ConcurrentBag<SuppressedRecord> suppressed = new ConcurrentBag<SuppressedRecord>();
BlockingCollection<List<object>> verboseOrErrors = new BlockingCollection<List<object>>();

// 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>>();

ruleSuppressions = Helper.Instance.GetRuleSuppression(scriptAst);
bool helpFile = (scriptAst == null) && Helper.Instance.IsHelpFile(filePath);

foreach (List<RuleSuppression> ruleSuppressionsList in ruleSuppressions.Values)
if (!helpFile)
{
foreach (RuleSuppression ruleSuppression in ruleSuppressionsList)
ruleSuppressions = Helper.Instance.GetRuleSuppression(scriptAst);

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

#region Run VariableAnalysis
try
{
Helper.Instance.InitializeVariableAnalysis(scriptAst);
}
catch { }
#endregion
#region Run VariableAnalysis
try
{
Helper.Instance.InitializeVariableAnalysis(scriptAst);
}
catch { }
#endregion

Helper.Instance.Tokens = scriptTokens;
Helper.Instance.Tokens = scriptTokens;
}

#region Run ScriptRules
//Trim down to the leaf element of the filePath and pass it to Diagnostic Record
Expand Down Expand Up @@ -1067,6 +1081,8 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
}
}
bool helpRule = String.Equals(scriptRule.GetName(), "PSUseUTF8EncodingForHelpFile", StringComparison.OrdinalIgnoreCase);
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
{
List<object> result = new List<object>();
Expand All @@ -1077,14 +1093,25 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
// We want the Engine to continue functioning even if one or more Rules throws an exception
try
{
var records = Helper.Instance.SuppressRule(scriptRule.GetName(), ruleSuppressions, scriptRule.AnalyzeScript(scriptAst, scriptAst.Extent.File).ToList());
foreach (var record in records.Item2)
if (helpRule && helpFile)
{
diagnostics.Add(record);
var records = scriptRule.AnalyzeScript(scriptAst, filePath);
foreach (var record in records)
{
diagnostics.Add(record);
}
}
foreach (var suppressedRec in records.Item1)
else if (!helpRule && !helpFile)
{
suppressed.Add(suppressedRec);
var records = Helper.Instance.SuppressRule(scriptRule.GetName(), ruleSuppressions, scriptRule.AnalyzeScript(scriptAst, scriptAst.Extent.File).ToList());
foreach (var record in records.Item2)
{
diagnostics.Add(record);
}
foreach (var suppressedRec in records.Item1)
{
suppressed.Add(suppressedRec);
}
}
}
catch (Exception scriptRuleException)
Expand Down Expand Up @@ -1122,7 +1149,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(

#region Run Token Rules

if (this.TokenRules != null)
if (this.TokenRules != null && !helpFile)
{
foreach (ITokenRule tokenRule in this.TokenRules)
{
Expand Down Expand Up @@ -1173,7 +1200,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
#endregion

#region DSC Resource Rules
if (this.DSCResourceRules != null)
if (this.DSCResourceRules != null && !helpFile)
{
// Invoke AnalyzeDSCClass only if the ast is a class based resource
if (Helper.Instance.IsDscResourceClassBased(scriptAst))
Expand Down Expand Up @@ -1282,7 +1309,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(

#region Run External Rules

if (this.ExternalRules != null)
if (this.ExternalRules != null && !helpFile)
{
List<ExternalRule> exRules = new List<ExternalRule>();

Expand Down
2 changes: 1 addition & 1 deletion Rules/ScriptAnalyzerBuiltinRules.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
<Compile Include="AvoidShouldContinueWithoutForce.cs" />
<Compile Include="AvoidUsingDeprecatedManifestFields.cs" />
<Compile Include="ProvideDefaultParameterValue.cs" />
<Compile Include="AvoidUninitializedVariable.cs" />
<Compile Include="AvoidUsernameAndPasswordParams.cs" />
<Compile Include="AvoidUsingComputerNameHardcoded.cs" />
<Compile Include="AvoidUsingConvertToSecureStringWithPlainText.cs" />
Expand Down Expand Up @@ -91,6 +90,7 @@
<Compile Include="UseShouldProcessForStateChangingFunctions.cs" />
<Compile Include="UseSingularNouns.cs" />
<Compile Include="UseStandardDSCFunctionsInResource.cs" />
<Compile Include="UseUTF8EncodingForHelpFile.cs" />
<Compile Include="ReturnCorrectTypesForDSCFunctions.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
38 changes: 37 additions & 1 deletion Rules/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Rules/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -732,4 +732,16 @@
<data name="AvoidUsingDeprecatedManifestFieldsName" xml:space="preserve">
<value>AvoidUsingDeprecatedManifestFields</value>
</data>
<data name="UseUTF8EncodingForHelpFileCommonName" xml:space="preserve">
<value>Use UTF8 Encoding For Help File</value>
</data>
<data name="UseUTF8EncodingForHelpFileDescription" xml:space="preserve">
<value>PowerShell help file needs to use UTF8 Encoding.</value>
</data>
<data name="UseUTF8EncodingForHelpFileError" xml:space="preserve">
<value>File {0} has to use UTF8 instead of {1} encoding because it is a powershell help file.</value>
</data>
<data name="UseUTF8EncodingForHelpFileName" xml:space="preserve">
<value>UseUTF8EncodingForHelpFile</value>
</data>
</root>
Loading

0 comments on commit 61b8454

Please sign in to comment.