From 3005e8ecdf94579ccddc9c42170c902ac497285a Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Oct 2020 18:50:43 +0100 Subject: [PATCH 1/8] First draft, needs debugging --- Rules/UseConsistentWhitespace.cs | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index aad4d3f46..bde411b2e 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -63,6 +63,9 @@ private List>> violationFind [ConfigurableRuleProperty(defaultValue: false)] public bool CheckParameter { get; protected set; } + [ConfigurableRuleProperty(defaultValue: true)] + public bool CheckUnaryOperatorWithDash { get; protected set; } + public override void ConfigureRule(IDictionary paramValueMap) { base.ConfigureRule(paramValueMap); @@ -95,6 +98,11 @@ public override void ConfigureRule(IDictionary paramValueMap) { violationFinders.Add(FindSeparatorViolations); } + + if (CheckUnaryOperatorWithDash) + { + violationFinders.Add(FindUnaryOperatorViolations); + } } /// @@ -362,6 +370,72 @@ private IEnumerable FindPipeViolations(TokenOperations tokenOp } } + private IEnumerable FindUnaryOperatorViolations(TokenOperations tokenOperations) + { + bool isUnaryOperatorWithDash(Token token) + { + return token.TokenFlags == TokenFlags.UnaryOperator && token.Text.StartsWith("-"); + } + + foreach (var unaryOperatorWithDash in tokenOperations.GetTokenNodes(token => isUnaryOperatorWithDash(token))) + { + if (unaryOperatorWithDash.Next == null + || !IsPreviousTokenOnSameLine(unaryOperatorWithDash) + || unaryOperatorWithDash.Next.Value.Kind == TokenKind.NewLine + || unaryOperatorWithDash.Next.Value.Kind == TokenKind.LineContinuation + ) + { + continue; + } + + if (!IsNextTokenApartByWhitespace(unaryOperatorWithDash, out bool hasRedundantWhitespace)) + { + // TODO put into if below: CheckPipeForRedundantWhitespace && hasRedundantWhitespace || + if (CheckUnaryOperatorWithDash && !hasRedundantWhitespace) + { + yield return new DiagnosticRecord( + GetError(ErrorKind.AfterPipe), + unaryOperatorWithDash.Value.Extent, + GetName(), + GetDiagnosticSeverity(), + tokenOperations.Ast.Extent.File, + null, + GetCorrections( + unaryOperatorWithDash.Previous.Value, unaryOperatorWithDash.Value, unaryOperatorWithDash.Next.Value, true, false) + .ToList()); + } + } + } + + // foreach (var pipe in tokenOperations.GetTokenNodes(TokenKind.Pipe)) + // { + // if (pipe.Previous == null + // || !IsPreviousTokenOnSameLine(pipe) + // || pipe.Previous.Value.Kind == TokenKind.Pipe + // || pipe.Previous.Value.Kind == TokenKind.NewLine + // || pipe.Previous.Value.Kind == TokenKind.LineContinuation + // ) + // { + // continue; + // } + + // if (!IsPreviousTokenApartByWhitespace(pipe, out bool hasRedundantWhitespace)) + // { + // if (CheckPipeForRedundantWhitespace && hasRedundantWhitespace || CheckUnaryOperatorWithDash && !hasRedundantWhitespace) + // { + // yield return new DiagnosticRecord( + // GetError(ErrorKind.BeforePipe), + // pipe.Value.Extent, + // GetName(), + // GetDiagnosticSeverity(), + // tokenOperations.Ast.Extent.File, + // null, + // GetCorrections(pipe.Previous.Value, pipe.Value, pipe.Next.Value, false, true).ToList()); + // } + // } + // } + } + private IEnumerable FindOpenParenViolations(TokenOperations tokenOperations) { foreach (var lparen in tokenOperations.GetTokenNodes(TokenKind.LParen)) From f4579dee1438b3db48aa246d40aa0f0d1dbe5613 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Oct 2020 20:32:24 +0100 Subject: [PATCH 2/8] re-user operator check --- Rules/UseConsistentWhitespace.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index bde411b2e..4a753d364 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -99,10 +99,10 @@ public override void ConfigureRule(IDictionary paramValueMap) violationFinders.Add(FindSeparatorViolations); } - if (CheckUnaryOperatorWithDash) - { - violationFinders.Add(FindUnaryOperatorViolations); - } + // if (CheckUnaryOperatorWithDash) + // { + // violationFinders.Add(FindUnaryOperatorViolations); + // } } /// @@ -199,6 +199,7 @@ private bool IsOperator(Token token) return TokenTraits.HasTrait(token.Kind, TokenFlags.AssignmentOperator) || TokenTraits.HasTrait(token.Kind, TokenFlags.BinaryPrecedenceAdd) || TokenTraits.HasTrait(token.Kind, TokenFlags.BinaryPrecedenceMultiply) + || TokenTraits.HasTrait(token.Kind, TokenFlags.UnaryOperator) && token.Text.StartsWith("-") || token.Kind == TokenKind.AndAnd || token.Kind == TokenKind.OrOr; } From 569ecf65c59e23f39f5cd6c4a18c3bd079a4acb4 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Oct 2020 22:03:46 +0100 Subject: [PATCH 3/8] cleanup --- Rules/UseConsistentWhitespace.cs | 73 -------------------------------- 1 file changed, 73 deletions(-) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index 4a753d364..c53921368 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -63,8 +63,6 @@ private List>> violationFind [ConfigurableRuleProperty(defaultValue: false)] public bool CheckParameter { get; protected set; } - [ConfigurableRuleProperty(defaultValue: true)] - public bool CheckUnaryOperatorWithDash { get; protected set; } public override void ConfigureRule(IDictionary paramValueMap) { @@ -98,11 +96,6 @@ public override void ConfigureRule(IDictionary paramValueMap) { violationFinders.Add(FindSeparatorViolations); } - - // if (CheckUnaryOperatorWithDash) - // { - // violationFinders.Add(FindUnaryOperatorViolations); - // } } /// @@ -371,72 +364,6 @@ private IEnumerable FindPipeViolations(TokenOperations tokenOp } } - private IEnumerable FindUnaryOperatorViolations(TokenOperations tokenOperations) - { - bool isUnaryOperatorWithDash(Token token) - { - return token.TokenFlags == TokenFlags.UnaryOperator && token.Text.StartsWith("-"); - } - - foreach (var unaryOperatorWithDash in tokenOperations.GetTokenNodes(token => isUnaryOperatorWithDash(token))) - { - if (unaryOperatorWithDash.Next == null - || !IsPreviousTokenOnSameLine(unaryOperatorWithDash) - || unaryOperatorWithDash.Next.Value.Kind == TokenKind.NewLine - || unaryOperatorWithDash.Next.Value.Kind == TokenKind.LineContinuation - ) - { - continue; - } - - if (!IsNextTokenApartByWhitespace(unaryOperatorWithDash, out bool hasRedundantWhitespace)) - { - // TODO put into if below: CheckPipeForRedundantWhitespace && hasRedundantWhitespace || - if (CheckUnaryOperatorWithDash && !hasRedundantWhitespace) - { - yield return new DiagnosticRecord( - GetError(ErrorKind.AfterPipe), - unaryOperatorWithDash.Value.Extent, - GetName(), - GetDiagnosticSeverity(), - tokenOperations.Ast.Extent.File, - null, - GetCorrections( - unaryOperatorWithDash.Previous.Value, unaryOperatorWithDash.Value, unaryOperatorWithDash.Next.Value, true, false) - .ToList()); - } - } - } - - // foreach (var pipe in tokenOperations.GetTokenNodes(TokenKind.Pipe)) - // { - // if (pipe.Previous == null - // || !IsPreviousTokenOnSameLine(pipe) - // || pipe.Previous.Value.Kind == TokenKind.Pipe - // || pipe.Previous.Value.Kind == TokenKind.NewLine - // || pipe.Previous.Value.Kind == TokenKind.LineContinuation - // ) - // { - // continue; - // } - - // if (!IsPreviousTokenApartByWhitespace(pipe, out bool hasRedundantWhitespace)) - // { - // if (CheckPipeForRedundantWhitespace && hasRedundantWhitespace || CheckUnaryOperatorWithDash && !hasRedundantWhitespace) - // { - // yield return new DiagnosticRecord( - // GetError(ErrorKind.BeforePipe), - // pipe.Value.Extent, - // GetName(), - // GetDiagnosticSeverity(), - // tokenOperations.Ast.Extent.File, - // null, - // GetCorrections(pipe.Previous.Value, pipe.Value, pipe.Next.Value, false, true).ToList()); - // } - // } - // } - } - private IEnumerable FindOpenParenViolations(TokenOperations tokenOperations) { foreach (var lparen in tokenOperations.GetTokenNodes(TokenKind.LParen)) From 2605f9b3e011b834459585e204e84434a1cee748 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Oct 2020 22:04:18 +0100 Subject: [PATCH 4/8] clean diff --- Rules/UseConsistentWhitespace.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index c53921368..7abe2c1a0 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -63,7 +63,6 @@ private List>> violationFind [ConfigurableRuleProperty(defaultValue: false)] public bool CheckParameter { get; protected set; } - public override void ConfigureRule(IDictionary paramValueMap) { base.ConfigureRule(paramValueMap); From 0196a152df2f797f5bbfb795873496bd14ebce96 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Oct 2020 22:49:21 +0100 Subject: [PATCH 5/8] add tests --- Tests/Rules/UseConsistentWhitespace.tests.ps1 | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tests/Rules/UseConsistentWhitespace.tests.ps1 b/Tests/Rules/UseConsistentWhitespace.tests.ps1 index 77d320830..319799819 100644 --- a/Tests/Rules/UseConsistentWhitespace.tests.ps1 +++ b/Tests/Rules/UseConsistentWhitespace.tests.ps1 @@ -180,6 +180,35 @@ $x = $true -and Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null } + + It "Should not find violation if there are whitespaces of size 1 around a unary operator starting with a dash" { + Invoke-ScriptAnalyzer -ScriptDefinition '$x -join $y' -Settings $settings | Should -BeNullOrEmpty + } + + It "Should find a violation if no whitespace around a unary operator starting with a dash" { + $def = '$x=1' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + Test-CorrectionExtentFromContent $def $violations 1 '=' ' = ' + } + + It "Should find a violation if no whitespace before a unary operator starting with a dash" { + $def = '$x-join $Y' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + Test-CorrectionExtentFromContent $def $violations 1 '' ' ' + } + + It "Should find a violation if no whitespace after a unary operator starting with a dash" { + $def = '$x -join$y' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + Test-CorrectionExtentFromContent $def $violations 1 '' ' ' + } + + It "Should find a violation if there is a whitespaces not of size 1 around a unary operator starting with a dash" { + $def = '$x -join $y' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + Test-CorrectionExtentFromContent $def $violations 1 ' -join ' ' -join ' + } + } Context "When a comma is not followed by a space" { From fc233bf801820069008e9ff7e4bb00e860d7891d Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister [MVP]" Date: Sun, 25 Oct 2020 10:32:14 +0000 Subject: [PATCH 6/8] also check if nothing preceds operator --- Rules/UseConsistentWhitespace.cs | 32 ++++++++++++++++++- Tests/Rules/UseConsistentWhitespace.tests.ps1 | 16 +++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index 7abe2c1a0..29a4431b5 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -520,7 +520,37 @@ private IEnumerable FindOperatorViolations(TokenOperations tok || tokenNode.Next == null || tokenNode.Value.Kind == TokenKind.DotDot) { - continue; + if (TokenTraits.HasTrait(tokenNode.Value.Kind, TokenFlags.UnaryOperator) && + tokenNode.Value.Text.StartsWith("-")) + { + var hasWhitespaceAfterOperator = tokenNode.Next.Value.Kind == TokenKind.NewLine + || IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode.Next); + if (!hasWhitespaceAfterOperator) + { + yield return new DiagnosticRecord( + GetError(ErrorKind.Operator), + tokenNode.Value.Extent, + GetName(), + GetDiagnosticSeverity(), + tokenOperations.Ast.Extent.File, + null, + new List() + { + new CorrectionExtent( + tokenNode.Value.Extent.StartLineNumber, + tokenNode.Value.Extent.EndLineNumber, + tokenNode.Value.Extent.StartColumnNumber, + tokenNode.Value.Extent.EndColumnNumber, + $"{tokenNode.Value.Text} ", + tokenNode.Value.Extent.File) + }); + continue; + } + } + else + { + continue; + } } // exclude unary operator for cases like $foo.bar(-$Var) diff --git a/Tests/Rules/UseConsistentWhitespace.tests.ps1 b/Tests/Rules/UseConsistentWhitespace.tests.ps1 index 319799819..6f8f9f8f6 100644 --- a/Tests/Rules/UseConsistentWhitespace.tests.ps1 +++ b/Tests/Rules/UseConsistentWhitespace.tests.ps1 @@ -181,34 +181,40 @@ $x = $true -and } - It "Should not find violation if there are whitespaces of size 1 around a unary operator starting with a dash" { + It 'Should not find violation if there are whitespaces of size 1 around a unary operator starting with a dash' { Invoke-ScriptAnalyzer -ScriptDefinition '$x -join $y' -Settings $settings | Should -BeNullOrEmpty } - It "Should find a violation if no whitespace around a unary operator starting with a dash" { + It 'Should find a violation if no whitespace around a unary operator starting with a dash' { $def = '$x=1' $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings Test-CorrectionExtentFromContent $def $violations 1 '=' ' = ' } - It "Should find a violation if no whitespace before a unary operator starting with a dash" { + It 'Should find a violation if no whitespace before a unary operator starting with a dash' { $def = '$x-join $Y' $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings Test-CorrectionExtentFromContent $def $violations 1 '' ' ' } - It "Should find a violation if no whitespace after a unary operator starting with a dash" { + It 'Should find a violation if no whitespace after a unary operator starting with a dash' { $def = '$x -join$y' $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings Test-CorrectionExtentFromContent $def $violations 1 '' ' ' } - It "Should find a violation if there is a whitespaces not of size 1 around a unary operator starting with a dash" { + It 'Should find a violation if there is a whitespaces not of size 1 around a unary operator starting with a dash' { $def = '$x -join $y' $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings Test-CorrectionExtentFromContent $def $violations 1 ' -join ' ' -join ' } + It 'Should find a violation if there is no whitespace after a unary operator with a dash but nothing that preceds it' { + $def = '-join$x' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + Test-CorrectionExtentFromContent $def $violations 1 '-join' '-join ' + } + } Context "When a comma is not followed by a space" { From 42f5877f400634a68714c4eb26fc44926ed97c50 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister [MVP]" Date: Sun, 25 Oct 2020 10:47:24 +0000 Subject: [PATCH 7/8] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Rules/Strings.resx | 2 +- Rules/UseConsistentWhitespace.cs | 7 ++----- Tests/Rules/UseConsistentWhitespace.tests.ps1 | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Rules/Strings.resx b/Rules/Strings.resx index 588e9e3dd..3719b7a36 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -988,7 +988,7 @@ Use space before open parenthesis. - Use space before and after binary and assignment operators. + Use space around binary, assignment and unary operators that start with a dash. Use space after a comma. diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index 29a4431b5..da2c60c42 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -520,6 +520,7 @@ private IEnumerable FindOperatorViolations(TokenOperations tok || tokenNode.Next == null || tokenNode.Value.Kind == TokenKind.DotDot) { + // for cases like '-split$a' as the other checks below in this function assume a preceding token if (TokenTraits.HasTrait(tokenNode.Value.Kind, TokenFlags.UnaryOperator) && tokenNode.Value.Text.StartsWith("-")) { @@ -544,13 +545,9 @@ private IEnumerable FindOperatorViolations(TokenOperations tok $"{tokenNode.Value.Text} ", tokenNode.Value.Extent.File) }); - continue; } } - else - { - continue; - } + continue; } // exclude unary operator for cases like $foo.bar(-$Var) diff --git a/Tests/Rules/UseConsistentWhitespace.tests.ps1 b/Tests/Rules/UseConsistentWhitespace.tests.ps1 index 6f8f9f8f6..801bea752 100644 --- a/Tests/Rules/UseConsistentWhitespace.tests.ps1 +++ b/Tests/Rules/UseConsistentWhitespace.tests.ps1 @@ -214,7 +214,6 @@ $x = $true -and $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings Test-CorrectionExtentFromContent $def $violations 1 '-join' '-join ' } - } Context "When a comma is not followed by a space" { From 6df338023c7a7bacf1954e7c01f8fc6cf6b8421b Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Wed, 21 Apr 2021 13:55:47 -0700 Subject: [PATCH 8/8] Update Rules/UseConsistentWhitespace.cs --- Rules/UseConsistentWhitespace.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs index da2c60c42..1d4e259a6 100644 --- a/Rules/UseConsistentWhitespace.cs +++ b/Rules/UseConsistentWhitespace.cs @@ -521,10 +521,12 @@ private IEnumerable FindOperatorViolations(TokenOperations tok || tokenNode.Value.Kind == TokenKind.DotDot) { // for cases like '-split$a' as the other checks below in this function assume a preceding token - if (TokenTraits.HasTrait(tokenNode.Value.Kind, TokenFlags.UnaryOperator) && - tokenNode.Value.Text.StartsWith("-")) + if (TokenTraits.HasTrait(tokenNode.Value.Kind, TokenFlags.UnaryOperator) + && tokenNode.Value.Text.StartsWith("-") + && tokenNode.Value.Text.Length > 1 + && Char.IsLetter(tokenNode.Value.Text[1])) { - var hasWhitespaceAfterOperator = tokenNode.Next.Value.Kind == TokenKind.NewLine + bool hasWhitespaceAfterOperator = tokenNode.Next.Value.Kind == TokenKind.NewLine || IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode.Next); if (!hasWhitespaceAfterOperator) {