diff --git a/Rules/UseConsistentIndentation.cs b/Rules/UseConsistentIndentation.cs index 0e6680e63..2dedf530a 100644 --- a/Rules/UseConsistentIndentation.cs +++ b/Rules/UseConsistentIndentation.cs @@ -359,6 +359,30 @@ private static int GetCommentRunIndentationOffset( out bool commentRunStartsAfterLineContinuation, out bool commentRunStartsAfterPipeline) { + commentRunStartsAfterLineContinuation = false; + commentRunStartsAfterPipeline = false; + if (HasCodeAfterCommentOnSameLine(tokens, tokenIndex)) + { + commentRunStartsAfterLineContinuation = + tokenIndex > 0 && + tokens[tokenIndex - 1].Kind == TokenKind.LineContinuation; + if (tokenIndex > 2 && + (tokens[tokenIndex - 1].Kind == TokenKind.NewLine || + tokens[tokenIndex - 1].Kind == TokenKind.LineContinuation) && + tokens[tokenIndex - 2].Kind == TokenKind.Comment && + (tokens[tokenIndex - 3].Kind == TokenKind.NewLine || + tokens[tokenIndex - 3].Kind == TokenKind.LineContinuation)) + { + GetCommentRunIndentationOffset( + tokens, + tokenIndex - 2, + out _, + out commentRunStartsAfterPipeline); + } + + return 0; + } + int firstCommentIndex = tokenIndex; int currentLine = tokens[tokenIndex].Extent.StartLineNumber; int precedingIndex = tokenIndex - 1; @@ -369,6 +393,7 @@ private static int GetCommentRunIndentationOffset( precedingIndex--; if (precedingIndex < 0 || tokens[precedingIndex].Kind != TokenKind.Comment || + HasCodeAfterCommentOnSameLine(tokens, precedingIndex) || tokens[precedingIndex].Extent.EndLineNumber != currentLine - 1 || (precedingIndex > 0 && tokens[precedingIndex - 1].Kind != TokenKind.NewLine && @@ -393,6 +418,7 @@ private static int GetCommentRunIndentationOffset( (tokens[nextCommentIndex - 1].Kind == TokenKind.NewLine || tokens[nextCommentIndex - 1].Kind == TokenKind.LineContinuation) && tokens[nextCommentIndex].Kind == TokenKind.Comment && + !HasCodeAfterCommentOnSameLine(tokens, nextCommentIndex) && tokens[nextCommentIndex].Extent.StartLineNumber == tokens[nextCommentIndex - 2].Extent.EndLineNumber + 1; nextCommentIndex += 2) { @@ -405,6 +431,16 @@ private static int GetCommentRunIndentationOffset( leastIndentedColumn; } + private static bool HasCodeAfterCommentOnSameLine(Token[] tokens, int commentIndex) + { + Token nextToken = NextTokenIgnoringComments(tokens, commentIndex); + return nextToken != null && + nextToken.Kind != TokenKind.NewLine && + nextToken.Kind != TokenKind.LineContinuation && + nextToken.Kind != TokenKind.EndOfInput && + nextToken.Extent.StartLineNumber <= tokens[commentIndex].Extent.EndLineNumber; + } + /// /// Scans forward from the current opener to the end of the line. /// Returns true if there is at least one unclosed opener when diff --git a/Tests/Rules/UseConsistentIndentation.tests.ps1 b/Tests/Rules/UseConsistentIndentation.tests.ps1 index d07a7b0a5..a48cf33c5 100644 --- a/Tests/Rules/UseConsistentIndentation.tests.ps1 +++ b/Tests/Rules/UseConsistentIndentation.tests.ps1 @@ -284,6 +284,25 @@ Write-Output ` Should -Be $scriptDefinition } + It 'Should not include a block comment followed by code in a comment run' { + $scriptDefinition = @' +if ($a) { + # comment + <# note #> Write-Output 'value' +} +'@ + $expectedScriptDefinition = @' +if ($a) { + # comment + <# note #> Write-Output 'value' +} +'@ + $settings.Rules.PSUseConsistentIndentation.PipelineIndentation = 'NoIndentation' + + Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings | + Should -Be $expectedScriptDefinition + } + It 'Should preserve a comment run containing an internal line continuation with indentation' -TestCases @( @{ Kind = 'space'; Indentation = ' ' } @{ Kind = 'tab'; Indentation = "`t" } @@ -674,6 +693,36 @@ bar Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $def } + It "Should preserve pipeline indentation across a comment line continuation with PipelineIndentation None" { + $def = @' +foo | + <# comment #> ` + <# note #> bar +'@ + $settings.Rules.PSUseConsistentIndentation.PipelineIndentation = 'None' + Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $def + } + + It "Should not inherit pipeline indentation from a trailing comment with PipelineIndentation None" { + $def = @' +function test { + foo | bar # trailing + <# note #> baz +} +'@ + $expected = @' +function test { + foo | bar # trailing + <# note #> baz +} +'@ + $settings.Rules.PSUseConsistentIndentation.PipelineIndentation = 'None' + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings + $violations.Count | Should -Be 1 + Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected + Invoke-Formatter -ScriptDefinition $expected -Settings $settings | Should -Be $expected + } + It "Should indent properly after line continuation (backtick) character with pipeline" { $def = @' foo |