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

Unable to suppress rules in an advanced function when there is no Param block #1930

Closed
fourpastmidnight opened this issue Aug 15, 2023 · 2 comments

Comments

@fourpastmidnight
Copy link

Overview

I was able to successfully suppress the violation of PSUseSingularNouns for two functions within a script using the SuppressMessageAttribute. But a third function will not suppress even with the presence of the SuppressMessageAttribute.

Steps to reproduce

  1. Use a PSScriptAnalyzer configuration file with the following contents:

    @{
        Severity = @('Warning', 'Error')
        IncludeRules = @('PSUseSingularNouns')
    }
  2. Use the following contents for a script file to be analyzed with PSScriptAnalyzer.

    # SUCCESS: The rule flags this, but there's explicit code looking for the word 'data' and such a
    # violation is suppressed. However, without the SuppressMessageAttribute, this function is flagged by
    # PSScriptAnalyzer v1.21.0
    function Get-QueueMessageMetadata {
        [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
        [CmdletBinding()]
        Param ( <# Doesn't matter #> )
        Begin { }
    }
    
    # SUCCESS: The rule flags this, but the SuppressMessageAttribute successfully suppresses a diagnostic
    # from being returned.
    function Start-EmptyQueuesAndStopServices {
        [CmdletBinding()]
        [Diagnostics.CodeAanalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
        Param ( <# Doesn't matter #> )
        Begin { }
    }
    
    # ALWAYS FLAGS: I tried four variations of using SuppressMessageAttribute and it WILL NOT suppress!
    #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Target='Get-QueuesWithMessages')]
    #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns, '', Target='Get-QueuesWithMessages', Scope='Function')]
    #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns, '', Target='Get-QueuesWithMessages', Scope='Script')]
    function Get-QueuesWithMesasges {
        #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Target='Get-QueuesWithMessages')]
        [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')]
        [CmdletBinding()]
        Begin { }
    }
  3. PSScriptAnalyzer returns a violation of the PSUseSingularNouns rule for the last function in the script file above even though a suppression attribute exists. And of course, I tried several variations with no success.

It took me quite a while to spot this since I'm so familiar with the code I'm working on. But notice that the last function DOES NOT declare a Param ( ) block! Once I added an empty Param ( ) block, no more violations were reported.

I do not believe this is expected behavior because unless your function requires parameters (or simply, doesn't name them), none of my resources say that the Param ( ) block is required for advanced functions. Additionally, it looks like PowerShell may be parsing the SuppressMessageAttribute as decorating the Begin { } block instead of being a "decorator of" the enclosing function.

As an aside, it has always bothered me how attributes for functions are placed inside the function declaration, instead of directly above it as it's done in C#. So, if anything, it looks like a PowerShell parser ambiguity here. Does the attribute decorate the enclosing function, or the block within? Adding a Param ( ) block to the function, it would seem, resolves the parser ambiguity. I even tried putting the [CmdletBinding()] attribute declaration below the SuppressMessageAttribute declaration, but the unexpected behavior remains.

Now that I think about this, this issue probably does not belong on the PSScriptAnalyzer repo, but with the PowerShell repo, proper. Let me know if I should post this issue on that repository instead, as it's most likely that the PSScriptAnalyzer team can do anything to PSScriptAnalyzer to "fix" this.

Expected behavior

I expect that if my function does not need parameters, the Param ( ) block can be omitted and that the SuppressMessageAttribute would still be associated with the function as it is for all other PowerShell functions so that the PSUseSingularNouns rule is suppressed on the affected function.

Actual behavior

PSScriptAnalyzer does not suppress this rule and emits a diagnostic record for the affected function. I suspect the attribute is not "decorating" the right block during parsing--being applied to the Begin { } block rather than the enclosing function.

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.4.0-preview.3
PSEdition                      Core
GitCommitId                    7.4.0-preview.3
OS                             Microsoft Windows 10.0.19042
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }

1.21.0
@SydneyhSmith
Copy link
Collaborator

Thanks @fourpastmidnight for taking the time to spend this issue, and for providing such detailed information. PowerShell (rather than PSSA) does the parsing, and applies the attribute accordingly, because there is no param statement what you are seeing is the PowerShell expected behavior. Unfortunately this is not something we can solve for right now on the PSSA level-- PowerShell would need to solve this. The workaround is to use an empty param block (as you did). Thanks!

@fourpastmidnight
Copy link
Author

@SydneyhSmith Thanks for confirming that this is a PowerShell parsing "issue" (at least, a parsing ambiguity with respect to how attributes are applied in PowerShell).

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

No branches or pull requests

2 participants