- 
                Notifications
    
You must be signed in to change notification settings  - Fork 403
 
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.