Skip to content
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

Warn when using FileRedirection operator inside if/while statements and improve new PossibleIncorrectUsageOfAssignmentOperator rule #881

Merged

Conversation

bergmeister
Copy link
Collaborator

@bergmeister bergmeister commented Feb 8, 2018

PR Summary

Closes #878

  • Improve existing rule about assignment operator to also not trigger for more special cases like e.g. [NameSpace]::Method() or $b -match $c on the RHS of the if expression and add optional, implicit clang suppression when extra parenthesis are used.
  • Add new PossibleIncorrectUsageOfRedirectionOperator rule to warn when using > unintentionally inside if and elseif statements (e.g if ($a > $){ }).
  • Apply the same logic to while/do-while statements.

PR Checklist

Note: Tick the boxes below that apply to this pull request by putting an x between the square brackets. Please mark anything not applicable to this PR NA.

  • PR has a meaningful title
    • Use the present tense and imperative mood when describing your changes
  • Summarized changes
  • User facing documentation needed
  • Change is not breaking (because the rule is new and has not shipped yet)
  • Make sure you've added a new test if existing tests do not effectively test the code changed
  • This PR is ready to merge and is not work in progress.
    • If the PR is work in progress, please add the prefix WIP: to the beginning of the title and remove the prefix when the PR is ready

@@ -0,0 +1,7 @@
# PossibleIncorrectUsageOfComparisonOperator

**Severity Level: Information**
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering because we can determine pretty accurately know that the usage of the comparison operator inside if statements is unintentional, if we should up the level to warning because some people ignore/disable warnings of informational level?

@LaurentDardenne
Copy link

About the renaming of the rule,I think there are two different cases.
To separate these two cases, even if it shares the same code of analysis, would allow a granularity in the configuration.

This causes parsing errors:

if ($a > = $b){ "ok"} else { "nok"}

And this is valid:

if ($a >=){ "ok"} else { "nok"}

This rule can also be applied to 'While' and 'Do' statements.

For the level of the rule, it depends on the level of knowledge of the person.
In my opinion, this writing is reserved for people who know the associated behavior and implicit conversions.
I wonder if this rule will be of any use to them, since here this writing is intentional.
In this case the level 'Warning' will be considered too strict and the level 'Information' would be considered too verbose and useless, the rule will just confirm his intention :-).

For a beginner the level 'Warning' would be useful and the level 'Information' would be too risky if it configures the triggering of the rules on 'Warning'.

And it is easier with PSSA to exlude a rule than to configure its level of criticality.

"Since assignment inside if statements are very rare,"
Yes, but it depends on who :-)

Test with a module triggering 38 times this rule:

$r=Invoke-ScriptAnalyzer -path 'C:\Program Files\WindowsPowerShell\Modules\InvokeBuild\5.1.0'|
    where-object rulename -eq 'PSPossibleIncorrectUsageOfAssignmentOperator'
#------
$_ = ${*}.Data['Checkpoint.Import']
$r = ${*checkpoint}.Result
$file = $b['File']
$log = $b['Log']
$up = $PSCmdlet.SessionState.PSVariable.Get('*')
$f = [System.IO.Directory]::GetFiles($Path, '*.build.ps1')
$_ = $f -match '[\\/]\.build\.ps1$'
$_ = $env:InvokeBuildGetFile
$_ = $PSCmdlet.SessionState.PSVariable.Get('*')
$_ = $PSBoundParameters['Result']
$_ = $p.Name
$_ = ${*}.All[$Name]
$_ = ${*}.All[$Task]
$_ = $PSCmdlet.GetVariableValue(${*n})
$d = $Hash[$f]
$c = $d.C[$n]
$_ = $PSBoundParameters['Variable']
$$ = $PSCmdlet.GetVariableValue($_)
$_ = $PSBoundParameters['Environment']
$_ = $PSBoundParameters['Property']
$t = ${*}.All[$r]
$t = ${*}.All[$r]
$r = ${*}.All[$_]
${private:*i} = $Task.Inputs
${private:*x} = $Task.If
${*}.Q = $BuildTask -eq '?' -or $BuildTask -eq '??'
${**} = ${*}.All
$_ = $_.Error
$w = ${*}.Warnings
$_ = ${*}.P
$root = ${env:ProgramFiles(x86)}
$r = $paths -like '*\Enterprise\*'
$r = $paths -like '*\Professional\*'
$r = $paths -like '*\Community\*'
$r = $r.parameters
$r = $r.parameter
$d = $Hash[$f]
$c = $d.C[$n]

