diff --git a/Rules/UseConsistentIndentation.cs b/Rules/UseConsistentIndentation.cs index b297b2ccc..1da472bf5 100644 --- a/Rules/UseConsistentIndentation.cs +++ b/Rules/UseConsistentIndentation.cs @@ -131,9 +131,9 @@ public override IEnumerable AnalyzeScript(Ast ast, string file var indentationLevel = 0; var onNewLine = true; var pipelineAsts = ast.FindAll(testAst => testAst is PipelineAst && (testAst as PipelineAst).PipelineElements.Count > 1, true); - for (int k = 0; k < tokens.Length; k++) + for (int tokenIndex = 0; tokenIndex < tokens.Length; tokenIndex++) { - var token = tokens[k]; + var token = tokens[tokenIndex]; if (token.Kind == TokenKind.EndOfInput) { @@ -151,8 +151,8 @@ public override IEnumerable AnalyzeScript(Ast ast, string file break; case TokenKind.Pipe: - bool pipelineIsFollowedByNewlineOrLineContinuation = k < tokens.Length - 1 && k > 0 && - (tokens[k + 1].Kind == TokenKind.NewLine || tokens[k + 1].Kind == TokenKind.LineContinuation); + bool pipelineIsFollowedByNewlineOrLineContinuation = tokenIndex < tokens.Length - 1 && tokenIndex > 0 && + (tokens[tokenIndex + 1].Kind == TokenKind.NewLine || tokens[tokenIndex + 1].Kind == TokenKind.LineContinuation); if (!pipelineIsFollowedByNewlineOrLineContinuation) { break; @@ -164,7 +164,7 @@ public override IEnumerable AnalyzeScript(Ast ast, string file } if (pipelineIndentationStyle == PipelineIndentationStyle.IncreaseIndentationForFirstPipeline) { - bool isFirstPipeInPipeline = pipelineAsts.Any(pipelineAst => PositionIsEqual(((PipelineAst)pipelineAst).PipelineElements[0].Extent.EndScriptPosition, tokens[k - 1].Extent.EndScriptPosition)); + bool isFirstPipeInPipeline = pipelineAsts.Any(pipelineAst => PositionIsEqual(((PipelineAst)pipelineAst).PipelineElements[0].Extent.EndScriptPosition, tokens[tokenIndex - 1].Extent.EndScriptPosition)); if (isFirstPipeInPipeline) { AddViolation(token, indentationLevel++, diagnosticRecords, ref onNewLine); @@ -191,19 +191,24 @@ public override IEnumerable AnalyzeScript(Ast ast, string file var tempIndentationLevel = indentationLevel; // Check if the preceding character is an escape character - if (k > 0 && tokens[k - 1].Kind == TokenKind.LineContinuation) + if (tokenIndex > 0 && tokens[tokenIndex - 1].Kind == TokenKind.LineContinuation) { ++tempIndentationLevel; } - else + + // check for comments in between multi-line commands with line continuation + if (tokenIndex > 2 && tokens[tokenIndex - 1].Kind == TokenKind.NewLine + && tokens[tokenIndex - 2].Kind == TokenKind.Comment) { - // Ignore comments - // Since the previous token is a newline token we start - // looking for comments at the token before the newline token. - int j = k - 2; - while (j > 0 && tokens[j].Kind == TokenKind.Comment) + int searchForPrecedingLineContinuationIndex = tokenIndex - 2; + while (searchForPrecedingLineContinuationIndex > 0 && tokens[searchForPrecedingLineContinuationIndex].Kind == TokenKind.Comment) + { + searchForPrecedingLineContinuationIndex--; + } + + if (searchForPrecedingLineContinuationIndex >= 0 && tokens[searchForPrecedingLineContinuationIndex].Kind == TokenKind.LineContinuation) { - --j; + tempIndentationLevel++; } } diff --git a/Tests/Rules/UseConsistentIndentation.tests.ps1 b/Tests/Rules/UseConsistentIndentation.tests.ps1 index 1503b8bd8..2cce7dd7c 100644 --- a/Tests/Rules/UseConsistentIndentation.tests.ps1 +++ b/Tests/Rules/UseConsistentIndentation.tests.ps1 @@ -3,7 +3,25 @@ $testRootDirectory = Split-Path -Parent $directory Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1") + Describe "UseConsistentIndentation" { + BeforeAll { + function Invoke-FormatterAssertion { + param( + [string] $ScriptDefinition, + [string] $ExcpectedScriptDefinition, + [int] $NumberOfExpectedWarnings, + [hashtable] $Settings + ) + + # Unit test just using this rule only + $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings + $violations.Count | Should -Be $NumberOfExpectedWarnings -Because $ScriptDefinition + Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings | Should -Be $expected -Because $ScriptDefinition + # Integration test with all default formatting rules + Invoke-Formatter -ScriptDefinition $scriptDefinition | Should -Be $expected -Because $ScriptDefinition + } + } BeforeEach { $indentationUnit = ' ' $indentationSize = 4 @@ -107,6 +125,39 @@ function foo { } Context "When a multi-line command is given" { + + It "When a comment is in the middle of a multi-line statement with preceding and succeeding line continuations" { + $scriptDefinition = @' +foo ` +# comment +-bar ` +-baz +'@ + $expected = @' +foo ` + # comment + -bar ` + -baz +'@ + Invoke-FormatterAssertion $scriptDefinition $expected 3 $settings + } + + It "When a comment is in the middle of a multi-line statement with preceding pipeline and succeeding line continuation " { + $scriptDefinition = @' +foo | +# comment +bar ` +-baz +'@ + $expected = @' +foo | + # comment + bar ` + -baz +'@ + Invoke-FormatterAssertion $scriptDefinition $expected 3 $settings + } + It "Should find a violation if a pipleline element is not indented correctly" { $def = @' get-process |