Skip to content
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

Fix calculation for slot containing offset #736

Merged
merged 2 commits into from Feb 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -52,8 +52,7 @@ public override int GetSlotOffset(int index)
public override int FindSlotIndexContainingOffset(int offset)
{
Debug.Assert(offset >= 0 && offset < FullWidth);
int idx = _childOffsets.BinarySearch(offset);
return idx >= 0 ? idx : (~idx - 1);
return _childOffsets.BinarySearchUpperBound(offset) - 1;
}

private static int[] CalculateOffsets(ArrayElement<CSharpSyntaxNode>[] children)
Expand Down
38 changes: 38 additions & 0 deletions src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs
Expand Up @@ -481,6 +481,44 @@ public void TestFindToken()
Assert.Equal(SyntaxKind.IfKeyword, token.Kind());
}

[Fact]
public void TestFindTokenInLargeList()
{
var identifier = SyntaxFactory.Identifier("x");
var missingIdentifier = SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken);
var name = SyntaxFactory.IdentifierName(identifier);
var missingName = SyntaxFactory.IdentifierName(missingIdentifier);
var comma = SyntaxFactory.Token(SyntaxKind.CommaToken);
var missingComma = SyntaxFactory.MissingToken(SyntaxKind.CommaToken);
var argument = SyntaxFactory.Argument(name);
var missingArgument = SyntaxFactory.Argument(missingName);

// make a large list that has lots of zero-length nodes (that shouldn't be found)
var nodesAndTokens = SyntaxFactory.NodeOrTokenList(
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
argument);

var argumentList = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList<ArgumentSyntax>(SyntaxFactory.NodeOrTokenList(nodesAndTokens)));
var invocation = SyntaxFactory.InvocationExpression(name, argumentList);
CheckFindToken(invocation);
}

private void CheckFindToken(SyntaxNode node)
{
for (int i = 0; i < node.FullSpan.End; i++)
{
var token = node.FindToken(i);
Assert.Equal(true, token.FullSpan.Contains(i));
}
}

[WorkItem(755236, "DevDiv")]
[Fact]
public void TestFindNode()
Expand Down
30 changes: 30 additions & 0 deletions src/Compilers/Core/Portable/InternalUtilities/ArrayExtensions.cs
Expand Up @@ -173,5 +173,35 @@ internal static int BinarySearch(this int[] array, int value)

return ~low;
}

/// <summary>
/// Search a sorted integer array for the target value in O(log N) time.
/// </summary>
/// <param name="array">The array of integers which must be sorted in ascending order.</param>
/// <param name="value">The target value.</param>
/// <returns>An index in the array pointing to the position where <paramref name="value"/> should be
/// inserted in order to maintain the sorted order. All values to the right of this position will be
/// strictly greater than <paramref name="value"/>. Note that this may return a position off the end
/// of the array if all elements are less than or equal to <paramref name="value"/>.</returns>
internal static int BinarySearchUpperBound(this int[] array, int value)
{
int low = 0;
int high = array.Length - 1;

while (low <= high)
{
int middle = low + ((high - low) >> 1);
if (array[middle] > value)
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}

return low;
}
}
}
Expand Up @@ -466,8 +466,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax
''' </remarks>
Public Overrides Function FindSlotIndexContainingOffset(offset As Integer) As Integer
Debug.Assert(offset >= 0 AndAlso offset < FullWidth)
Dim idx = _childOffsets.BinarySearch(offset)
Return If(idx >= 0, idx, (Not idx) - 1)
Return _childOffsets.BinarySearchUpperBound(offset) - 1
End Function

Friend Overrides Function SetDiagnostics(errors() As DiagnosticInfo) As GreenNode
Expand Down
35 changes: 35 additions & 0 deletions src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb
Expand Up @@ -2114,6 +2114,41 @@ End Class]]>
Assert.Throws(Of ArgumentOutOfRangeException)(Sub() classDecl.FindNode(root.FullSpan))
End Sub

<Fact>
Public Sub TestFindTokenInLargeList()
Dim identifier = SyntaxFactory.Identifier("x")
Dim missingIdentifier = SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken)
Dim name = SyntaxFactory.IdentifierName(identifier)
Dim missingName = SyntaxFactory.IdentifierName(missingIdentifier)
Dim comma = SyntaxFactory.Token(SyntaxKind.CommaToken)
Dim missingComma = SyntaxFactory.MissingToken(SyntaxKind.CommaToken)
Dim argument = SyntaxFactory.SimpleArgument(name)
Dim missingArgument = SyntaxFactory.SimpleArgument(missingName)

'' make a large list that has lots of zero-length nodes (that shouldn't be found)
Dim nodesAndTokens = SyntaxFactory.NodeOrTokenList(
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
missingArgument, missingComma,
argument)

Dim argumentList = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(Of ArgumentSyntax)(SyntaxFactory.NodeOrTokenList(nodesAndTokens)))
Dim invocation = SyntaxFactory.InvocationExpression(name, argumentList)
CheckFindToken(invocation)
End Sub

Private Sub CheckFindToken(node As SyntaxNode)
For i As Integer = 1 To node.FullSpan.End - 1
Dim token = node.FindToken(i)
Assert.Equal(True, token.FullSpan.Contains(i))
Next
End Sub

<WorkItem(539940, "DevDiv")>
<Fact>
Public Sub TestFindTriviaNoTriviaExistsAtPosition()
Expand Down