@JamesWTruher
Copy link
Member

while if ( $a >=) { "ok" } is parsable, it's probably not what you want, because a file named = will be created with the contents of $a

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 11, 2018

@LaurentDardenne

About the renaming of the rule,I think there are two different cases.
To separate these two cases, even if it shares the same code of analysis, would allow a granularity in the configuration.

The rule is for cases where the user simply forgets the right PowerShell syntax (due to context switching or because he/she is a newbie) and therefore I do not understand why someone would enable/disable only one of them if the rule were to be split into 2 rules. Can you please give an example/scenario where a split would be needed?

Parsing errors are OK and by design (they come from the PowerShell parses itself) and are a good signal to raise an early red flag because if a script does not parse then there is no point running the script at all and the error messages of the parses are good as well and even point to the right line where the problem happens. There is no point to catch parsing errors and do our own logic, we would be re-inventing the wheel.

"Since assignment inside if statements are very rare,"

Yes, but it depends on who :-)

The implementation of the rule is clever enough to not warn in those special cases scenarios where assignment is intentional.

This rule can also be applied to 'While' and 'Do' statements.

That's a good point. We should consider implementing the rule for those statements as well.

Your 38 examples do not trigger the rule for me (I even tried putting some of the lines in an if statement), but they do trigger PSUseDeclaredVarsMoreThanAssignments correctly, was this a mistake or can you elaborate please? Examples of false positives that repro would be very welcome.

@LaurentDardenne
Copy link

@bergmeister
Can you please give an example/scenario where a split would be needed?
It's more of a personal choice or a question of granularity.
In this discussion nightroman prefers this syntax :

