-
Notifications
You must be signed in to change notification settings - Fork 394
Warn when using FileRedirection operator inside if/while statements and improve new PossibleIncorrectUsageOfAssignmentOperator rule #881
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
JamesWTruher
merged 26 commits into
PowerShell:development
from
bergmeister:WarnPipelineInsideIfStatement
Apr 9, 2018
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
4a0485c
first working prototype that warns against usage of the redirection o…
bergmeister 2c0bc28
adapt error message strings and add tests
bergmeister 29c7e34
remove old todo comment
bergmeister 7310387
remove duplicated test case
bergmeister 4078e41
syntax fix from last cleanup commits
bergmeister b7ad069
tweak extents in error message: for equal sign warnings, it will poin…
bergmeister 8a48a62
Enhance check for assignment by rather checking if assigned variable …
bergmeister c9d510f
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister fd339f6
tweak messages and readme
bergmeister 5e8a8be
Merge branch 'WarnPipelineInsideIfStatement' of https://github.com/be…
bergmeister c74a746
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister b467d10
update to pester v4 syntax
bergmeister 594414f
Revert to not check assigned variable usage of RHS but add optional c…
bergmeister c4e242e
Minor fix resource variable naming
bergmeister f7ce114
uncommented accidental comment out of ipmo pssa in tests
bergmeister bc00213
do not exclude BinaryExpressionAst on RHS because this case is the ch…
bergmeister c6c4f4a
update test to test against clang suppression
bergmeister 691f2ce
make clang suppression work again
bergmeister fe30f4d
reword warning text to use 'equality operator' instead of 'equals ope…
bergmeister 78ef4bf
Always warn when LHS is $null
bergmeister 675e3eb
Enhance PossibleIncorrectUsageOfAssignmentOperator rule to do the sam…
bergmeister ad008cd
tweak message to be more generic in terms of the conditional statement
bergmeister d042f37
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister f530d75
Address PR comments
bergmeister ed95d84
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister bdf39ac
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
54 changes: 54 additions & 0 deletions
54
RuleDocumentation/PossibleIncorrectUsageOAssignmentOperator.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# PossibleIncorrectUsageOfAssignmentOperator | ||
|
||
**Severity Level: Information** | ||
|
||
## Description | ||
|
||
In many programming languages, the equality operator is denoted as `==` or `=` in many programming languages, but `PowerShell` uses `-eq`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high. | ||
|
||
The rule looks for usages of `==` and `=` operators inside `if`, `else if`, `while` and `do-while` statements but it will not warn if any kind of command or expression is used at the right hand side as this is probably by design. | ||
|
||
## Example | ||
|
||
### Wrong | ||
|
||
```` PowerShell | ||
if ($a = $b) | ||
{ | ||
... | ||
} | ||
```` | ||
|
||
```` PowerShell | ||
if ($a == $b) | ||
{ | ||
|
||
} | ||
```` | ||
|
||
### Correct | ||
|
||
```` PowerShell | ||
if ($a -eq $b) # Compare $a with $b | ||
{ | ||
... | ||
} | ||
```` | ||
|
||
```` PowerShell | ||
if ($a = Get-Something) # Only execute action if command returns something and assign result to variable | ||
{ | ||
Do-SomethingWith $a | ||
} | ||
```` | ||
|
||
## Implicit suppresion using Clang style | ||
|
||
There are some rare cases where assignment of variable inside an if statement is by design. Instead of suppression the rule, one can also signal that assignment was intentional by wrapping the expression in extra parenthesis. An exception for this is when `$null` is used on the LHS is used because there is no use case for this. | ||
|
||
```` powershell | ||
if (($shortVariableName = $SuperLongVariableName['SpecialItem']['AnotherItem'])) | ||
{ | ||
... | ||
} | ||
```` |
7 changes: 0 additions & 7 deletions
7
RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md
This file was deleted.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# PossibleIncorrectUsageOfRedirectionOperator | ||
|
||
**Severity Level: Information** | ||
|
||
## Description | ||
|
||
In many programming languages, the comparison operator for 'greater than' is `>` but `PowerShell` uses `-gt` for it and `-ge` (greater or equal) for `>=`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high. | ||
|
||
The rule looks for usages of `>` or `>=` operators inside if, elseif, while and do-while statements because this is likely going to be unintentional usage. | ||
|
||
## Example | ||
|
||
### Wrong | ||
|
||
```` PowerShell | ||
if ($a > $b) | ||
{ | ||
... | ||
} | ||
```` | ||
|
||
### Correct | ||
|
||
```` PowerShell | ||
if ($a -gt $b) | ||
{ | ||
... | ||
} | ||
```` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Management.Automation.Language; | ||
|
||
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer | ||
{ | ||
/// <summary> | ||
/// The idea behind clang suppresion style is to wrap a statement in extra parenthesis to implicitly suppress warnings of its content to signal that the offending operation was deliberate. | ||
/// </summary> | ||
internal static class ClangSuppresion | ||
{ | ||
/// <summary> | ||
/// The community requested an implicit suppression mechanism that follows the clang style where warnings are not issued if the expression is wrapped in extra parenthesis. | ||
/// See here for details: https://github.com/Microsoft/clang/blob/349091162fcf2211a2e55cf81db934978e1c4f0c/test/SemaCXX/warn-assignment-condition.cpp#L15-L18 | ||
/// </summary> | ||
/// <param name="scriptExtent"></param> | ||
/// <returns></returns> | ||
internal static bool ScriptExtendIsWrappedInParenthesis(IScriptExtent scriptExtent) | ||
{ | ||
return scriptExtent.Text.StartsWith("(") && scriptExtent.Text.EndsWith(")"); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic; | ||
using System; | ||
using System.Collections.Generic; | ||
#if !CORECLR | ||
using System.ComponentModel.Composition; | ||
#endif | ||
using System.Management.Automation.Language; | ||
using System.Globalization; | ||
|
||
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules | ||
{ | ||
/// <summary> | ||
/// PossibleIncorrectUsageOfRedirectionOperator: Warn if someone uses '>' or '>=' inside an if, elseif, while or do-while statement because in most cases that is not the intention. | ||
/// The origin of this rule is that people often forget that operators change when switching between different languages such as C# and PowerShell. | ||
/// </summary> | ||
#if !CORECLR | ||
[Export(typeof(IScriptRule))] | ||
#endif | ||
public class PossibleIncorrectUsageOfRedirectionOperator : AstVisitor, IScriptRule | ||
{ | ||
/// <summary> | ||
/// The idea is to get all FileRedirectionAst inside all IfStatementAst clauses. | ||
/// </summary> | ||
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) | ||
{ | ||
if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); | ||
|
||
var ifStatementAsts = ast.FindAll(testAst => testAst is IfStatementAst, searchNestedScriptBlocks: true); | ||
foreach (IfStatementAst ifStatementAst in ifStatementAsts) | ||
{ | ||
foreach (var clause in ifStatementAst.Clauses) | ||
{ | ||
var fileRedirectionAst = clause.Item1.Find(testAst => testAst is FileRedirectionAst, searchNestedScriptBlocks: false) as FileRedirectionAst; | ||
if (fileRedirectionAst != null) | ||
{ | ||
yield return new DiagnosticRecord( | ||
Strings.PossibleIncorrectUsageOfRedirectionOperatorError, fileRedirectionAst.Extent, | ||
GetName(), DiagnosticSeverity.Warning, fileName); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// GetName: Retrieves the name of this rule. | ||
/// </summary> | ||
/// <returns>The name of this rule</returns> | ||
public string GetName() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.PossibleIncorrectUsageOfRedirectionOperatorName); | ||
} | ||
|
||
/// <summary> | ||
/// GetCommonName: Retrieves the common name of this rule. | ||
/// </summary> | ||
/// <returns>The common name of this rule</returns> | ||
public string GetCommonName() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.PossibleIncorrectUsageOfRedirectionOperatorCommonName); | ||
} | ||
|
||
/// <summary> | ||
/// GetDescription: Retrieves the description of this rule. | ||
/// </summary> | ||
/// <returns>The description of this rule</returns> | ||
public string GetDescription() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.PossibleIncorrectUsageOfRedirectionOperatorDescription); | ||
} | ||
|
||
/// <summary> | ||
/// GetSourceType: Retrieves the type of the rule: builtin, managed or module. | ||
/// </summary> | ||
public SourceType GetSourceType() | ||
{ | ||
return SourceType.Builtin; | ||
} | ||
|
||
/// <summary> | ||
/// GetSeverity: Retrieves the severity of the rule: error, warning of information. | ||
/// </summary> | ||
/// <returns></returns> | ||
public RuleSeverity GetSeverity() | ||
{ | ||
return RuleSeverity.Warning; | ||
} | ||
|
||
/// <summary> | ||
/// GetSourceName: Retrieves the module/assembly name the rule is from. | ||
/// </summary> | ||
public string GetSourceName() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still even in this case we might want to only compare the variable with the function result. Shouldn't we give some warning message as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know what you mean but it was a strong desire of the community to not see warnings when assignment is by design as this is a common use case. See referenced issue and there was also a discussion on the testing channel in Slack. I can sort of understand this fear/annoyance of people about false positives, especially given that one cannot suppress on a per-line basis in PSSA. I guess it is better to warn in most cases and help save the developer time rather than always warning and annoying the developer.