提交 649960f4 编写于 作者: P Paul Harrington

Address performance of smart indenter at end of file with inactive regions.

上级 e0371c92
......@@ -282,6 +282,7 @@
<Compile Include="Extensions\ContextQuery\AbstractContextTests.cs" />
<Compile Include="Extensions\ContextQuery\NamespaceContextTests.cs" />
<Compile Include="Extensions\ContextQuery\TypeContextTests.cs" />
<Compile Include="Extensions\SyntaxTreeExtensionsTests.cs" />
<Compile Include="ExtractInterface\ExtractInterfaceTests.cs" />
<Compile Include="ExtractMethod\ExtractMethodBase.cs" />
<Compile Include="ExtractMethod\ExtractMethodTests.cs" />
......@@ -675,4 +676,4 @@
<Import Project="..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Extensions
{
public class SyntaxTreeExtensionsTests
{
private static void VerifyWholeLineIsActive(SyntaxTree tree, int lineNumber)
{
var line = tree.GetText().Lines[lineNumber];
for(int pos = line.Start; pos < line.EndIncludingLineBreak; pos++)
{
Assert.False(tree.IsInInactiveRegion(pos, CancellationToken.None));
}
}
private static void VerifyWholeLineIsInactive(SyntaxTree tree, int lineNumber)
{
var line = tree.GetText().Lines[lineNumber];
for (int pos = line.Start; pos < line.EndIncludingLineBreak; pos++)
{
Assert.True(tree.IsInInactiveRegion(pos, CancellationToken.None));
}
}
[Fact]
public void SimpleInactive()
{
var code = @"#if false
This is inactive
#else
// This is active
#endif
";
var tree = CSharpSyntaxTree.ParseText(code);
VerifyWholeLineIsActive(tree, 0);
VerifyWholeLineIsInactive(tree, 1);
VerifyWholeLineIsActive(tree, 2);
VerifyWholeLineIsActive(tree, 3);
VerifyWholeLineIsActive(tree, 4);
}
[Fact]
public void InactiveEof()
{
var code = @"#if false
This is inactive
";
var tree = CSharpSyntaxTree.ParseText(code);
VerifyWholeLineIsActive(tree, 0);
VerifyWholeLineIsInactive(tree, 1);
}
[Fact]
public void InactiveEof2()
{
var code = @"#if false
This is inactive
#endif
// This is active
";
var tree = CSharpSyntaxTree.ParseText(code);
VerifyWholeLineIsActive(tree, 0);
VerifyWholeLineIsInactive(tree, 1);
VerifyWholeLineIsActive(tree, 2);
VerifyWholeLineIsActive(tree, 3);
}
}
}
......@@ -50,6 +50,39 @@ public void NoPreviousLine()
expectedIndentation: 0);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.SmartIndent)]
public void EndOfFileInactive()
{
var code = @"
// Line 1
#if false
#endif
";
AssertSmartIndent(
code,
indentationLine: 4,
expectedIndentation: 4);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.SmartIndent)]
public void EndOfFileInactive2()
{
var code = @"
// Line 1
#if false
#endif
// Line 2
";
AssertSmartIndent(
code,
indentationLine: 5,
expectedIndentation: 0);
}
[Fact]
[Trait(Traits.Feature, Traits.Features.SmartIndent)]
public void Comments()
......
......@@ -780,10 +780,29 @@ public static IEnumerable<SyntaxNode> GetAncestorsOrThis(this SyntaxNode node, F
/// </summary>
private static IEnumerable<SyntaxToken> GetSkippedTokens(SyntaxTriviaList list)
{
// PERF: Avoid allocations in the most common case of no skipped tokens.
if (!HasSkippedTokens(list))
{
return SpecializedCollections.EmptyEnumerable<SyntaxToken>();
}
return list.Where(trivia => trivia.RawKind == (int)SyntaxKind.SkippedTokensTrivia)
.SelectMany(t => ((SkippedTokensTriviaSyntax)t.GetStructure()).Tokens);
}
private static bool HasSkippedTokens(SyntaxTriviaList list)
{
foreach (var trivia in list)
{
if (trivia.RawKind == (int)SyntaxKind.SkippedTokensTrivia)
{
return true;
}
}
return false;
}
/// <summary>
/// If the position is inside of token, return that token; otherwise, return the token to the right.
/// </summary>
......
......@@ -534,24 +534,26 @@ private static bool AtEndOfIncompleteStringOrCharLiteral(SyntaxToken token, int
}
var token = syntaxTree.FindTokenOrEndToken(position, cancellationToken);
var text = syntaxTree.GetText(cancellationToken);
var lineContainingPosition = text.Lines.IndexOf(position);
if (token.Kind() == SyntaxKind.EndOfFileToken)
{
var text = syntaxTree.GetText(cancellationToken);
var lineContainingPosition = text.Lines.IndexOf(position);
var triviaList = token.LeadingTrivia;
foreach (var triviaTok in triviaList.Reverse())
{
if (triviaTok.HasStructure)
var triviaLine = text.Lines.IndexOf(triviaTok.SpanStart);
if (triviaLine <= lineContainingPosition)
{
if (!triviaTok.HasStructure)
{
return false;
}
var structure = triviaTok.GetStructure();
if (structure is BranchingDirectiveTriviaSyntax)
{
var triviaLine = text.Lines.IndexOf(triviaTok.SpanStart);
if (triviaLine < lineContainingPosition)
{
var branch = (BranchingDirectiveTriviaSyntax)structure;
return !branch.IsActive || !branch.BranchTaken;
}
var branch = (BranchingDirectiveTriviaSyntax)structure;
return !branch.IsActive || !branch.BranchTaken;
}
}
}
......
......@@ -113,13 +113,17 @@ internal static class FindTokenHelper
public static SyntaxToken FindSkippedTokenBackward(IEnumerable<SyntaxToken> skippedTokenList, int position)
{
// the given skipped token list is already in order
var skippedTokenContainingPosition = skippedTokenList.LastOrDefault(skipped => skipped.Span.Length > 0 && skipped.SpanStart <= position);
if (skippedTokenContainingPosition != default(SyntaxToken))
// PERF: Expansion of return skippedTokenList.LastOrDefault(skipped => skipped.Span.Length > 0 && skipped.SpanStart <= position);
var skippedTokenContainingPosition = default(SyntaxToken);
foreach (var skipped in skippedTokenList)
{
return skippedTokenContainingPosition;
if (skipped.Span.Length > 0 && skipped.SpanStart <= position)
{
skippedTokenContainingPosition = skipped;
}
}
return default(SyntaxToken);
return skippedTokenContainingPosition;
}
/// <summary>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册