if ($x = <something>) {

When I deliver code to a customer, I prefer it for maintenance / knowledge reasons :

$x = <something>
if ($x) {

For that I would like to have this rule with a level 'warning'.
People using the first, more concise syntax will prefer, I suppose, this rule with an 'information' level.

For this case :

if ($a > $b){ "ok"} else { "nok"}

I assume that the majority of people will consider this case as being of the warning level.

This is what makes me think that splitting these cases into two rules,the both with a 'warning' level , with could satisfy as many people as possible :

Invoke-ScriptAnalyzer -ExcludeRule 'PSPossibleIncorrectUsageOfAssignmentOperator' -IncludeRule 'PSPossibleIncorrectUsageOfRedirectionOperator'
Invoke-ScriptAnalyzer -IncludeRule 'PSPossibleIncorrectUsageOfAssignmentOperator','PSPossibleIncorrectUsageOfRedirectionOperator'
#or
Invoke-ScriptAnalyzer #default 

There is no point to catch parsing errors and do our own logic, we would be re-inventing the wheel.
We are talking about the same thing, but not in the same way :-)

Invoke-ScriptAnalyzer -ScriptDefinition 'if ($a > = $b){ "ok"} else { "nok"}'
# Invoke-ScriptAnalyzer : Parse error in script definition:  Unexpected token '$b' in expression or statement at line 1
# column 12.
# At line:1 char:1
# + Invoke-ScriptAnalyzer -ScriptDefinition 'if ($a > = $b){ "ok"} else { ...
# + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#     + CategoryInfo          : ParserError: (UnexpectedToken:String) [Invoke-ScriptAnalyzer], ParseException
#     + FullyQualifiedErrorId : Parse error in script definition:  Unexpected token '$b' in expression or statement at l
#    ine 1 column 12.,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand

What I wanted to say : it is not necessary to put this case in the tests because PSSA is waiting for a syntactically correct script.

Your 38 examples do not trigger the rule for me
I would check again with a development version posted in Appveyor. so we will be sure to use the same code.

ipmo PSScriptAnalyzer
$r=Invoke-ScriptAnalyzer -path 'C:\Program Files\WindowsPowerShell\Modules\InvokeBuild\5.1.0'|
    where rulename -eq 'PSPossibleIncorrectUsageOfAssignmentOperator'
$r.count
#38
$r[0]|select *
# 
# Line                 : 59
# Column               : 7
# Message              : Did you really mean to make an assignment inside an if statement? If you rather meant to check
#                        for equality, use the '-eq'  operator.
# Extent               : $_ = ${*}.Data['Checkpoint.Import']
# RuleName             : PSPossibleIncorrectUsageOfAssignmentOperator
# Severity             : Information
# ScriptName           : Build-Checkpoint.ps1
# ScriptPath           : C:\Program Files\WindowsPowerShell\Modules\InvokeBuild\5.1.0\Build-Checkpoint.ps1
# RuleSuppressionID    :
# SuggestedCorrections :

@bergmeister
Copy link
Collaborator Author

@LaurentDardenne I think you are missing a detail: The legitimate case if ($gotSomething = Get-MeSomething){ } will not trigger the rule and neither will if ($x){}. Only cases like if ($a=$b){} or if ($a>$b){} will, which is the reason why I am thinking of always treating it as a warning because the likelihood that it is an error is extremely high due and this is why I don't see the need for the split because the rule does not trigger false positives.
I do not have anything like if ($a > = $b) in the pester tests that I added because as we both agree, it throws a parser error. You must be referring to the test cases that I wrote in the corresponding issue, you can ignore them now because I wrote them only down to have a big picture of cases where a user might make a mistake.
About your 38 test cases. I build it locally using .\buildCoreClr.ps1 -Framework net451 -Configuration Release -Build; .\buildCoreClr.ps1 -Framework net451 -Configuration PSV3Release -Build; .\buildCoreClr.ps1 -Framework netstandard1.6 -Configuration Release -Build; .\build.ps1 -BuildDocs and then I import the psd1 in the out folder (using Windows PowerShell 5.1 or PowerShell Core) and it does not repro on my dev machine.
How are you building/using the PSSA version of my branch? I personally cannot use the artifacts from AppVeyor because I get this error when importing the psd1:

Import-Module : Could not load file or assembly 'file:///C:\Users\cberg\Downloads\psscriptanalyzer\out\PSScriptAnalyzer
\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll' or one of its dependencies. Operation is not supported. (Exception
from HRESULT: 0x80131515)
At C:\Users\cberg\Downloads\psscriptanalyzer\out\PSScriptAnalyzer\PSScriptAnalyzer.psm1:24 char:17
+ $binaryModule = Import-Module -Name $binaryModulePath -PassThru
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Import-Module], FileLoadException
    + FullyQualifiedErrorId : System.IO.FileLoadException,Microsoft.PowerShell.Commands.ImportModuleCommand

@LaurentDardenne
Copy link

... this is why I don't see the need for the split...
Ok.

How are you building/using the PSSA version of my branch?
I did not use the latest commited version.
Now, I use the zip file here
I compile it with VS studio 2017( VM in Azure) or with the build script.

cd C:\temp\pssa\out\PSScriptAnalyzer 
ipmo .\PSScriptAnalyzer.psd1
Invoke-ScriptAnalyzer -ScriptDefinition 'if ($root = ${env:ProgramFiles(x86)}) {}'
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfCompariso Information             1     Did you really mean to use the assignment operator
# nOperator                                                         '=' inside an if statement? If you rather meant to
#                                                                   check for equality, use the '-eq'  operator.
# PSUseDeclaredVarsMoreThanAssignment Warning                 1     The variable 'root' is assigned but never used.
# s

Invoke-ScriptAnalyzer -ScriptDefinition 'if ($root = get-nothing) {}'

# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSUseDeclaredVarsMoreThanAssignment Warning                 1     The variable 'root' is assigned but never used.
# s

