Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Roslyn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Toolset.Package", "src\NuGet\Microsoft.Net.Compilers.Toolset\Microsoft.Net.Compilers.Toolset.Package.csproj", "{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.Protocol", "src\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj", "{686BF57E-A6FF-467B-AAB3-44DE916A9772}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests", "src\Features\LanguageServer\ProtocolUnitTests\Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj", "{1DDE89EE-5819-441F-A060-2FF4A986F372}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Debugger", "src\Tools\ExternalAccess\Debugger\Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj", "{655A5B07-39B8-48CD-8590-8AC0C2B708D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.UnitTesting", "src\Tools\ExternalAccess\UnitTesting\Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.csproj", "{FA51A3CB-5174-4D99-B76E-DC31C5361DF3}"
Expand Down Expand Up @@ -1067,6 +1071,14 @@ Global
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Release|Any CPU.Build.0 = Release|Any CPU
{686BF57E-A6FF-467B-AAB3-44DE916A9772}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{686BF57E-A6FF-467B-AAB3-44DE916A9772}.Debug|Any CPU.Build.0 = Debug|Any CPU
{686BF57E-A6FF-467B-AAB3-44DE916A9772}.Release|Any CPU.ActiveCfg = Release|Any CPU
{686BF57E-A6FF-467B-AAB3-44DE916A9772}.Release|Any CPU.Build.0 = Release|Any CPU
{1DDE89EE-5819-441F-A060-2FF4A986F372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DDE89EE-5819-441F-A060-2FF4A986F372}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DDE89EE-5819-441F-A060-2FF4A986F372}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DDE89EE-5819-441F-A060-2FF4A986F372}.Release|Any CPU.Build.0 = Release|Any CPU
{655A5B07-39B8-48CD-8590-8AC0C2B708D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{655A5B07-39B8-48CD-8590-8AC0C2B708D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{655A5B07-39B8-48CD-8590-8AC0C2B708D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1296,6 +1308,8 @@ Global
{2FB6C157-DF91-4B1C-9827-A4D1C08C73EC} = {8977A560-45C2-4EC2-A849-97335B382C74}
{1638FB04-0298-4341-B5E0-8A13B4823C81} = {8977A560-45C2-4EC2-A849-97335B382C74}
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC} = {C52D8057-43AF-40E6-A01B-6CDBB7301985}
{686BF57E-A6FF-467B-AAB3-44DE916A9772} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
{1DDE89EE-5819-441F-A060-2FF4A986F372} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
{655A5B07-39B8-48CD-8590-8AC0C2B708D8} = {8977A560-45C2-4EC2-A849-97335B382C74}
{FA51A3CB-5174-4D99-B76E-DC31C5361DF3} = {8977A560-45C2-4EC2-A849-97335B382C74}
{DE53934B-7FC1-48A0-85AB-C519FBBD02CF} = {8977A560-45C2-4EC2-A849-97335B382C74}
Expand Down
5 changes: 4 additions & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
<Project>
<!--
Expand Down Expand Up @@ -111,6 +111,8 @@
<MicrosoftVisualStudioLanguageIntellisenseVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioLanguageIntellisenseVersion>
<MicrosoftVisualStudioLanguageNavigateToInterfacesVersion>16.0.467</MicrosoftVisualStudioLanguageNavigateToInterfacesVersion>
<MicrosoftVisualStudioLanguageStandardClassificationVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioLanguageStandardClassificationVersion>
<MicrosoftVisualStudioLanguageServerProtocolVersion>16.2.1078</MicrosoftVisualStudioLanguageServerProtocolVersion>
<MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>16.2.1078</MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>
<MicrosoftVisualStudioOLEInteropVersion>7.10.6071</MicrosoftVisualStudioOLEInteropVersion>
<MicrosoftVisualStudioPlatformVSEditorVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioPlatformVSEditorVersion>
<MicrosoftVisualStudioProgressionCodeSchemaVersion>15.8.27812-alpha</MicrosoftVisualStudioProgressionCodeSchemaVersion>
Expand Down Expand Up @@ -309,6 +311,7 @@
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
https://dotnet.myget.org/F/dotnet-corefxtestdata/api/v3/index.json;
https://dotnet.myget.org/F/dotnet-buildtools/api/v3/index.json;
https://dotnet.myget.org/F/experimental-vs-packages/api/v3/index.json;
https://dotnet.myget.org/F/symreader/api/v3/index.json;
https://dotnet.myget.org/F/symreader-portable/api/v3/index.json;
https://dotnet.myget.org/F/symreader-converter/api/v3/index.json;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ProjectReference Include="..\..\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
<ProjectReference Include="..\..\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\EditorFeatures\CSharp.Wpf\Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf.csproj" />
<ProjectReference Include="..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" />
<ProjectReference Include="..\..\Test\Utilities\Portable\Roslyn.Test.Utilities.csproj" />
<ProjectReference Include="..\..\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ProjectReference Include="..\..\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
<ProjectReference Include="..\..\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\EditorFeatures\CSharp.Wpf\Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf.csproj" />
<ProjectReference Include="..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" />
<ProjectReference Include="..\..\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj" />
<ProjectReference Include="..\..\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.CSharp.EditorFeatures" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.EditorFeatures.Wpf" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.LanguageServer.Protocol" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.Debugger" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.EditorFeatures" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ProjectReference Include="..\..\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\EditorFeatures\CSharp.Wpf\Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf.csproj" />
<ProjectReference Include="..\..\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\Test\PdbUtilities\Roslyn.Test.PdbUtilities.csproj" />
<ProjectReference Include="..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" />
<ProjectReference Include="..\..\Test\Utilities\Portable\Roslyn.Test.Utilities.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<ProjectReference Include="..\..\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj" />
<ProjectReference Include="..\..\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
<ProjectReference Include="..\..\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" />
<ProjectReference Include="..\..\Test\Utilities\Portable\Roslyn.Test.Utilities.csproj" />
<ProjectReference Include="..\..\VisualStudio\VisualBasic\Impl\Microsoft.VisualStudio.LanguageServices.VisualBasic.vbproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.Text.Adornments;
using Newtonsoft.Json;
using Roslyn.Utilities;
using Xunit;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Roslyn.Test.Utilities
{
[UseExportProvider]
public abstract class AbstractLanguageServerProtocolTests
{
protected virtual ExportProvider GetExportProvider()
{
var requestHelperTypes = DesktopTestHelpers.GetAllTypesImplementingGivenInterface(
typeof(IRequestHandler).Assembly, typeof(IRequestHandler));
var exportProviderFactory = ExportProviderCache.GetOrCreateExportProviderFactory(
TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic
.WithPart(typeof(LanguageServerProtocol))
.WithParts(requestHelperTypes));
return exportProviderFactory.CreateExportProvider();
}

/// <summary>
/// Asserts two objects are equivalent by converting to JSON and ignoring whitespace.
/// </summary>
/// <typeparam name="T">the JSON object type.</typeparam>
/// <param name="expected">the expected object to be converted to JSON.</param>
/// <param name="actual">the actual object to be converted to JSON.</param>
protected static void AssertJsonEquals<T>(T expected, T actual)
{
var expectedStr = JsonConvert.SerializeObject(expected);
var actualStr = JsonConvert.SerializeObject(actual);
AssertEqualIgnoringWhitespace(expectedStr, actualStr);
}

protected static void AssertEqualIgnoringWhitespace(string expected, string actual)
{
var expectedWithoutWhitespace = Regex.Replace(expected, @"\s+", string.Empty);
var actualWithoutWhitespace = Regex.Replace(actual, @"\s+", string.Empty);
Assert.Equal(expectedWithoutWhitespace, actualWithoutWhitespace);
}

/// <summary>
/// Assert that two location lists are equivalent.
/// Locations are not always returned in a consistent order so they must be sorted.
/// </summary>
protected static void AssertLocationsEqual(IEnumerable<LSP.Location> expectedLocations, IEnumerable<LSP.Location> actualLocations)
{
var orderedActualLocations = actualLocations.OrderBy(CompareLocations);
var orderedExpectedLocations = expectedLocations.OrderBy(CompareLocations);

AssertJsonEquals(orderedExpectedLocations, orderedActualLocations);

static int CompareLocations(LSP.Location l1, LSP.Location l2)
{
var compareDocument = l1.Uri.OriginalString.CompareTo(l2.Uri.OriginalString);
var compareRange = CompareRange(l1.Range, l2.Range);
return compareDocument != 0 ? compareDocument : compareRange;
}
}

protected static int CompareRange(LSP.Range r1, LSP.Range r2)
{
var compareLine = r1.Start.Line.CompareTo(r2.Start.Line);
var compareChar = r1.Start.Character.CompareTo(r2.Start.Character);
return compareLine != 0 ? compareLine : compareChar;
}

protected static string ApplyTextEdits(LSP.TextEdit[] edits, SourceText originalMarkup)
{
var text = originalMarkup;
foreach (var edit in edits)
{
var lines = text.Lines;
var startPosition = ProtocolConversions.PositionToLinePosition(edit.Range.Start);
var endPosition = ProtocolConversions.PositionToLinePosition(edit.Range.End);
var textSpan = lines.GetTextSpan(new LinePositionSpan(startPosition, endPosition));
text = text.Replace(textSpan, edit.NewText);
}

return text.ToString();
}

protected static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kind, string name, LSP.Location location, string containerName = null)
=> new LSP.SymbolInformation()
{
Kind = kind,
Name = name,
Location = location,
ContainerName = containerName
};

protected static LSP.TextDocumentIdentifier CreateTextDocumentIdentifier(Uri uri)
=> new LSP.TextDocumentIdentifier()
{
Uri = uri
};

protected static LSP.TextDocumentPositionParams CreateTextDocumentPositionParams(LSP.Location caret)
=> new LSP.TextDocumentPositionParams()
{
TextDocument = CreateTextDocumentIdentifier(caret.Uri),
Position = caret.Range.Start
};

protected static LSP.MarkupContent CreateMarkupContent(LSP.MarkupKind kind, string value)
=> new LSP.MarkupContent()
{
Kind = kind,
Value = value
};

protected static LSP.CompletionParams CreateCompletionParams(LSP.Location caret)
=> new LSP.CompletionParams()
{
TextDocument = CreateTextDocumentIdentifier(caret.Uri),
Position = caret.Range.Start,
Context = new LSP.CompletionContext()
{
// TODO - completion should respect context.
}
};

protected static LSP.VSCompletionItem CreateCompletionItem(string text, LSP.CompletionItemKind kind, string[] tags, LSP.CompletionParams requestParameters)
=> new LSP.VSCompletionItem()
{
FilterText = text,
InsertText = text,
Label = text,
SortText = text,
InsertTextFormat = LSP.InsertTextFormat.Plaintext,
Kind = kind,
Data = new CompletionResolveData()
{
DisplayText = text,
CompletionParams = requestParameters
},
Icon = tags != null ? new ImageElement(tags.ToImmutableArray().GetFirstGlyph().GetImageId()) : null
};

private protected static RunCodeActionParams CreateRunCodeActionParams(string codeActionTitle, LSP.Location location)
=> new RunCodeActionParams()
{
CodeActionParams = new LSP.CodeActionParams()
{
TextDocument = CreateTextDocumentIdentifier(location.Uri),
Range = location.Range,
Context = new LSP.CodeActionContext()
},
Title = codeActionTitle
};

/// <summary>
/// Creates a solution with a document.
/// </summary>
/// <returns>the solution and the annotated ranges in the document.</returns>
protected (Solution solution, Dictionary<string, IList<LSP.Location>> locations) CreateTestSolution(string markup)
=> CreateTestSolution(new string[] { markup });

/// <summary>
/// Create a solution with multiple documents.
/// </summary>
/// <returns>
/// the solution with the documents plus a list for each document of all annotated ranges in the document.
/// </returns>
protected (Solution solution, Dictionary<string, IList<LSP.Location>> locations) CreateTestSolution(string[] markups)
{
using var workspace = TestWorkspace.CreateCSharp(markups, exportProvider: GetExportProvider());
var solution = workspace.CurrentSolution;
var locations = new Dictionary<string, IList<LSP.Location>>();

foreach (var document in workspace.Documents)
{
var text = document.TextBuffer.AsTextContainer().CurrentText;
foreach (var kvp in document.AnnotatedSpans)
{
locations.GetOrAdd(kvp.Key, CreateLocation)
.AddRange(kvp.Value.Select(s => ProtocolConversions.TextSpanToLocation(s, text, new Uri(GetDocumentFilePathFromName(document.Name)))));
}

// Pass in the text without markup.
workspace.ChangeSolution(ChangeDocumentFilePathToValidURI(workspace.CurrentSolution, document, text));
}

return (workspace.CurrentSolution, locations);

// local functions
static List<LSP.Location> CreateLocation(string s) => new List<LSP.Location>();
}

// Private protected because LanguageServerProtocol is internal
private protected static LanguageServerProtocol GetLanguageServer(Solution solution)
{
var workspace = (TestWorkspace)solution.Workspace;
return workspace.ExportProvider.GetExportedValue<LanguageServerProtocol>();
}

private static string GetDocumentFilePathFromName(string documentName)
=> "C:\\" + documentName;

/// <summary>
/// Changes the document file path.
/// Adds/Removes the document instead of updating file path due to
/// https://github.com/dotnet/roslyn/issues/34837
/// </summary>
private static Solution ChangeDocumentFilePathToValidURI(Solution originalSolution, TestHostDocument originalDocument, SourceText text)
{
var documentName = originalDocument.Name;
var documentPath = GetDocumentFilePathFromName(documentName);

var solution = originalSolution.RemoveDocument(originalDocument.Id);

var newDocumentId = DocumentId.CreateNewId(originalDocument.Project.Id);
return solution.AddDocument(newDocumentId, documentName, text, filePath: documentPath);
}
}
}
Loading