/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/LanguageServer/ProtocolUnitTests/CallHierarchy/CallHierarchyTests.cs
206 строк
8 KB
Joey Robichaud
Add LSP CallHierarchy support (#82865)
01 апр 2026, 02:55
Не верифицирован
01 апр 2026, 02:55
83c179c
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Linq; using System.Threading; using System.Threading.Tasks; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.CallHierarchy; public sealed class CallHierarchyTests(ITestOutputHelper testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) { [Theory, CombinatorialData] public async Task TestPrepareCallHierarchyIncludesContainingTypeInName(bool mutatingLspWorkspace) { var markup = """ class C { void {|definition:M|}() { } void N() { {|caret:|}M(); } } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var preparedItems = await RunPrepareCallHierarchyAsync(testLspServer, testLspServer.GetLocations("caret").Single()); var preparedItem = Assert.Single(preparedItems); var definition = testLspServer.GetLocations("definition").Single(); Assert.Equal("C.M()", preparedItem.Name); Assert.Equal(definition.DocumentUri, preparedItem.Uri); Assert.Equal(0, CompareRange(definition.Range, preparedItem.SelectionRange)); Assert.NotNull(preparedItem.Data); } [Theory, CombinatorialData] public async Task TestOutgoingCallsIncludeImplicitConstructors(bool mutatingLspWorkspace) { var markup = """ class {|type:C|} { public void {|targetMethod:M|}() { } } class Caller { void {|caret:N|}() { var c = new C(); c.M(); } } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var preparedItem = Assert.Single(await RunPrepareCallHierarchyAsync(testLspServer, testLspServer.GetLocations("caret").Single())); var outgoingCalls = await RunOutgoingCallsAsync(testLspServer, preparedItem); Assert.Equal(2, outgoingCalls.Length); var constructorCall = Assert.Single(outgoingCalls, static call => call.To.Name == "C.C()"); var methodCall = Assert.Single(outgoingCalls, static call => call.To.Name == "C.M()"); var typeLocation = testLspServer.GetLocations("type").Single(); var methodLocation = testLspServer.GetLocations("targetMethod").Single(); Assert.Equal(typeLocation.DocumentUri, constructorCall.To.Uri); Assert.Equal(0, CompareRange(typeLocation.Range, constructorCall.To.SelectionRange)); Assert.Single(constructorCall.FromRanges); Assert.Equal(methodLocation.DocumentUri, methodCall.To.Uri); Assert.Equal(0, CompareRange(methodLocation.Range, methodCall.To.SelectionRange)); Assert.Single(methodCall.FromRanges); } [Theory, CombinatorialData] public async Task TestIncomingCallsIncludesManyCallers(bool mutatingLspWorkspace) { var markup = """ class Target { void {|definition:M|}() { } } class Caller { void {|caller1:Caller1|}() { var target = new Target(); target.{|caret:|}M(); } void {|caller2:Caller2|}() { var target = new Target(); target.M(); } } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var preparedItem = Assert.Single(await RunPrepareCallHierarchyAsync(testLspServer, testLspServer.GetLocations("caret").Single())); var incomingCalls = await RunIncomingCallsAsync(testLspServer, preparedItem); Assert.Equal(2, incomingCalls.Length); var firstCaller = Assert.Single(incomingCalls, static call => call.From.Name == "Caller.Caller1()"); var secondCaller = Assert.Single(incomingCalls, static call => call.From.Name == "Caller.Caller2()"); var firstCallerLocation = testLspServer.GetLocations("caller1").Single(); var secondCallerLocation = testLspServer.GetLocations("caller2").Single(); Assert.Equal(0, CompareRange(firstCallerLocation.Range, firstCaller.From.SelectionRange)); Assert.Equal(0, CompareRange(secondCallerLocation.Range, secondCaller.From.SelectionRange)); Assert.Single(firstCaller.FromRanges); Assert.Single(secondCaller.FromRanges); } [Theory, CombinatorialData] public async Task TestOutgoingCallsIncludesMethodPropertyAndField(bool mutatingLspWorkspace) { var markup = """ class C { int {|field:F|}; int {|property:P|} => F; void {|method:M|}() { } void {|caret:N|}() { M(); var p = P; var f = F; } } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var preparedItem = Assert.Single(await RunPrepareCallHierarchyAsync(testLspServer, testLspServer.GetLocations("caret").Single())); var outgoingCalls = await RunOutgoingCallsAsync(testLspServer, preparedItem); Assert.Equal(3, outgoingCalls.Length); var methodCall = Assert.Single(outgoingCalls, static call => call.To.Name == "C.M()"); var propertyCall = Assert.Single(outgoingCalls, static call => call.To.Name == "C.P"); var fieldCall = Assert.Single(outgoingCalls, static call => call.To.Name == "C.F"); Assert.Equal(0, CompareRange(testLspServer.GetLocations("method").Single().Range, methodCall.To.SelectionRange)); Assert.Equal(0, CompareRange(testLspServer.GetLocations("property").Single().Range, propertyCall.To.SelectionRange)); Assert.Equal(0, CompareRange(testLspServer.GetLocations("field").Single().Range, fieldCall.To.SelectionRange)); Assert.Single(methodCall.FromRanges); Assert.Single(propertyCall.FromRanges); Assert.Single(fieldCall.FromRanges); } private static async Task<LSP.CallHierarchyItem[]> RunPrepareCallHierarchyAsync(TestLspServer testLspServer, LSP.Location caret) => await testLspServer.ExecuteRequestAsync<LSP.CallHierarchyPrepareParams, LSP.CallHierarchyItem[]?>( LSP.Methods.PrepareCallHierarchyName, new LSP.CallHierarchyPrepareParams { TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, }, CancellationToken.None) ?? []; private static async Task<LSP.CallHierarchyOutgoingCall[]> RunOutgoingCallsAsync(TestLspServer testLspServer, LSP.CallHierarchyItem item) => await testLspServer.ExecuteRequestAsync<LSP.CallHierarchyOutgoingCallsParams, LSP.CallHierarchyOutgoingCall[]?>( LSP.Methods.CallHierarchyOutgoingCallsName, new LSP.CallHierarchyOutgoingCallsParams { Item = item, }, CancellationToken.None) ?? []; private static async Task<LSP.CallHierarchyIncomingCall[]> RunIncomingCallsAsync(TestLspServer testLspServer, LSP.CallHierarchyItem item) => await testLspServer.ExecuteRequestAsync<LSP.CallHierarchyIncomingCallsParams, LSP.CallHierarchyIncomingCall[]?>( LSP.Methods.CallHierarchyIncomingCallsName, new LSP.CallHierarchyIncomingCallsParams { Item = item, }, CancellationToken.None) ?? []; }