Invoke-ScriptAnalyzer -ScriptDefinition 'if ($root > $b) {}'
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfCompariso Warning                 1     Did you really mean to use the redirection operator
# nOperator                                                         '>'? If you wanted to use an equality comparer then
#                                                                   use the '-gt' (greater than) or '-ge' (greater or
#                                                                   equal) operators.


Invoke-ScriptAnalyzer -ScriptDefinition 'if ($root > get-nothing) {}'
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfCompariso Warning                 1     Did you really mean to use the redirection operator
# nOperator                                                         '>'?   ...

Invoke-ScriptAnalyzer -ScriptDefinition 'if (get-nothing > $root) {}'
# 
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfAssignmen Warning                 1     Did you really mean to use the redirection operator
# tOperator                                                          '>'?   ...

…t to the equal sign (instead of the RHS only) and fore file redirections it will be the redirection ast (e.g. '> $b')
@bergmeister
Copy link
Collaborator Author

@LaurentDardenne Thanks for clarifying the repro, very helpful, I can repro now and will take a look at them.

@bergmeister bergmeister changed the title Warn when using FileRedirection operator inside if statement WIP: Warn when using FileRedirection operator inside if statement Feb 12, 2018
@LaurentDardenne
Copy link

One last remark on the presence of two rules.
In case I want to filter one of the cases for this code :

$sb={
 if ($root > $b) {}
 if ($root = ${env:ProgramFiles(x86)}) {}
}

I have to filter this way :

Invoke-ScriptAnalyzer -ScriptDefinition "$sb"|
 Where {($_.RuleName -eq 'PSPossibleIncorrectUsageOfComparisonOperator') -and ($_.Severity -ne 'Information')}
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfCompariso Warning                 2     Did you really mean to use the redirection operator
# nOperator                                                         '>'? If you wanted to use an equality comparer then

Until now this was enough :

Invoke-ScriptAnalyzer -ScriptDefinition "$sb" -ExcludeRule 'PSPossibleIncorrectUsageOf_AssignmentOperator'

Finally the deletion of the application of the rule, for one of the two cases, by the attribute SuppressMessage is not possible:

$sb={
function Test{
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSPossibleIncorrectUsageOfComparisonOperator', '')]
[CmdletBinding()]
 param ()
 if ($root > $b) {}
 if ($root = ${env:ProgramFiles(x86)}) {}
 }
}
Invoke-ScriptAnalyzer -ScriptDefinition "$sb"
#nothing

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 13, 2018

@LaurentDardenne I think I slowly start to understand your point of view and can see now how a split into 2 rules would be beneficial.
I also went through all your example samples and for cases of the form if ($a = $variableExperssionOfSomeForm){}, we could maybe be more clever about the surrounding script code and check if the variable is being used inside the statement block of the if statement as an approval that the assignment was intentional and then not trigger the rule. I managed to hack together a prototype here that does this!
This trick would allow me not having to try to detect the special cases of the form if ($a = InvokeExpressionInUsingSpecialSyntax)){}:

  • if ($_a= $PSCmdlet.SessionState.PSVariable.Get('*')){ } and similar
  • if (${*}.Q = $BuildTask -eq '?' -or $BuildTask -eq '??'){ }
  • if ($r = $paths -like '*\Enterprise\*'){ }
    What do you think about this approach of avoiding false positives?
    About the redirection operator: I think if the redirection operator is used inside an if statement then this must be by accident (since the variable on the left hand side will never get assigned). Can you give an example usage where using the > operator is intentional AND useful?
    Thanks for being patience and collaboration.

@LaurentDardenne
Copy link

LaurentDardenne commented Feb 14, 2018

@bergmeister
I also went through all your example samples
They come from the InvokeBuilder module, we can also consult the chapter 7.11 Assignment operators of language specifications .

Can you give an example usage where using the > operator is intentional AND useful?
No sorry, I never use this write option in an if statement.
I do not know the behavior of such a writing (case of lock on the file or of insufficient rights, with $ErrorActionPreference = 'SilentlyContinue', ...).

