Skip to content

Commit

Permalink
Merge pull request #736 from mattwar/Bug605
Browse files Browse the repository at this point in the history
Fix calculation for slot containing offset
  • Loading branch information
mattwar committed Feb 23, 2015
2 parents 28ceb71 + b106d3d commit 63e58ee
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 4 deletions.
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

0 comments on commit 63e58ee

Please sign in to comment.