-
Notifications
You must be signed in to change notification settings - Fork 395
Add the AvoidExclaimOperator rule to warn about the use of the ! negation operator. Fixes #1826 #1922
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
Merged
Add the AvoidExclaimOperator rule to warn about the use of the ! negation operator. Fixes #1826 #1922
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
fd926e3
Added the AvoidExclamationPointOperator rule to warn about the use of…
liamjpeters 16ba414
Updated license header of Rules/AvoidExclamationPointOperator.cs
liamjpeters 01633c5
Updated the description of the rule in docs
liamjpeters 1edbcf1
Fix alignment
liamjpeters 69af14f
Update Rules/Strings.resx
liamjpeters 5e1b945
Renamed rule from AvoidExclamationPointOperator to AvoidExclaimOperator
liamjpeters eb1deed
Added comment explanation of the replacement suggestion logic and ren…
liamjpeters 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
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,144 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
#if !CORECLR | ||
using System.ComponentModel.Composition; | ||
#endif | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Management.Automation; | ||
using System.Management.Automation.Language; | ||
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic; | ||
|
||
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules | ||
{ | ||
/// <summary> | ||
/// AvoidExclamationPointOperator: Checks for use of the exclamation point operator | ||
/// </summary> | ||
#if !CORECLR | ||
[Export(typeof(IScriptRule))] | ||
#endif | ||
public class AvoidExclamationPointOperator : ConfigurableRule | ||
{ | ||
|
||
/// <summary> | ||
/// Construct an object of AvoidExclamationPointOperator type. | ||
/// </summary> | ||
public AvoidExclamationPointOperator() { | ||
Enable = false; | ||
} | ||
|
||
/// <summary> | ||
/// Analyzes the given ast to find the [violation] | ||
/// </summary> | ||
/// <param name="ast">AST to be analyzed. This should be non-null</param> | ||
/// <param name="fileName">Name of file that corresponds to the input AST.</param> | ||
/// <returns>A an enumerable type containing the violations</returns> | ||
public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) | ||
{ | ||
if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); | ||
|
||
var diagnosticRecords = new List<DiagnosticRecord>(); | ||
|
||
IEnumerable<Ast> foundAsts = ast.FindAll(testAst => testAst is UnaryExpressionAst, true); | ||
if (foundAsts != null) { | ||
var CorrectionDescription = Strings.AvoidExclamationPointOperatorCorrectionDescription; | ||
foreach (UnaryExpressionAst foundAst in foundAsts) { | ||
if (foundAst.TokenKind == TokenKind.Exclaim) { | ||
// If the exclaim is not followed by a space, add one | ||
var replaceWith = "-not"; | ||
if (foundAst.Child != null && foundAst.Child.Extent.StartColumnNumber == foundAst.Extent.StartColumnNumber + 1) { | ||
liamjpeters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
replaceWith = "-not "; | ||
} | ||
var corrections = new List<CorrectionExtent> { | ||
new CorrectionExtent( | ||
foundAst.Extent.StartLineNumber, | ||
foundAst.Extent.EndLineNumber, | ||
foundAst.Extent.StartColumnNumber, | ||
foundAst.Extent.StartColumnNumber + 1, | ||
replaceWith, | ||
fileName, | ||
CorrectionDescription | ||
) | ||
}; | ||
diagnosticRecords.Add(new DiagnosticRecord( | ||
string.Format( | ||
CultureInfo.CurrentCulture, | ||
Strings.AvoidExclamationPointOperatorError | ||
), | ||
foundAst.Extent, | ||
GetName(), | ||
GetDiagnosticSeverity(), | ||
fileName, | ||
suggestedCorrections: corrections | ||
)); | ||
} | ||
} | ||
} | ||
return diagnosticRecords; | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the common name of this rule. | ||
/// </summary> | ||
public override string GetCommonName() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidExclamationPointOperatorCommonName); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the description of this rule. | ||
/// </summary> | ||
public override string GetDescription() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidExclamationPointOperatorDescription); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the name of this rule. | ||
/// </summary> | ||
public override string GetName() | ||
{ | ||
return string.Format( | ||
CultureInfo.CurrentCulture, | ||
Strings.NameSpaceFormat, | ||
GetSourceName(), | ||
Strings.AvoidExclamationPointOperatorName); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the severity of the rule: error, warning or information. | ||
/// </summary> | ||
public override RuleSeverity GetSeverity() | ||
{ | ||
return RuleSeverity.Warning; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the severity of the returned diagnostic record: error, warning, or information. | ||
/// </summary> | ||
/// <returns></returns> | ||
public DiagnosticSeverity GetDiagnosticSeverity() | ||
{ | ||
return DiagnosticSeverity.Warning; | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the name of the module/assembly the rule is from. | ||
/// </summary> | ||
public override string GetSourceName() | ||
{ | ||
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieves the type of the rule, Builtin, Managed or Module. | ||
/// </summary> | ||
public override SourceType GetSourceType() | ||
{ | ||
return SourceType.Builtin; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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 @@ | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. | ||
|
||
BeforeAll { | ||
$ruleName = "PSAvoidExclamationPointOperator" | ||
|
||
$ruleSettings = @{ | ||
Enable = $true | ||
} | ||
$settings = @{ | ||
IncludeRules = @($ruleName) | ||
Rules = @{ $ruleName = $ruleSettings } | ||
} | ||
} | ||
|
||
Describe "AvoidExclamationPointOperator" { | ||
Context "When the rule is not enabled explicitly" { | ||
It "Should not find violations" { | ||
$def = '!$true' | ||
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def | ||
$violations.Count | Should -Be 0 | ||
} | ||
} | ||
|
||
Context "Given a line with the exclamation point operator" { | ||
It "Should find one violation" { | ||
$def = '!$true' | ||
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | ||
$violations.Count | Should -Be 1 | ||
} | ||
} | ||
|
||
Context "Given a line with the exclamation point operator" { | ||
It "Should replace the exclamation point operator with the -not operator" { | ||
$def = '!$true' | ||
$expected = '-not $true' | ||
Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected | ||
} | ||
} | ||
Context "Given a line with the exclamation point operator followed by a space" { | ||
It "Should replace the exclamation point operator without adding an additional space" { | ||
$def = '! $true' | ||
$expected = '-not $true' | ||
Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected | ||
} | ||
} | ||
Context "Given a line with a string containing an exclamation point" { | ||
It "Should not replace it" { | ||
$def = '$MyVar = "Should not replace!"' | ||
$expected = '$MyVar = "Should not replace!"' | ||
Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected | ||
} | ||
} | ||
} |
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,44 @@ | ||
--- | ||
description: Avoid exclamation point operator | ||
ms.custom: PSSA v1.21.0 | ||
ms.date: 06/14/2023 | ||
ms.topic: reference | ||
title: AvoidExclamationPointOperator | ||
--- | ||
# AvoidExclamationPointOperator | ||
**Severity Level: Warning** | ||
|
||
## Description | ||
|
||
The negation operator ! should not be used. Use -not instead. | ||
liamjpeters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
**Note**: This rule is not enabled by default. The user needs to enable it through settings. | ||
|
||
## How to Fix | ||
|
||
## Example | ||
### Wrong: | ||
```PowerShell | ||
$MyVar = !$true | ||
``` | ||
|
||
### Correct: | ||
```PowerShell | ||
$MyVar = -not $true | ||
``` | ||
|
||
## Configuration | ||
|
||
```powershell | ||
Rules = @{ | ||
PSAvoidExclamationPointOperator = @{ | ||
Enable = $true | ||
liamjpeters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
``` | ||
|
||
### Parameters | ||
|
||
#### Enable: bool (Default value is `$false`) | ||
|
||
Enable or disable the rule during ScriptAnalyzer invocation. |
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
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.
Uh oh!
There was an error while loading. Please reload this page.