But maybe this for the assignment can occur :

 $Resgen="$psScriptRoot\ResGen.exe" 
 if ($ResultExec=.$Resgen $Source $Destination 2>&1) {}

It's not written like that in the original code and I wonder if this writing has an interest ...

What do you think about this approach of avoiding false positives?
Sounds good to me. That said, I think the problem here is not in the depth of analysis but the behavior expected by users.
If for

if ( $files = get-childitem )

@JamesWTruher consider that "There is a pattern which is very useful which will cause warnings to appear"
others consider that this:

if ( $A = $B )

is also a very useful pattern (see InvokeBuilder module) and others that it will always be an error.

Consider a trigger level configuration could cover these cases :

  • No trigger : everything is allowed, we respect the possibilities of the Powershell language. Is identical to the -ExcludeRule parameter.
  • Trigger for variable assignment only : if ($ A = $ B). Are allowed if ($ files = get-childitem) and derived expressions.
  • Trigger always : the mere presence of '=' into an If statement triggers the rule.

So we are no longer concerned about the intention it is the user who declares it.
Obviously it would be a global behavior and we could not change the behavior for a portion of code or for the entirety of a file (all except).

…is used in assignment block

to avoid false positives for assignments: check if variable on LHS is used in statement block
update documentation and change level to warning since we are now much more certain that a violation. is happening

Commits:

* prototype of detecting variable usage on LHS to avoid  false positives

* simplify and reduce nesting

* fix regression by continue statements

* fix last regression

* add simple test case for new improvemeent

* finish it off and adapt tests

* update docs

* minor style update

* fix typo

* fix test due to warning level change
@bergmeister bergmeister changed the title WIP: Warn when using FileRedirection operator inside if statement Warn when using FileRedirection operator inside if statement Feb 17, 2018
@bergmeister bergmeister self-assigned this Feb 17, 2018
@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 17, 2018

To avoid false positives for assignments I refactored the rule to check if the variable on LHS is used in statement block and if not, then warn. This should then not leave any false positive cases, therefore there is no need for a rule split any more and the level was bumped to be a warning. @LaurentDardenne Let me know if this works well for you now as well.

@LaurentDardenne
Copy link

@bergmeister
The contain of the Extend.Text property does not appear correctly, we lose the contents of the statement that triggers the error.
The PossibleIncorrectUsageOfComparisonOperator.md file should contain an explicit example :
($ a = $ b -> $ a -eq $ b)

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 20, 2018

The highlighting of the Extent.Text is chosen to be as close as possible to the operator is by design because this is where people should see the squigglies in VsCode.

$w=Invoke-ScriptAnalyzer -ScriptDefinition 'if($a > $b){}'
$w.Extent.Text
> $b
$w=Invoke-ScriptAnalyzer -ScriptDefinition 'if($a > $b){}'
$w.Extent.Text
=
$w=Invoke-ScriptAnalyzer -ScriptDefinition 'if($a == $b){}'
$w.Extent.Text
==

I have already added examples to the markdown file.

@imfrancisd
Copy link

@bergmeister

-More exceptions for PossibleIncorrectUsageOfAssignmentOperator to also exclude usage of [NameSpace]::Method() or $b -match $c on the RHS of the if expression. The rule should continue to warn if any kind of variable expression is on the RHS.

Is the exception of -match because it sometimes returns a boolean and sometimes it returns an array? If so, what about operators that are purely arithmetic and operators that are purely boolean?

    #Will this be flagged?
    #Common in loops with index.
    #
    if ($i = $array.Count -1) {}

    #Will this be flagged?
    #Common in functions with multiple switches to configure behavior.
    #
    if ($switch1 = ($switch2 -and $switch3)) {}

I think those lines should be flagged.

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 26, 2018

