OmniSharp / OmniSharp/csharp-language-server-protocol
Bug in SemanticTokensDocument.GetSemanticTokenEdits
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 638
- Forks
- 109
- Avg merge
- 1m
- Merged PRs (30d)
- 2
Description
This bit of code in GetSemanticTokenEdits (lines 162 to 178) throws an ArgumentOutOfRangeException in the call to ImmutableArray.Create when you delete code in a document (but maybe in other cases too):
while (startIndex < dataLength && startIndex < prevDataLength && prevData[startIndex] ==
Data[startIndex])
{
startIndex++;
}
if (startIndex < dataLength && startIndex < prevDataLength)
{
// Find end index
var endIndex = 0;
while (endIndex < dataLength && endIndex < prevDataLength &&
prevData[prevDataLength - 1 - endIndex] == Data[dataLength - 1 - endIndex])
{
endIndex++;
}
var newData = ImmutableArray.Create(Data, startIndex, dataLength - endIndex - startIndex);
It looks like the intent here is to find both the longest common prefix and the longest common suffix between prevData and Data. Then it will return a SematicTokensEdit with a DeleteCount = prevDataLength - endIndex - startIndex to delete the tokens in the middle, and Data = newData to insert the replacement tokens.
Logically:
prevData = [... common prefix ...] [... stuff to delete ...] [... common suffix ...]
Data = [... common prefix ...] [... stuff to insert ...] [... common suffix ...]
Where "stuff to insert" can have a different length than "stuff to delete", including a length of zero.
So it's trying to diff them like this:
prevData = [a a a b b b c c c]
Data = [a a a c c c] // extra spaces added for alignment, Data.Length = 6
^ ^ ^ snip!
startIndex = 3
endIndex = 3
newData = Create(Data, 3, 6 - 3 - 3) // length = 0, this is fine
DeleteCount = 9 - 3 - 3 // = 3, all good
But this isn't reliable. The common prefix can overlap with the common suffix, just by chance, as in this example:
prevData = [a a a a b a a a a]
Data = [a a a a a a]
^ ^ ^ snip!
startIndex = 4
endIndex = 4
newData = Create(Data, 3, 6 - 4 - 4) // length = -2, oops!!!!
DeleteCount = 9 - 3 - 3 // = 3
The search for endIndex needs to be limited to not eat into the common prefix. In this example, we should get startIndex = 4, endIndex = 2, DeleteCount = 3, newData.Length = 0.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading SemanticTokensDocument.GetSemanticTokenEdits around lines 162-178 and trace the prefix and suffix scans for the deletion example. Reproduce the overlapping-prefix case, then verify the resulting SemanticTokensEdit has valid replacement and delete lengths without an ArgumentOutOfRangeException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- devtools, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100