@imfrancisd The current exceptions to PossibleIncorrectUsageOfAssignmentOperator are if one of the following asts are present on the right hand side:

  • CommandAst (a powershell cmdlet/function)
  • InvokeMemberExpressionAst to include other function calls (.net methods or methods on object)
  • BinaryExpressionAst (operators, like -match, -and, -)
    So yes, your 2 examples would not get flagged due to them being a BinaryExpressionAst. The idea was that anything that is any sort of function or operation/transformation on data gets excluded because it could be by design. But I am happy to remove BinaryExpressionAst from the exclusion list because this case is much less likely to be an assignment by design (initially I was more thinking about operators like -match or -like but you are right that it is better to warn because it also includes basic operators where we get closer to the use case where assignment was more likely to be unintentional). Thanks for the feedback. :-)

…ance that it is by design is much smaller, therefore rather having some false positives is preferred
@LaurentDardenne
Copy link

I do not find this use case in the test file :

Invoke-ScriptAnalyzer -ScriptDefinition 'if ( ($a=$b) ){}'

@bergmeister bergmeister changed the title Warn when using FileRedirection operator inside if statement and improve new PossibleIncorrectUsageOfAssignmentOperator rule WIP Warn when using FileRedirection operator inside if statement and improve new PossibleIncorrectUsageOfAssignmentOperator rule Feb 26, 2018
@bergmeister
Copy link
Collaborator Author

Thanks @LaurentDardenne for spotting that, I fixed it. It seems I was unlucky to introduce a regression both in the implementation and test when doing the final refactoring.

@bergmeister bergmeister changed the title WIP Warn when using FileRedirection operator inside if statement and improve new PossibleIncorrectUsageOfAssignmentOperator rule Warn when using FileRedirection operator inside if statement and improve new PossibleIncorrectUsageOfAssignmentOperator rule Feb 26, 2018
@bergmeister bergmeister added this to the 1.17 milestone Feb 26, 2018
@LaurentDardenne
Copy link

@bergmeister
Only those who do nothing make no mistakes ;-)

@LaurentDardenne
Copy link

Should not the second example fail, even if we use () ?

Invoke-ScriptAnalyzer -ScriptDefinition 'if ($_ == $_.Error) {}'
# RuleName                            Severity     ScriptName Line  Message
# --------                            --------     ---------- ----  -------
# PSPossibleIncorrectUsageOfAssignmen Warning                 1     Did you mean to use the assignment operator '='? The
# tOperator                                                         equals operator in PowerShell is 'eq'.

Invoke-ScriptAnalyzer -ScriptDefinition 'if (($_ == $_.Error)) {}'
#no warning

typo in the error message :

...The equals operator in PowerShell is '-eq'.

@bergmeister
Copy link
Collaborator Author

@LaurentDardenne The clang style extra parenthesis are a way of letting the author state implicitly that assignment is deliberate and by design forPSPossibleIncorrectUsageOfAssignmentOperatorwithout "having to litter the code with suppressions"(that was what people said in the Slack forums, which is understandable, especially since we cannot suppress one line/statement only at the moment).
I changed the warning text to rather use the term equality operator, I just used the other expression because to me it is the equal/equals operator because that's what the -eq stands for.

@imfrancisd
Copy link

@bergmeister What do you think about "if ($null = )"?

Shouldn't they always be flagged?

Command : invoke-scriptanalyzer -script 'if ($null = $b) {}'
Output  : 
          RuleName                            Severity     ScriptName Line  Message                                                     
          --------                            --------     ---------- ----  -------                                                     
          PSPossibleIncorrectUsageOfAssignmen Information             1     Did you mean to use the assignment operator '='? The        
          tOperator                                                         equality operator in PowerShell is 'eq'.                    
          
          
          

Command : invoke-scriptanalyzer -script 'if ($null = [string]::Empty) {}'
Output  : 
          RuleName                            Severity     ScriptName Line  Message                                                     
          --------                            --------     ---------- ----  -------                                                     
          PSPossibleIncorrectUsageOfAssignmen Information             1     Did you mean to use the assignment operator '='? The        
          tOperator                                                         equality operator in PowerShell is 'eq'.                    
          
          
          

Command : invoke-scriptanalyzer -script 'if ($null = [string]::Concat($a, $b)) {}'
Output  : 

Command : invoke-scriptanalyzer -script 'if ($null = $hashtable.Count) {}'
Output  : 
          RuleName                            Severity     ScriptName Line  Message                                                     
          --------                            --------     ---------- ----  -------                                                     
          PSPossibleIncorrectUsageOfAssignmen Information             1     Did you mean to use the assignment operator '='? The        
          tOperator                                                         equality operator in PowerShell is 'eq'.                    
          
          
          

Command : invoke-scriptanalyzer -script 'if ($null = $hashtable["key"]) {}'
Output  : 
          RuleName                            Severity     ScriptName Line  Message                                                     
          --------                            --------     ---------- ----  -------                                                     
          PSPossibleIncorrectUsageOfAssignmen Information             1     Did you mean to use the assignment operator '='? The        
          tOperator                                                         equality operator in PowerShell is 'eq'.                    
          
          
          

Command : invoke-scriptanalyzer -script 'if ($null = $hashtable.Item("key")) {}'
Output  : 

Command : invoke-scriptanalyzer -script 'if ($null = get-childitem) {}'
Output  : 

Command : invoke-scriptanalyzer -script 'if ($null = (get-childitem)) {}'
Output  : 

Command : invoke-scriptanalyzer -script 'if ($null = $(get-childitem)) {}'
Output  : 

Command : invoke-scriptanalyzer -script 'if ($null = @(get-childitem)) {}'
Output  : 

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 28, 2018

@imfrancisd The rule currently does not inspect the LHS of the assignment, only the RHS. But it would be a good improvement because a common (recommended pattern) is to do comparison via $null -eq $foo and using $null on the LHS does not make sense inside an assignment, therefore I will consider this improvement. Thanks for contributing ideas. Does it look ready to you now since I would like to finish this PR soon. I think making the rule even more clever than it already is should be later separate PRs because to me it looks like we have no managed to get to a very good and relatively clever rule.

@imfrancisd
Copy link

@bergmeister

Does it look ready to you now since I would like to finish this PR soon.

I didn't know I had a say in the matter! :-)

Not my place to say. I just wander around GitHub issues from time to time and one day found myself here in pull request land.

…e analysis for while and do-while statements as well, which is the exact same use case as if statements
@bergmeister
Copy link
Collaborator Author

@JamesWTruher After community feedback I addressed it and implemented additional enhancements for special cases. To me the rule looks very polished now. Can you please re-review and give your opinion?

@bergmeister bergmeister changed the title Warn when using FileRedirection operator inside if statement and improve new PossibleIncorrectUsageOfAssignmentOperator rule Warn when using FileRedirection operator inside if/while statements and improve new PossibleIncorrectUsageOfAssignmentOperator rule Mar 15, 2018
Copy link
Contributor

@kalgiz kalgiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok in general, but I have some comments about possible extending rules.

````

```` PowerShell
if ($a = Get-Something) # Only execute action if command returns something and assign result to variable
Copy link
Contributor

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?

Copy link
Collaborator Author

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.

### Correct

```` PowerShell
if ($a -eq $b)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be -gt here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this makes more sense to someone reading the document and comparing wrong vs right. I will change that.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please finish the sentence with '.'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
{
/// <summary>
/// PossibleIncorrectUsageOfRedirectionOperator: Warn if someone uses '>' or '>=' inside an if or elseif statement because in most cases that is not the intention.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want it to work as well for While statements as PossibleIncorrectUsageOfAssignmentOperator ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually do, but the comment got out of date. I will fix that. I am following the current comment style but my feeling is that the codebase has too many repeated comments.

…nalyzer into WarnPipelineInsideIfStatement

resolved by taking both changes
# Conflicts:
#	Rules/Strings.resx
…nalyzer into WarnPipelineInsideIfStatement

resolve by taking head
# Conflicts:
#	Tests/Rules/PossibleIncorrectUsageOfAssignmentOperator.tests.ps1
Copy link
Member

@JamesWTruher JamesWTruher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good - eventually we will have line suppression, but for now the possibility of false positive outweighs the benefit of catching problems early.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants