Merge remote-tracking branch 'upstream/main' into features/cohost

This commit is contained in:
David Wengier 2024-01-26 21:09:00 +11:00
Родитель 5335952ad1 8e5fbd463e
Коммит 5c5b3e6e89
84 изменённых файлов: 1354 добавлений и 1231 удалений

Просмотреть файл

@ -103,6 +103,10 @@ csharp_style_unused_value_expression_statement_preference = discard_variable:non
# IDE0065
csharp_using_directive_placement = outside_namespace:suggestion
# Roslyn analyzers
dotnet_diagnostic.RS0006.severity = error
dotnet_diagnostic.RS0023.severity = error
# xUnit1004: Test methods should not be skipped
dotnet_diagnostic.xUnit1004.severity = refactoring

Просмотреть файл

@ -0,0 +1,50 @@
# Razor Basics
Razor is a templating language used in ASP.NET for creating dynamic web pages. It's not a programming language itself, but a markup syntax for embedding code (C# or VB.NET) into HTML.
In a Razor file, you can use a combination of several languages:
| Language | Usage | Supported in .NET Core and .NET 5+ |
| --- | --- | --- |
| **Razor syntax** | Used to embed and execute server-side code within HTML. | Yes |
| **C#** | The server-side language used within Razor templates. Most commonly used with Razor. | Yes |
| **HTML** | Used to structure the content on web pages. | Yes |
| **JavaScript** | Used for client-side scripting in Razor templates. | Yes |
| **CSS** | Used for styling web pages. | Yes |
| **VB.NET** | Can be used in Razor syntax in the older .NET Framework. | No |
Please note that while Razor syntax does support VB.NET in the older .NET Framework, VB.NET is not supported in .NET Core or .NET 5 and onwards. In these newer frameworks, only C# is supported.
## Razor File Types
Razor files typically come in three extensions: `.cshtml`, `.vbhtml`, and `.razor`. Each extension corresponds to a specific type of Razor file and determines its usage within an application:
| File Extension | Type | Description | Usage |
| --- | --- | --- | --- |
| `.cshtml` | Razor View | Part of the MVC (Model-View-Controller) pattern, where the View is responsible for the presentation logic. Located within the Views folder of an MVC application and associated with a Controller. | Used in MVC applications for complex scenarios where separation of concerns is important. |
| `.cshtml` | Razor Page | A page-based programming model that makes building web UI easier and more productive. Located within the Pages folder of a Razor Pages application and includes a `@page` directive at the top. | Used in Razor Pages applications for simpler scenarios where a full MVC model might be overkill. |
| `.razor` | Razor Component (Blazor) | Used in Blazor, a framework for building interactive client-side web UI with .NET. Each `.razor` file is a self-contained component that can include both the markup and the processing logic. | Used in Blazor applications for building interactive client-side web UIs. |
| `.vbhtml` | Razor View (VB.NET) | Part of the MVC (Model-View-Controller) pattern, where the View is responsible for the presentation logic. Located within the Views folder of an MVC application and associated with a Controller. | Used in older MVC applications written in VB.NET. |
## Razor Editors: Legacy vs New
| Aspect | Razor Legacy | Legacy .NET Core Razor Editor | New .NET Core Razor Editor |
| --- | --- | --- | --- |
| **Introduction** | Introduced with ASP.NET MVC 3. | Older Razor editor for ASP.NET Core projects. | Updated Razor editor introduced in Visual Studio 2019 version 16.8. |
| **Usage** | Used in ASP.NET MVC and ASP.NET Web Pages applications. | Used for editing Razor views and pages in ASP.NET Core projects. | Used for editing Razor views and pages in ASP.NET Core projects. |
| **Source code** | Closed source. | Closed source. | [Open source on GitHub](https://github.com/dotnet/razor/) |
| **File Extensions** | `.cshtml` for C#, `.vbhtml` for VB.NET. | `.cshtml` and `.razor` | `.cshtml` and `.razor` |
| **Functionality** | Creates dynamic web pages that combine HTML and server-side code. | Provides basic features like syntax highlighting and IntelliSense for Razor syntax. | Provides improved functionality and performance, including better IntelliSense, improved syntax highlighting, support for Razor formatting, better diagnostics, and features like "Go to Definition" and "Find All References" for Razor components and their parameters. |
| **Support** | Supported for maintaining existing applications. | Phased out, not recommended for new projects. | Actively supported and recommended for new projects. |
| **Configuration** | Used by default for .NET Framework applications. | The legacy .NET Core editor is off by default. | The new .NET Core editor is used by default. |
| **Implementation** | Monolithic design, language services implemented by the editor, no LSP or TextMate grammars, limited VS integration. | Same as Razor Legacy | Uses LSP for language services, TextMate grammars for syntax highlighting, integrated with VS editor API, includes Blazor support. |
## Razor Support Across ASP.NET Versions
Different versions of ASP.NET support different features of Razor. Here's a summary:
| TFM | Razor Support |
| --- | --- |
| **.NET Framework (<= 4.8)** | Supports Razor syntax with C# and VB.NET. Used in ASP.NET MVC and ASP.NET Web Pages applications. |
| **.NET Core 1.x - 3.1** | Supports Razor syntax with C# only. Used in ASP.NET Core MVC, Razor Pages applications, and had preview support for Blazor. |
| **.NET 5+** | Supports Razor syntax with C# only. Used in ASP.NET Core MVC, Razor Pages, and Blazor applications. |

Просмотреть файл

@ -90,9 +90,9 @@
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
<Sha>3a25a7f1cc446b60678ed25c9d829420d6321eba</Sha>
</Dependency>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24060.4">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.24074.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>888985fb9a9ae4cb30bca75f98af9126c839e660</Sha>
<Sha>96c2cee493aa1542c0b06a6498e0379eb11e005f</Sha>
<SourceBuild RepoName="arcade" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.DotNet.XliffTasks" Version="1.0.0-beta.23475.1" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">

Просмотреть файл

@ -21,6 +21,6 @@
"rollForward": "latestPatch"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24060.4"
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24074.2"
}
}

Просмотреть файл

@ -13,6 +13,13 @@ namespace Microsoft.AspNetCore.Razor.Language.Components;
internal class ComponentMarkupEncodingPass : ComponentIntermediateNodePassBase, IRazorOptimizationPass
{
private readonly RazorLanguageVersion _version;
public ComponentMarkupEncodingPass(RazorLanguageVersion version)
{
_version = version;
}
// Runs after ComponentMarkupBlockPass
public override int Order => ComponentMarkupDiagnosticPass.DefaultOrder + 20;
@ -29,7 +36,7 @@ internal class ComponentMarkupEncodingPass : ComponentIntermediateNodePassBase,
return;
}
var rewriter = new Rewriter();
var rewriter = new Rewriter(_version);
rewriter.Visit(documentNode);
}
@ -47,10 +54,37 @@ internal class ComponentMarkupEncodingPass : ComponentIntermediateNodePassBase,
private static readonly char[] EncodedCharacters = new[] { '\r', '\n', '\t', '<', '>' };
private readonly bool _avoidEncodingScripts;
private readonly Dictionary<string, string> _seenEntities = new Dictionary<string, string>(StringComparer.Ordinal);
private bool _avoidEncodingContent;
public Rewriter(RazorLanguageVersion version)
{
_avoidEncodingScripts = version.CompareTo(RazorLanguageVersion.Version_8_0) >= 0;
}
public override void VisitMarkupElement(MarkupElementIntermediateNode node)
{
// We don't want to HTML-encode literal content inside <script> tags.
var oldAvoidEncodingContent = _avoidEncodingContent;
_avoidEncodingContent = _avoidEncodingContent || (
_avoidEncodingScripts &&
string.Equals("script", node.TagName, StringComparison.OrdinalIgnoreCase));
base.VisitMarkupElement(node);
_avoidEncodingContent = oldAvoidEncodingContent;
}
public override void VisitHtml(HtmlContentIntermediateNode node)
{
if (_avoidEncodingContent)
{
node.SetEncoded();
return;
}
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i];

Просмотреть файл

@ -498,7 +498,7 @@ public class RazorProjectEngine
builder.Features.Add(new ComponentChildContentDiagnosticPass());
builder.Features.Add(new ComponentMarkupDiagnosticPass());
builder.Features.Add(new ComponentMarkupBlockPass(razorLanguageVersion));
builder.Features.Add(new ComponentMarkupEncodingPass());
builder.Features.Add(new ComponentMarkupEncodingPass(razorLanguageVersion));
}
private static void LoadExtensions(RazorProjectEngineBuilder builder, IReadOnlyList<RazorExtension> extensions)

Просмотреть файл

@ -15,7 +15,7 @@ public class ComponentMarkupEncodingPassTest
{
public ComponentMarkupEncodingPassTest()
{
Pass = new ComponentMarkupEncodingPass();
Pass = new ComponentMarkupEncodingPass(RazorLanguageVersion.Latest);
ProjectEngine = RazorProjectEngine.Create(
RazorConfiguration.Default,
RazorProjectFileSystem.Create(Environment.CurrentDirectory),

Просмотреть файл

@ -587,6 +587,57 @@ public sealed class RazorSourceGeneratorComponentTests : RazorSourceGeneratorTes
await VerifyRazorPageMatchesBaselineAsync(compilation, "Views_Home_Index");
}
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/aspnetcore/issues/52547")]
public async Task ScriptTag_WithVariable([CombinatorialValues("7.0", "8.0", "Latest")] string razorLangVersion)
{
// Arrange
var code = """
@{ var msg = "What's up"; }
<script>console.log('@msg');</script>
<div>console.log('@msg');</div>
<script>console.log('No variable');</script>
<div>console.log('No variable');</div>
<script>
console.log('@msg');
</script>
<div>
console.log('@msg');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>
""";
var project = CreateTestProject(new()
{
["Views/Home/Index.cshtml"] = $"""
{code}
@(await Html.RenderComponentAsync<MyApp.Shared.Component1>(RenderMode.Static))
""",
["Shared/Component1.razor"] = $"""
Component:
{code}
""",
});
var compilation = await project.GetCompilationAsync();
var driver = await GetDriverAsync(project, options =>
{
options.TestGlobalOptions["build_property.RazorLangVersion"] = razorLangVersion;
});
// Act
var result = RunGenerator(compilation!, ref driver, out compilation);
// Assert
result.Diagnostics.Verify();
Assert.Equal(2, result.GeneratedSources.Length);
var suffix = razorLangVersion == "7.0" ? "7" : "8";
result.VerifyOutputsMatchBaseline(suffix: suffix);
await VerifyRazorPageMatchesBaselineAsync(compilation, "Views_Home_Index", suffix: suffix);
}
[Fact, WorkItem("https://github.com/dotnet/razor/issues/9051")]
public async Task LineMapping()
{

Просмотреть файл

@ -210,7 +210,7 @@ public abstract class RazorSourceGeneratorTestsBase
}
protected static async Task VerifyRazorPageMatchesBaselineAsync(Compilation compilation, string name,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
var html = await RenderRazorPageAsync(compilation, name);
Extensions.VerifyTextMatchesBaseline(
@ -218,7 +218,8 @@ public abstract class RazorSourceGeneratorTestsBase
fileName: name,
extension: "html",
testPath: testPath,
testName: testName);
testName: testName,
suffix: suffix);
}
protected static Project CreateTestProject(
@ -420,21 +421,22 @@ internal static class Extensions
return result;
}
private static string CreateBaselineDirectory(string testPath, string testName)
private static string CreateBaselineDirectory(string testPath, string testName, string suffix)
{
var baselineDirectory = Path.Join(
_testProjectRoot,
"TestFiles",
Path.GetFileNameWithoutExtension(testPath)!,
testName);
testName,
suffix);
Directory.CreateDirectory(baselineDirectory);
return baselineDirectory;
}
public static GeneratorRunResult VerifyOutputsMatchBaseline(this GeneratorRunResult result,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
var baselineDirectory = CreateBaselineDirectory(testPath, testName);
var baselineDirectory = CreateBaselineDirectory(testPath, testName, suffix);
var touchedFiles = new HashSet<string>();
foreach (var source in result.GeneratedSources)
@ -453,10 +455,10 @@ internal static class Extensions
}
public static void VerifyTextMatchesBaseline(string actualText, string fileName, string extension,
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "")
[CallerFilePath] string testPath = "", [CallerMemberName] string testName = "", string suffix = "")
{
// Create output directory.
var baselineDirectory = CreateBaselineDirectory(testPath, testName);
var baselineDirectory = CreateBaselineDirectory(testPath, testName, suffix);
// Generate baseline if enabled.
var baselinePath = Path.Join(baselineDirectory, $"{fileName}.{extension}");

Просмотреть файл

@ -0,0 +1,87 @@
#pragma checksum "Shared/Component1.razor" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b72b3eb93cc4a906714929a4849d9f7aac2ef62a"
// <auto-generated/>
#pragma warning disable 1591
namespace MyApp.Shared
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class Component1 : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.AddMarkupContent(0, "Component:\r\n");
#nullable restore
#line 2 "Shared/Component1.razor"
var msg = "What's up";
#line default
#line hidden
#nullable disable
__builder.OpenElement(1, "script");
__builder.AddContent(2, "console.log(\'");
#nullable restore
#line (3,23)-(3,26) 24 "Shared/Component1.razor"
__builder.AddContent(3, msg);
#line default
#line hidden
#nullable disable
__builder.AddContent(4, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(5, "\r\n");
__builder.OpenElement(6, "div");
__builder.AddContent(7, "console.log(\'");
#nullable restore
#line (4,20)-(4,23) 24 "Shared/Component1.razor"
__builder.AddContent(8, msg);
#line default
#line hidden
#nullable disable
__builder.AddContent(9, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(10, "\r\n");
__builder.OpenElement(11, "script");
__builder.AddContent(12, "console.log(\'No variable\');");
__builder.CloseElement();
__builder.AddMarkupContent(13, "\r\n");
__builder.AddMarkupContent(14, "<div>console.log(\'No variable\');</div>\r\n");
__builder.OpenElement(15, "script");
__builder.AddMarkupContent(16, "\r\n console.log(\'");
#nullable restore
#line (8,19)-(8,22) 25 "Shared/Component1.razor"
__builder.AddContent(17, msg);
#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(18, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(19, "\r\n");
__builder.OpenElement(20, "div");
__builder.AddMarkupContent(21, "\r\n console.log(\'");
#nullable restore
#line (11,19)-(11,22) 25 "Shared/Component1.razor"
__builder.AddContent(22, msg);
#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(23, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(24, "\r\n");
__builder.OpenElement(25, "script");
__builder.AddMarkupContent(26, "\r\n console.log(\'No variable\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(27, "\r\n");
__builder.AddMarkupContent(28, "<div>\r\n console.log(\'No variable\');\r\n</div>");
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1,33 @@
<script>console.log('What&#x27;s up');</script>
<div>console.log('What&#x27;s up');</div>
<script>console.log('No variable');</script>
<div>console.log('No variable');</div>
<script>
console.log('What&#x27;s up');
</script>
<div>
console.log('What&#x27;s up');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>
Component:
<script>console.log(\u0027What\u0027s up\u0027);</script>
<div>console.log(&#x27;What&#x27;s up&#x27;);</div>
<script>console.log(\u0027No variable\u0027);</script>
<div>console.log('No variable');</div>
<script>
console.log('What\u0027s up');
</script>
<div>
console.log('What&#x27;s up');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>

Просмотреть файл

@ -0,0 +1,95 @@
#pragma checksum "Views/Home/Index.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "87d8a07c5693b48e5469d0cbc37b8ccc95b4cce2"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCoreGeneratedDocument.Views_Home_Index), @"mvc.1.0.view", @"/Views/Home/Index.cshtml")]
namespace AspNetCoreGeneratedDocument
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Mvc;
using global::Microsoft.AspNetCore.Mvc.Rendering;
using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Views/Home/Index.cshtml")]
[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
#nullable restore
internal sealed class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
#nullable disable
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
#nullable restore
#line 1 "Views/Home/Index.cshtml"
var msg = "What's up";
#line default
#line hidden
#nullable disable
WriteLiteral("<script>console.log(\'");
#nullable restore
#line (2,23)-(2,26) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');</script>\r\n<div>console.log(\'");
#nullable restore
#line (3,20)-(3,23) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');</div>\r\n<script>console.log(\'No variable\');</script>\r\n<div>console.log(\'No variable\');</div>\r\n<script>\r\n console.log(\'");
#nullable restore
#line (7,19)-(7,22) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');\r\n</script>\r\n<div>\r\n console.log(\'");
#nullable restore
#line (10,19)-(10,22) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');\r\n</div>\r\n<script>\r\n console.log(\'No variable\');\r\n</script>\r\n<div>\r\n console.log(\'No variable\');\r\n</div>\r\n");
#nullable restore
#line (18,3)-(18,78) 6 "Views/Home/Index.cshtml"
Write(await Html.RenderComponentAsync<MyApp.Shared.Component1>(RenderMode.Static));
#line default
#line hidden
#nullable disable
}
#pragma warning restore 1998
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1,81 @@
#pragma checksum "Shared/Component1.razor" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "b72b3eb93cc4a906714929a4849d9f7aac2ef62a"
// <auto-generated/>
#pragma warning disable 1591
namespace MyApp.Shared
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class Component1 : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.AddMarkupContent(0, "Component:\r\n");
#nullable restore
#line 2 "Shared/Component1.razor"
var msg = "What's up";
#line default
#line hidden
#nullable disable
__builder.OpenElement(1, "script");
__builder.AddMarkupContent(2, "console.log(\'");
#nullable restore
#line (3,23)-(3,26) 24 "Shared/Component1.razor"
__builder.AddContent(3, msg);
#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(4, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(5, "\r\n");
__builder.OpenElement(6, "div");
__builder.AddContent(7, "console.log(\'");
#nullable restore
#line (4,20)-(4,23) 24 "Shared/Component1.razor"
__builder.AddContent(8, msg);
#line default
#line hidden
#nullable disable
__builder.AddContent(9, "\');");
__builder.CloseElement();
__builder.AddMarkupContent(10, "\r\n");
__builder.AddMarkupContent(11, "<script>console.log(\'No variable\');</script>\r\n");
__builder.AddMarkupContent(12, "<div>console.log(\'No variable\');</div>\r\n");
__builder.OpenElement(13, "script");
__builder.AddMarkupContent(14, "\r\n console.log(\'");
#nullable restore
#line (8,19)-(8,22) 25 "Shared/Component1.razor"
__builder.AddContent(15, msg);
#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(16, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(17, "\r\n");
__builder.OpenElement(18, "div");
__builder.AddMarkupContent(19, "\r\n console.log(\'");
#nullable restore
#line (11,19)-(11,22) 25 "Shared/Component1.razor"
__builder.AddContent(20, msg);
#line default
#line hidden
#nullable disable
__builder.AddMarkupContent(21, "\');\r\n");
__builder.CloseElement();
__builder.AddMarkupContent(22, "\r\n");
__builder.AddMarkupContent(23, "<script>\r\n console.log(\'No variable\');\r\n</script>\r\n");
__builder.AddMarkupContent(24, "<div>\r\n console.log(\'No variable\');\r\n</div>");
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1,33 @@
<script>console.log('What&#x27;s up');</script>
<div>console.log('What&#x27;s up');</div>
<script>console.log('No variable');</script>
<div>console.log('No variable');</div>
<script>
console.log('What&#x27;s up');
</script>
<div>
console.log('What&#x27;s up');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>
Component:
<script>console.log('What\u0027s up');</script>
<div>console.log(&#x27;What&#x27;s up&#x27;);</div>
<script>console.log('No variable');</script>
<div>console.log('No variable');</div>
<script>
console.log('What\u0027s up');
</script>
<div>
console.log('What&#x27;s up');
</div>
<script>
console.log('No variable');
</script>
<div>
console.log('No variable');
</div>

Просмотреть файл

@ -0,0 +1,95 @@
#pragma checksum "Views/Home/Index.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "87d8a07c5693b48e5469d0cbc37b8ccc95b4cce2"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCoreGeneratedDocument.Views_Home_Index), @"mvc.1.0.view", @"/Views/Home/Index.cshtml")]
namespace AspNetCoreGeneratedDocument
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Mvc;
using global::Microsoft.AspNetCore.Mvc.Rendering;
using global::Microsoft.AspNetCore.Mvc.ViewFeatures;
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Views/Home/Index.cshtml")]
[global::System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute]
#nullable restore
internal sealed class Views_Home_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
#nullable disable
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
#nullable restore
#line 1 "Views/Home/Index.cshtml"
var msg = "What's up";
#line default
#line hidden
#nullable disable
WriteLiteral("<script>console.log(\'");
#nullable restore
#line (2,23)-(2,26) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');</script>\r\n<div>console.log(\'");
#nullable restore
#line (3,20)-(3,23) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');</div>\r\n<script>console.log(\'No variable\');</script>\r\n<div>console.log(\'No variable\');</div>\r\n<script>\r\n console.log(\'");
#nullable restore
#line (7,19)-(7,22) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');\r\n</script>\r\n<div>\r\n console.log(\'");
#nullable restore
#line (10,19)-(10,22) 6 "Views/Home/Index.cshtml"
Write(msg);
#line default
#line hidden
#nullable disable
WriteLiteral("\');\r\n</div>\r\n<script>\r\n console.log(\'No variable\');\r\n</script>\r\n<div>\r\n console.log(\'No variable\');\r\n</div>\r\n");
#nullable restore
#line (18,3)-(18,78) 6 "Views/Home/Index.cshtml"
Write(await Html.RenderComponentAsync<MyApp.Shared.Component1>(RenderMode.Static));
#line default
#line hidden
#nullable disable
}
#pragma warning restore 1998
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } = default!;
#nullable disable
#nullable restore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; } = default!;
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -120,8 +120,9 @@ public class RazorSemanticTokensBenchmark : RazorLanguageServerBenchmarkBase
private void EnsureServicesInitialized()
{
var languageServer = RazorLanguageServer.GetInnerLanguageServerForTesting();
var legend = new RazorSemanticTokensLegend(new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true });
RazorSemanticTokenService = languageServer.GetRequiredService<IRazorSemanticTokensInfoService>();
RazorSemanticTokenService.ApplyCapabilities(new(), new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true });
RazorSemanticTokenService.SetTokensLegend(legend);
VersionCache = languageServer.GetRequiredService<IDocumentVersionCache>();
ProjectSnapshotManagerDispatcher = languageServer.GetRequiredService<ProjectSnapshotManagerDispatcher>();
}

Просмотреть файл

@ -58,7 +58,7 @@ public class RazorSemanticTokensScrollingBenchmark : RazorLanguageServerBenchmar
DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version: 1);
SemanticTokensLegend = new RazorSemanticTokensLegend(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });
RazorSemanticTokenService.ApplyCapabilities(new(), new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true });
RazorSemanticTokenService.SetTokensLegend(SemanticTokensLegend);
var text = await DocumentSnapshot.GetTextAsync().ConfigureAwait(false);
Range = new Range

Просмотреть файл

@ -1,24 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.Microbenchmarks;
public abstract partial class ProjectSnapshotManagerBenchmarkBase
{
private class StaticTagHelperResolver(ImmutableArray<TagHelperDescriptor> tagHelpers) : ITagHelperResolver
{
public ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(
Project workspaceProject,
IProjectSnapshot projectSnapshot,
CancellationToken cancellationToken)
=> new(tagHelpers);
}
}

Просмотреть файл

@ -8,9 +8,7 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.Microbenchmarks;
@ -20,7 +18,6 @@ public abstract partial class ProjectSnapshotManagerBenchmarkBase
internal HostProject HostProject { get; }
internal ImmutableArray<HostDocument> Documents { get; }
internal ImmutableArray<TextLoader> TextLoaders { get; }
internal ITagHelperResolver TagHelperResolver { get; }
protected string RepoRoot { get; }
protected ProjectSnapshotManagerBenchmarkBase(int documentCount = 100)
@ -59,20 +56,15 @@ public abstract partial class ProjectSnapshotManagerBenchmarkBase
}
Documents = documents.ToImmutable();
var tagHelpers = CommonResources.LegacyTagHelpers;
TagHelperResolver = new StaticTagHelperResolver(tagHelpers);
}
internal DefaultProjectSnapshotManager CreateProjectSnapshotManager()
{
var services = TestServices.Create(
[TagHelperResolver],
Array.Empty<ILanguageService>());
var services = TestServices.Create([], []);
return new DefaultProjectSnapshotManager(
new TestErrorReporter(),
Array.Empty<IProjectSnapshotChangeTrigger>(),
triggers: [],
#pragma warning disable CA2000 // Dispose objects before losing scope
new AdhocWorkspace(services),
StaticProjectEngineFactoryProvider.Instance,

Просмотреть файл

@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Cohost;
// NOTE: This is not a "normal" MEF export (ie, exporting an interface) purely because of a strange desire to keep API in
// RazorCohostRequestContextExtensions looking like the previous code in the non-cohost world.
[Shared]
[ExportRazorStatelessLspService(typeof(CohostDocumentContextFactory))]
[method: ImportingConstructor]
internal class CohostDocumentContextFactory(DocumentSnapshotFactory documentSnapshotFactory, IDocumentVersionCache documentVersionCache) : AbstractRazorLspService

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
@ -36,11 +35,6 @@ internal class CohostDocumentSnapshot(TextDocument textDocument, IProjectSnapsho
public bool TryGetTextVersion(out VersionStamp result) => _textDocument.TryGetTextVersion(out result);
public ImmutableArray<IDocumentSnapshot> GetImports()
{
return DocumentState.GetImportsCore(Project, FilePath.AssumeNotNull(), FileKind.AssumeNotNull());
}
public async Task<RazorCodeDocument> GetGeneratedOutputAsync()
{
// TODO: We don't need to worry about locking if we get called from the didOpen/didChange LSP requests, as CLaSP

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Common;
internal static class VSInternalServerCapabilitiesExtensions
{
public static void EnableDocumentColorProvider(this VSInternalServerCapabilities serverCapabilities)
{
serverCapabilities.DocumentColorProvider = new DocumentColorOptions();
}
public static void EnableSemanticTokens(this VSInternalServerCapabilities serverCapabilities, SemanticTokensLegend legend)
{
serverCapabilities.SemanticTokensOptions = new SemanticTokensOptions
{
Full = false,
Legend = legend,
Range = true,
};
}
}

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.VisualStudio.LanguageServer.Protocol;
@ -18,7 +19,7 @@ internal sealed class DocumentColorEndpoint(IDocumentColorService documentColorS
public bool MutatesSolutionState => false;
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
=> _documentColorService.ApplyCapabilities(serverCapabilities, clientCapabilities);
=> serverCapabilities.EnableDocumentColorProvider();
public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentColorParams request)
=> request.TextDocument;

Просмотреть файл

@ -13,11 +13,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentColor;
[method: ImportingConstructor]
internal sealed class DocumentColorService() : IDocumentColorService
{
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
{
serverCapabilities.DocumentColorProvider = new DocumentColorOptions();
}
public async Task<ColorInformation[]> GetColorInformationAsync(IClientConnection clientConnection, DocumentColorParams request, VersionedDocumentContext? documentContext, CancellationToken cancellationToken)
{
// Workaround for Web Tools bug https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1743689 where they sometimes

Просмотреть файл

@ -7,7 +7,7 @@ using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentColor;
internal interface IDocumentColorService : ICapabilitiesProvider
internal interface IDocumentColorService
{
Task<ColorInformation[]> GetColorInformationAsync(IClientConnection clientConnection, DocumentColorParams request, VersionedDocumentContext? documentContext, CancellationToken cancellationToken);
}

Просмотреть файл

@ -77,6 +77,9 @@ internal sealed class RazorLanguageServerWrapper : IDisposable
var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(output, input, messageFormatter));
// Get more information about exceptions that occur during RPC method invocations.
jsonRpc.ExceptionStrategy = ExceptionProcessing.ISerializable;
return jsonRpc;
}

Просмотреть файл

@ -3,6 +3,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.VisualStudio.LanguageServer.Protocol;
@ -23,7 +24,9 @@ internal sealed class SemanticTokensRangeEndpoint(
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
{
_semanticTokensInfoService.ApplyCapabilities(serverCapabilities, clientCapabilities);
var legend = new RazorSemanticTokensLegend(clientCapabilities);
serverCapabilities.EnableSemanticTokens(legend.Legend);
_semanticTokensInfoService.SetTokensLegend(legend);
}
public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParams request)

Просмотреть файл

@ -7,7 +7,8 @@ using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
internal interface IRazorSemanticTokensInfoService : ICapabilitiesProvider
internal interface IRazorSemanticTokensInfoService
{
Task<SemanticTokens?> GetSemanticTokensAsync(IClientConnection clientConnection, TextDocumentIdentifier textDocumentIdentifier, Range range, VersionedDocumentContext documentContext, bool colorBackground, CancellationToken cancellationToken);
void SetTokensLegend(RazorSemanticTokensLegend legend);
}

Просмотреть файл

@ -44,16 +44,10 @@ internal class RazorSemanticTokensInfoService(
private RazorSemanticTokensLegend? _razorSemanticTokensLegend;
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
[MemberNotNull(nameof(_razorSemanticTokensLegend))]
public void SetTokensLegend(RazorSemanticTokensLegend legend)
{
_razorSemanticTokensLegend = new RazorSemanticTokensLegend(clientCapabilities);
serverCapabilities.SemanticTokensOptions = new SemanticTokensOptions
{
Full = false,
Legend = _razorSemanticTokensLegend.Legend,
Range = true,
};
_razorSemanticTokensLegend = legend;
}
public async Task<SemanticTokens?> GetSemanticTokensAsync(

Просмотреть файл

@ -5,12 +5,11 @@ using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor.Workspaces;
internal interface ITagHelperResolver : IWorkspaceService
internal interface ITagHelperResolver
{
ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(
Project workspaceProject,

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
@ -27,9 +26,6 @@ internal class DocumentSnapshot : IDocumentSnapshot
State = state ?? throw new ArgumentNullException(nameof(state));
}
public virtual ImmutableArray<IDocumentSnapshot> GetImports()
=> State.GetImports(ProjectInternal);
public Task<SourceText> GetTextAsync()
=> State.GetTextAsync();

Просмотреть файл

@ -6,6 +6,7 @@ using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.PooledObjects;
using Microsoft.CodeAnalysis.Text;
@ -80,11 +81,6 @@ internal class DocumentState
return ComputedState.GetGeneratedOutputAndVersionAsync(project, document);
}
public ImmutableArray<IDocumentSnapshot> GetImports(ProjectSnapshot project)
{
return GetImportsCore(project, HostDocument.FilePath, HostDocument.FileKind);
}
public async Task<SourceText> GetTextAsync()
{
if (TryGetText(out var text))
@ -502,7 +498,7 @@ internal class DocumentState
internal static async Task<ImmutableArray<ImportItem>> GetImportsAsync(IDocumentSnapshot document)
{
var imports = document.GetImports();
var imports = DocumentState.GetImportsCore(document.Project, document.FilePath.AssumeNotNull(), document.FileKind.AssumeNotNull());
using var result = new PooledArrayBuilder<ImportItem>(imports.Length);
foreach (var snapshot in imports)

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
@ -17,8 +16,6 @@ internal interface IDocumentSnapshot
IProjectSnapshot Project { get; }
bool SupportsOutput { get; }
ImmutableArray<IDocumentSnapshot> GetImports();
Task<SourceText> GetTextAsync();
Task<VersionStamp> GetTextVersionAsync();
Task<RazorCodeDocument> GetGeneratedOutputAsync();

Просмотреть файл

@ -2,7 +2,6 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
@ -36,9 +35,6 @@ internal class ImportDocumentSnapshot : IDocumentSnapshot
public Task<RazorCodeDocument> GetGeneratedOutputAsync()
=> throw new NotSupportedException();
public ImmutableArray<IDocumentSnapshot> GetImports()
=> ImmutableArray<IDocumentSnapshot>.Empty;
public async Task<SourceText> GetTextAsync()
{
using (var stream = _importItem.Read())

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
@ -20,43 +18,34 @@ namespace Microsoft.CodeAnalysis.Razor;
[Shared]
[Export(typeof(IProjectWorkspaceStateGenerator))]
[Export(typeof(IProjectSnapshotChangeTrigger))]
[method: ImportingConstructor]
internal sealed class ProjectWorkspaceStateGenerator(
IProjectSnapshotManagerAccessor projectManagerAccessor,
ITagHelperResolver tagHelperResolver,
ProjectSnapshotManagerDispatcher dispatcher,
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter)
: IProjectWorkspaceStateGenerator, IProjectSnapshotChangeTrigger, IDisposable
: IProjectWorkspaceStateGenerator, IDisposable
{
// Internal for testing
internal readonly Dictionary<ProjectKey, UpdateItem> Updates = new();
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter ?? throw new ArgumentNullException(nameof(telemetryReporter));
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor = projectManagerAccessor;
private readonly ITagHelperResolver _tagHelperResolver = tagHelperResolver;
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
private readonly IErrorReporter _errorReporter = errorReporter;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(initialCount: 1);
private ProjectSnapshotManagerBase _projectManager;
private ITagHelperResolver _tagHelperResolver;
private bool _disposed;
// Used in unit tests to ensure we can control when background work starts.
public ManualResetEventSlim BlockBackgroundWorkStart { get; set; }
public ManualResetEventSlim? BlockBackgroundWorkStart { get; set; }
// Used in unit tests to ensure we can know when background work finishes.
public ManualResetEventSlim NotifyBackgroundWorkCompleted { get; set; }
public ManualResetEventSlim? NotifyBackgroundWorkCompleted { get; set; }
public void Initialize(ProjectSnapshotManagerBase projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
_tagHelperResolver = _projectManager.Workspace.Services.GetRequiredService<ITagHelperResolver>();
}
public void Update(Project workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
public void Update(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
{
if (projectSnapshot is null)
{
@ -119,7 +108,7 @@ internal sealed class ProjectWorkspaceStateGenerator(
BlockBackgroundWorkStart?.Set();
}
private async Task UpdateWorkspaceStateAsync(Project workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
private async Task UpdateWorkspaceStateAsync(Project? workspaceProject, IProjectSnapshot projectSnapshot, CancellationToken cancellationToken)
{
// We fire this up on a background thread so we could have been disposed already, and if so, waiting on our semaphore
// throws an exception.
@ -163,7 +152,7 @@ internal sealed class ProjectWorkspaceStateGenerator(
if (workspaceProject != null)
{
var csharpLanguageVersion = LanguageVersion.Default;
var csharpParseOptions = (CSharpParseOptions)workspaceProject.ParseOptions;
var csharpParseOptions = workspaceProject.ParseOptions as CSharpParseOptions;
if (csharpParseOptions is null)
{
Debug.Fail("Workspace project should always have CSharp parse options.");
@ -203,7 +192,7 @@ internal sealed class ProjectWorkspaceStateGenerator(
new Property("result", "error"));
await _dispatcher.RunOnDispatcherThreadAsync(
() => _projectManager.ReportError(ex, projectSnapshot),
() => _errorReporter.ReportError(ex, projectSnapshot),
// Don't allow errors to be cancelled
CancellationToken.None).ConfigureAwait(false);
return;
@ -236,7 +225,7 @@ internal sealed class ProjectWorkspaceStateGenerator(
{
// This is something totally unexpected, let's just send it over to the project manager.
await _dispatcher.RunOnDispatcherThreadAsync(
() => _projectManager.ReportError(ex),
() => _errorReporter.ReportError(ex),
// Don't allow errors to be cancelled
CancellationToken.None).ConfigureAwait(false);
}
@ -264,7 +253,7 @@ internal sealed class ProjectWorkspaceStateGenerator(
{
_dispatcher.AssertDispatcherThread();
_projectManager.ProjectWorkspaceStateChanged(projectKey, workspaceStateChange);
_projectManagerAccessor.Instance.ProjectWorkspaceStateChanged(projectKey, workspaceStateChange);
}
private void OnStartingBackgroundWork()
@ -285,26 +274,10 @@ internal sealed class ProjectWorkspaceStateGenerator(
}
// Internal for testing
internal class UpdateItem
internal class UpdateItem(Task task, CancellationTokenSource cts)
{
public UpdateItem(Task task, CancellationTokenSource cts)
{
if (task is null)
{
throw new ArgumentNullException(nameof(task));
}
public Task Task { get; } = task;
if (cts is null)
{
throw new ArgumentNullException(nameof(cts));
}
Task = task;
Cts = cts;
}
public Task Task { get; }
public CancellationTokenSource Cts { get; }
public CancellationTokenSource Cts { get; } = cts;
}
}

Просмотреть файл

@ -1,27 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Razor;
internal partial class TagHelperResolverFactory
{
private sealed class Resolver(ITelemetryReporter telemetryReporter) : ITagHelperResolver
{
private readonly CompilationTagHelperResolver _resolver = new(telemetryReporter);
public ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(
Project workspaceProject,
IProjectSnapshot projectSnapshot,
CancellationToken cancellationToken)
=> _resolver.GetTagHelpersAsync(workspaceProject, projectSnapshot.GetProjectEngine(), cancellationToken);
}
}

Просмотреть файл

@ -1,19 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Razor;
[Shared]
[ExportWorkspaceServiceFactory(typeof(ITagHelperResolver), ServiceLayer.Default)]
[method: ImportingConstructor]
internal partial class TagHelperResolverFactory(ITelemetryReporter telemetryReporter) : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new Resolver(telemetryReporter);
}

Просмотреть файл

@ -1,25 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Remote.Razor;
[Shared]
[ExportWorkspaceServiceFactory(typeof(ITagHelperResolver), ServiceLayer.Host)]
[method: ImportingConstructor]
internal class OOPTagHelperResolverFactory(
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter) : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new OOPTagHelperResolver(
workspaceServices.Workspace,
errorReporter,
telemetryReporter);
}

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
@ -18,21 +19,17 @@ using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.CodeAnalysis.Remote.Razor;
internal class OOPTagHelperResolver : ITagHelperResolver
[Export(typeof(ITagHelperResolver))]
[method: ImportingConstructor]
internal class OutOfProcTagHelperResolver(
IProjectSnapshotManagerAccessor projectManagerAccessor,
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter) : ITagHelperResolver
{
private readonly Workspace _workspace;
private readonly IErrorReporter _errorReporter;
private readonly CompilationTagHelperResolver _innerResolver;
private readonly TagHelperResultCache _resultCache;
public OOPTagHelperResolver(Workspace workspace, IErrorReporter errorReporter, ITelemetryReporter telemetryReporter)
{
_errorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter));
_workspace = workspace ?? throw new ArgumentNullException(nameof(workspace));
_innerResolver = new CompilationTagHelperResolver(telemetryReporter);
_resultCache = new TagHelperResultCache();
}
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor = projectManagerAccessor;
private readonly IErrorReporter _errorReporter = errorReporter;
private readonly CompilationTagHelperResolver _innerResolver = new(telemetryReporter);
private readonly TagHelperResultCache _resultCache = new();
public async ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(
Project workspaceProject,
@ -75,7 +72,7 @@ internal class OOPTagHelperResolver : ITagHelperResolver
//
// This will change in the future to an easier to consume API but for VS RTM this is what we have.
var remoteClient = await RazorRemoteHostClient.TryGetClientAsync(
_workspace.Services,
_projectManagerAccessor.Instance.Workspace.Services,
RazorServiceDescriptors.TagHelperProviderServiceDescriptors,
RazorRemoteServiceCallbackDispatcherRegistry.Empty,
cancellationToken);

Просмотреть файл

@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Threading;
@ -24,7 +25,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
private readonly JoinableTaskContext _joinableTaskContext;
private readonly string _filePath;
private readonly string _projectPath;
private readonly ProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly WorkspaceEditorSettings _workspaceEditorSettings;
private readonly ITextBuffer _textBuffer;
private readonly ImportDocumentManager _importDocumentManager;
@ -41,7 +42,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
JoinableTaskContext joinableTaskContext,
string filePath,
string projectPath,
ProjectSnapshotManager projectManager,
IProjectSnapshotManagerAccessor projectManagerAccessor,
WorkspaceEditorSettings workspaceEditorSettings,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ITextBuffer textBuffer,
@ -67,9 +68,9 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
throw new ArgumentNullException(nameof(projectPath));
}
if (projectManager is null)
if (projectManagerAccessor is null)
{
throw new ArgumentNullException(nameof(projectManager));
throw new ArgumentNullException(nameof(projectManagerAccessor));
}
if (workspaceEditorSettings is null)
@ -96,7 +97,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
_joinableTaskContext = joinableTaskContext;
_filePath = filePath;
_projectPath = projectPath;
_projectManager = projectManager;
_projectManagerAccessor = projectManagerAccessor;
_workspaceEditorSettings = workspaceEditorSettings;
_textBuffer = textBuffer;
_importDocumentManager = importDocumentManager;
@ -180,7 +181,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
_projectSnapshot = GetOrCreateProject(_projectPath);
_isSupportedProject = true;
_projectManager.Changed += ProjectManager_Changed;
_projectManagerAccessor.Instance.Changed += ProjectManager_Changed;
_workspaceEditorSettings.Changed += EditorSettingsManager_Changed;
_importDocumentManager.Changed += Import_Changed;
@ -193,9 +194,11 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
{
_dispatcher.AssertDispatcherThread();
var projectKey = _projectManager.GetAllProjectKeys(projectPath).FirstOrDefault();
var projectManager = _projectManagerAccessor.Instance;
if (_projectManager.GetLoadedProject(projectKey) is not { } project)
var projectKey = projectManager.GetAllProjectKeys(projectPath).FirstOrDefault();
if (projectManager.GetLoadedProject(projectKey) is not { } project)
{
return new EphemeralProjectSnapshot(_projectEngineFactoryProvider, projectPath);
}
@ -214,7 +217,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
_importDocumentManager.OnUnsubscribed(this);
_projectManager.Changed -= ProjectManager_Changed;
_projectManagerAccessor.Instance.Changed -= ProjectManager_Changed;
_workspaceEditorSettings.Changed -= EditorSettingsManager_Changed;
_importDocumentManager.Changed -= Import_Changed;
@ -246,7 +249,7 @@ internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase))
{
// This will be the new snapshot unless the project was removed.
_projectSnapshot = _projectManager.GetLoadedProject(e.ProjectKey);
_projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(e.ProjectKey);
switch (e.Kind)
{

Просмотреть файл

@ -6,7 +6,7 @@ using System.Diagnostics;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Threading;
@ -19,14 +19,14 @@ internal class DefaultVisualStudioDocumentTrackerFactory : VisualStudioDocumentT
private readonly ITextDocumentFactoryService _textDocumentFactory;
private readonly ProjectPathProvider _projectPathProvider;
private readonly ImportDocumentManager _importDocumentManager;
private readonly ProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly WorkspaceEditorSettings _workspaceEditorSettings;
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
public DefaultVisualStudioDocumentTrackerFactory(
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext,
ProjectSnapshotManager projectManager,
IProjectSnapshotManagerAccessor projectManagerAccessor,
WorkspaceEditorSettings workspaceEditorSettings,
ProjectPathProvider projectPathProvider,
ITextDocumentFactoryService textDocumentFactory,
@ -35,7 +35,7 @@ internal class DefaultVisualStudioDocumentTrackerFactory : VisualStudioDocumentT
{
_dispatcher = dispatcher;
_joinableTaskContext = joinableTaskContext;
_projectManager = projectManager;
_projectManagerAccessor = projectManagerAccessor;
_workspaceEditorSettings = workspaceEditorSettings;
_projectPathProvider = projectPathProvider;
_textDocumentFactory = textDocumentFactory;
@ -63,7 +63,7 @@ internal class DefaultVisualStudioDocumentTrackerFactory : VisualStudioDocumentT
var filePath = textDocument.FilePath;
var tracker = new DefaultVisualStudioDocumentTracker(
_dispatcher, _joinableTaskContext, filePath, projectPath, _projectManager, _workspaceEditorSettings, _projectEngineFactoryProvider, textBuffer, _importDocumentManager);
_dispatcher, _joinableTaskContext, filePath, projectPath, _projectManagerAccessor, _workspaceEditorSettings, _projectEngineFactoryProvider, textBuffer, _importDocumentManager);
return tracker;
}

Просмотреть файл

@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Threading;
@ -19,12 +19,12 @@ namespace Microsoft.VisualStudio.Editor.Razor;
internal class DefaultVisualStudioDocumentTrackerFactoryFactory(
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext,
IProjectSnapshotManagerAccessor projectManagerAccessor,
ITextDocumentFactoryService textDocumentFactory,
IProjectEngineFactoryProvider projectEngineFactoryProvider) : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
var projectManager = languageServices.GetRequiredService<ProjectSnapshotManager>();
var workspaceEditorSettings = languageServices.GetRequiredService<WorkspaceEditorSettings>();
var importDocumentManager = languageServices.GetRequiredService<ImportDocumentManager>();
@ -33,7 +33,7 @@ internal class DefaultVisualStudioDocumentTrackerFactoryFactory(
return new DefaultVisualStudioDocumentTrackerFactory(
dispatcher,
joinableTaskContext,
projectManager,
projectManagerAccessor,
workspaceEditorSettings,
projectPathProvider,
textDocumentFactory,

Просмотреть файл

@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.Extensions.Internal;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Threading;
using static Microsoft.VisualStudio.Editor.Razor.BackgroundParser;
@ -36,7 +37,7 @@ internal class DefaultVisualStudioRazorParser : VisualStudioRazorParser, IDispos
private readonly object _idleLock = new();
private readonly object _updateStateLock = new();
private readonly VisualStudioCompletionBroker _completionBroker;
private readonly ICompletionBroker _completionBroker;
private readonly VisualStudioDocumentTracker _documentTracker;
private readonly JoinableTaskContext _joinableTaskContext;
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
@ -63,7 +64,7 @@ internal class DefaultVisualStudioRazorParser : VisualStudioRazorParser, IDispos
VisualStudioDocumentTracker documentTracker,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
IErrorReporter errorReporter,
VisualStudioCompletionBroker completionBroker)
ICompletionBroker completionBroker)
{
if (joinableTaskContext is null)
{

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.VisualStudio.Editor.Razor;
@ -11,12 +12,12 @@ namespace Microsoft.VisualStudio.Editor.Razor;
internal class DefaultVisualStudioRazorParserFactory(
JoinableTaskContext joinableTaskContext,
IErrorReporter errorReporter,
VisualStudioCompletionBroker completionBroker,
ICompletionBroker completionBroker,
IProjectEngineFactoryProvider projectEngineFactoryProvider) : VisualStudioRazorParserFactory
{
private readonly JoinableTaskContext _joinableTaskContext = joinableTaskContext;
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider = projectEngineFactoryProvider;
private readonly VisualStudioCompletionBroker _completionBroker = completionBroker;
private readonly ICompletionBroker _completionBroker = completionBroker;
private readonly IErrorReporter _errorReporter = errorReporter;
public override VisualStudioRazorParser Create(VisualStudioDocumentTracker documentTracker)

Просмотреть файл

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.VisualStudio.Editor.Razor;
@ -16,16 +17,13 @@ namespace Microsoft.VisualStudio.Editor.Razor;
internal class DefaultVisualStudioRazorParserFactoryFactory(
JoinableTaskContext joinableTaskContext,
IProjectEngineFactoryProvider projectEngineFactoryProvider,
ICompletionBroker completionBroker,
IErrorReporter errorReporter) : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
var completionBroker = languageServices.GetRequiredService<VisualStudioCompletionBroker>();
return new DefaultVisualStudioRazorParserFactory(
=> new DefaultVisualStudioRazorParserFactory(
joinableTaskContext,
errorReporter,
completionBroker,
projectEngineFactoryProvider);
}
}

Просмотреть файл

@ -2,10 +2,12 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.Editor.Razor.Documents;
[Shared]
[ExportWorkspaceService(typeof(FileChangeTrackerFactory), layer: ServiceLayer.Editor)]
internal class DefaultFileChangeTrackerFactory : FileChangeTrackerFactory
{

Просмотреть файл

@ -24,6 +24,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents;
// other triggers with lesser priority so we can attach to Changed sooner. We happen to be so important because we control the
// open/close state of documents. If other triggers depend on a document being open/closed (some do) then we need to ensure we
// can mark open/closed prior to them running.
[Shared]
[Export(typeof(IProjectSnapshotChangeTrigger))]
internal class EditorDocumentManagerListener : IPriorityProjectSnapshotChangeTrigger
{

Просмотреть файл

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.Editor.Razor;
internal abstract class VisualStudioCompletionBroker : ILanguageService
{
public abstract bool IsCompletionActive(ITextView textView);
}

Просмотреть файл

@ -5,6 +5,7 @@ using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.DocumentColor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
using Microsoft.CodeAnalysis.Razor.Logging;
@ -14,6 +15,7 @@ using Microsoft.VisualStudio.LanguageServerClient.Razor.Extensions;
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Cohost;
[Shared]
[RazorLanguageServerEndpoint(Methods.TextDocumentDocumentColorName)]
[ExportRazorStatelessLspService(typeof(CohostDocumentColorEndpoint))]
[Export(typeof(ICapabilitiesProvider))]
@ -32,8 +34,8 @@ internal sealed class CohostDocumentColorEndpoint(
protected override RazorTextDocumentIdentifier? GetRazorTextDocumentIdentifier(DocumentColorParams request)
=> request.TextDocument.ToRazorTextDocumentIdentifier();
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
=> _documentColorService.ApplyCapabilities(serverCapabilities, clientCapabilities);
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities _)
=> serverCapabilities.EnableDocumentColorProvider();
protected override Task<ColorInformation[]> HandleRequestAsync(DocumentColorParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
{

Просмотреть файл

@ -5,6 +5,7 @@ using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
using Microsoft.CodeAnalysis.Razor.Logging;
@ -15,6 +16,7 @@ using Microsoft.VisualStudio.LanguageServerClient.Razor.Extensions;
namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Cohost;
[Shared]
[RazorLanguageServerEndpoint(Methods.TextDocumentSemanticTokensRangeName)]
[ExportRazorStatelessLspService(typeof(CohostSemanticTokensRangeEndpoint))]
[Export(typeof(ICapabilitiesProvider))]
@ -36,7 +38,11 @@ internal sealed class CohostSemanticTokensRangeEndpoint(
=> request.TextDocument.ToRazorTextDocumentIdentifier();
public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, VSInternalClientCapabilities clientCapabilities)
=> _semanticTokensInfoService.ApplyCapabilities(serverCapabilities, clientCapabilities);
{
var legend = new RazorSemanticTokensLegend(clientCapabilities);
serverCapabilities.EnableSemanticTokens(legend.Legend);
_semanticTokensInfoService.SetTokensLegend(legend);
}
protected override Task<SemanticTokens?> HandleRequestAsync(SemanticTokensRangeParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
{

Просмотреть файл

@ -25,6 +25,7 @@ using static Microsoft.VisualStudio.LanguageServer.ContainedLanguage.DefaultLSPD
namespace Microsoft.VisualStudio.LanguageServerClient.Razor;
[Shared]
[Export(typeof(IRazorCustomMessageTarget))]
[Export(typeof(RazorCustomMessageTarget))]
internal partial class RazorCustomMessageTarget : IRazorCustomMessageTarget

Просмотреть файл

@ -1,35 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor;
internal class DefaultVisualStudioCompletionBroker : VisualStudioCompletionBroker
{
private readonly ICompletionBroker _completionBroker;
public DefaultVisualStudioCompletionBroker(ICompletionBroker completionBroker)
{
if (completionBroker is null)
{
throw new ArgumentNullException(nameof(completionBroker));
}
_completionBroker = completionBroker;
}
public override bool IsCompletionActive(ITextView textView)
{
if (textView is null)
{
throw new ArgumentNullException(nameof(textView));
}
var completionIsActive = _completionBroker.IsCompletionActive(textView);
return completionIsActive;
}
}

Просмотреть файл

@ -1,40 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor;
[Shared]
[ExportLanguageServiceFactory(typeof(VisualStudioCompletionBroker), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultVisualStudioCompletionBrokerFactory : ILanguageServiceFactory
{
private readonly ICompletionBroker _completionBroker;
[ImportingConstructor]
public DefaultVisualStudioCompletionBrokerFactory(ICompletionBroker completionBroker)
{
if (completionBroker is null)
{
throw new ArgumentNullException(nameof(completionBroker));
}
_completionBroker = completionBroker;
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices is null)
{
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultVisualStudioCompletionBroker(_completionBroker);
}
}

Просмотреть файл

@ -12,7 +12,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Item = System.Collections.Generic.KeyValuePair<string, System.Collections.Immutable.IImmutableDictionary<string, string>>;
@ -35,33 +34,20 @@ internal class DefaultWindowsRazorProjectHost : WindowsRazorProjectHostBase
Rules.RazorGenerateWithTargetPath.SchemaName,
ConfigurationGeneralSchemaName,
});
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly LanguageServerFeatureOptions? _languageServerFeatureOptions;
[ImportingConstructor]
public DefaultWindowsRazorProjectHost(
IUnconfiguredProjectCommonServices commonServices,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
IProjectSnapshotManagerAccessor projectManagerAccessor,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
LanguageServerFeatureOptions languageServerFeatureOptions)
: base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore)
LanguageServerFeatureOptions? languageServerFeatureOptions)
: base(commonServices, projectManagerAccessor, dispatcher, projectConfigurationFilePathStore)
{
_languageServerFeatureOptions = languageServerFeatureOptions;
}
// Internal for testing
#pragma warning disable CS8618 // Non-nullable variable must contain a non-null value when exiting constructor. Consider declaring it as nullable.
internal DefaultWindowsRazorProjectHost(
#pragma warning restore CS8618 // Non-nullable variable must contain a non-null value when exiting constructor. Consider declaring it as nullable.
IUnconfiguredProjectCommonServices commonServices,
Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
ProjectSnapshotManagerBase projectManager)
: base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager)
{
}
protected override ImmutableHashSet<string> GetRuleNames() => s_ruleNames;
protected override async Task HandleProjectChangeAsync(string sliceDimensions, IProjectVersionedValue<IProjectSubscriptionUpdate> update)

Просмотреть файл

@ -14,7 +14,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.ProjectSystem;
using ContentItem = Microsoft.CodeAnalysis.Razor.ProjectSystem.ManagedProjectSystemSchema.ContentItem;
using ItemReference = Microsoft.CodeAnalysis.Razor.ProjectSystem.ManagedProjectSystemSchema.ItemReference;
@ -37,33 +36,20 @@ internal class FallbackWindowsRazorProjectHost : WindowsRazorProjectHostBase
NoneItem.SchemaName,
ConfigurationGeneralSchemaName,
});
private readonly LanguageServerFeatureOptions _languageServerFeatureOptions;
private readonly LanguageServerFeatureOptions? _languageServerFeatureOptions;
[ImportingConstructor]
public FallbackWindowsRazorProjectHost(
IUnconfiguredProjectCommonServices commonServices,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
IProjectSnapshotManagerAccessor projectManagerAccessor,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
LanguageServerFeatureOptions languageServerFeatureOptions)
: base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore)
LanguageServerFeatureOptions? languageServerFeatureOptions)
: base(commonServices, projectManagerAccessor, dispatcher, projectConfigurationFilePathStore)
{
_languageServerFeatureOptions = languageServerFeatureOptions;
}
// Internal for testing
#pragma warning disable CS8618 // Non-nullable variable must contain a non-null value when exiting constructor. Consider declaring it as nullable.
internal FallbackWindowsRazorProjectHost(
#pragma warning restore CS8618 // Non-nullable variable must contain a non-null value when exiting constructor. Consider declaring it as nullable.
IUnconfiguredProjectCommonServices commonServices,
Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
ProjectSnapshotManagerBase projectManager)
: base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager)
{
}
protected override ImmutableHashSet<string> GetRuleNames() => s_ruleNames;
protected override async Task HandleProjectChangeAsync(string sliceDimensions, IProjectVersionedValue<IProjectSubscriptionUpdate> update)

Просмотреть файл

@ -4,14 +4,13 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Microsoft.AspNetCore.Razor;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Microsoft.VisualStudio.Threading;
@ -22,8 +21,8 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
{
private static readonly DataflowLinkOptions s_dataflowLinkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
private readonly Workspace _workspace;
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly AsyncSemaphore _lock;
private ProjectSnapshotManagerBase? _projectManager;
@ -41,10 +40,10 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
// 250ms between publishes to prevent bursts of changes yet still be responsive to changes.
internal int EnqueueDelay { get; set; } = 250;
public WindowsRazorProjectHostBase(
protected WindowsRazorProjectHostBase(
IUnconfiguredProjectCommonServices commonServices,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
IProjectSnapshotManagerAccessor projectManagerAccessor,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore)
: base(commonServices.ThreadingService.JoinableTaskContext)
{
@ -53,14 +52,9 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
throw new ArgumentNullException(nameof(commonServices));
}
if (workspace is null)
if (dispatcher is null)
{
throw new ArgumentNullException(nameof(workspace));
}
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
throw new ArgumentNullException(nameof(dispatcher));
}
if (projectConfigurationFilePathStore is null)
@ -69,30 +63,13 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
}
CommonServices = commonServices;
_workspace = workspace;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_projectManagerAccessor = projectManagerAccessor;
_dispatcher = dispatcher;
_lock = new AsyncSemaphore(initialCount: 1);
ProjectConfigurationFilePathStore = projectConfigurationFilePathStore;
}
// Internal for testing
protected WindowsRazorProjectHostBase(
IUnconfiguredProjectCommonServices commonServices,
Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
ProjectSnapshotManagerBase projectManager)
: this(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
}
protected abstract ImmutableHashSet<string> GetRuleNames();
protected abstract Task HandleProjectChangeAsync(string sliceDimensions, IProjectVersionedValue<IProjectSubscriptionUpdate> update);
@ -277,17 +254,16 @@ internal abstract class WindowsRazorProjectHostBase : OnceInitializedOnceDispose
}
// Should only be called from the project snapshot manager's specialized thread.
[MemberNotNull(nameof(_projectManager))]
protected ProjectSnapshotManagerBase GetProjectManager()
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
_dispatcher.AssertDispatcherThread();
_projectManager ??= (ProjectSnapshotManagerBase)_workspace.Services.GetLanguageServices(RazorLanguage.Name).GetRequiredService<ProjectSnapshotManager>();
return _projectManager;
return _projectManager ??= _projectManagerAccessor.Instance;
}
protected Task UpdateAsync(Action action, CancellationToken cancellationToken)
=> _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken);
=> _dispatcher.RunOnDispatcherThreadAsync(action, cancellationToken);
protected void UninitializeProjectUnsafe(ProjectKey projectKey)
{

Просмотреть файл

@ -2,11 +2,11 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.VisualStudio.LanguageServices.Razor;
@ -14,27 +14,50 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor;
[Export(typeof(IProjectSnapshotManagerAccessor))]
[method: ImportingConstructor]
internal sealed class VisualStudioProjectSnapshotManagerAccessor(
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
[Import(typeof(VisualStudioWorkspace))] Workspace workspace,
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext)
: IProjectSnapshotManagerAccessor
{
private readonly Workspace _workspace = workspace;
private readonly ProjectSnapshotManagerDispatcher _dispatcher = dispatcher;
private readonly JoinableTaskFactory _jtf = joinableTaskContext.Factory;
private ProjectSnapshotManagerBase? _projectManager;
public ProjectSnapshotManagerBase Instance
{
get
{
EnsureInitialized();
if (_projectManager is { } projectManager)
{
return projectManager;
}
return _projectManager;
if (_dispatcher.IsDispatcherThread)
{
return _projectManager ??= Create();
}
// The JTF.Run isn't great, but it should go away with IProjectSnapshotManagerAccessor.
// ProjectSnapshotManager must be created on the dispatcher scheduler because it calls the
// Initialize() method of any IProjectSnapshotChangeTrigger its created with.
return _jtf.Run(async () =>
{
await _dispatcher.DispatcherScheduler;
return _projectManager ??= Create();
});
ProjectSnapshotManagerBase Create()
{
_dispatcher.AssertDispatcherThread();
return (ProjectSnapshotManagerBase)_workspace.Services
.GetLanguageServices(RazorLanguage.Name)
.GetRequiredService<ProjectSnapshotManager>();
}
}
}
[MemberNotNull(nameof(_projectManager))]
private void EnsureInitialized()
{
_projectManager ??= (ProjectSnapshotManagerBase)_workspace.Services
.GetLanguageServices(RazorLanguage.Name)
.GetRequiredService<ProjectSnapshotManager>();
}
}

Просмотреть файл

@ -5,7 +5,9 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Threading;
using IAsyncDisposable = Microsoft.VisualStudio.Threading.IAsyncDisposable;
@ -16,38 +18,24 @@ internal class ProjectSnapshotSynchronizationService : ICollaborationService, IA
private readonly JoinableTaskFactory _joinableTaskFactory;
private readonly CollaborationSession _sessionContext;
private readonly IProjectSnapshotManagerProxy _hostProjectManagerProxy;
private readonly ProjectSnapshotManagerBase _projectSnapshotManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly IErrorReporter _errorReporter;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
public ProjectSnapshotSynchronizationService(
JoinableTaskFactory joinableTaskFactory,
CollaborationSession sessionContext,
IProjectSnapshotManagerProxy hostProjectManagerProxy,
ProjectSnapshotManagerBase projectSnapshotManager)
IProjectSnapshotManagerAccessor projectManagerAccessor,
IErrorReporter errorReporter,
ProjectSnapshotManagerDispatcher dispatcher)
{
if (joinableTaskFactory is null)
{
throw new ArgumentNullException(nameof(joinableTaskFactory));
}
if (sessionContext is null)
{
throw new ArgumentNullException(nameof(sessionContext));
}
if (hostProjectManagerProxy is null)
{
throw new ArgumentNullException(nameof(hostProjectManagerProxy));
}
if (projectSnapshotManager is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManager));
}
_joinableTaskFactory = joinableTaskFactory;
_sessionContext = sessionContext;
_hostProjectManagerProxy = hostProjectManagerProxy;
_projectSnapshotManager = projectSnapshotManager;
_projectManagerAccessor = projectManagerAccessor;
_errorReporter = errorReporter;
_dispatcher = dispatcher;
}
public async Task InitializeAsync(CancellationToken cancellationToken)
@ -58,51 +46,62 @@ internal class ProjectSnapshotSynchronizationService : ICollaborationService, IA
var projectManagerState = await _hostProjectManagerProxy.GetProjectManagerStateAsync(cancellationToken);
await InitializeGuestProjectManagerAsync(projectManagerState.ProjectHandles, cancellationToken);
await InitializeGuestProjectManagerAsync(projectManagerState.ProjectHandles);
}
public async Task DisposeAsync()
{
_hostProjectManagerProxy.Changed -= HostProxyProjectManager_Changed;
await _joinableTaskFactory.SwitchToMainThreadAsync();
await _dispatcher.DispatcherScheduler;
var projects = _projectSnapshotManager.GetProjects();
var projectManager = _projectManagerAccessor.Instance;
var projects = projectManager.GetProjects();
foreach (var project in projects)
{
try
{
_projectSnapshotManager.ProjectRemoved(project.Key);
projectManager.ProjectRemoved(project.Key);
}
catch (Exception ex)
{
_projectSnapshotManager.ReportError(ex, project);
projectManager.ReportError(ex, project);
}
}
}
// Internal for testing
internal void UpdateGuestProjectManager(ProjectChangeEventProxyArgs args)
ValueTask System.IAsyncDisposable.DisposeAsync()
{
return new ValueTask(DisposeAsync());
}
// Internal for testing
internal async ValueTask UpdateGuestProjectManagerAsync(ProjectChangeEventProxyArgs args)
{
await _dispatcher.DispatcherScheduler;
var projectManager = _projectManagerAccessor.Instance;
if (args.Kind == ProjectProxyChangeKind.ProjectAdded)
{
var guestPath = ResolveGuestPath(args.ProjectFilePath);
var guestIntermediateOutputPath = ResolveGuestPath(args.IntermediateOutputPath);
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, args.Newer!.Configuration, args.Newer.RootNamespace);
_projectSnapshotManager.ProjectAdded(hostProject);
projectManager.ProjectAdded(hostProject);
if (args.Newer.ProjectWorkspaceState != null)
{
_projectSnapshotManager.ProjectWorkspaceStateChanged(hostProject.Key, args.Newer.ProjectWorkspaceState);
projectManager.ProjectWorkspaceStateChanged(hostProject.Key, args.Newer.ProjectWorkspaceState);
}
}
else if (args.Kind == ProjectProxyChangeKind.ProjectRemoved)
{
var guestPath = ResolveGuestPath(args.ProjectFilePath);
var projectKeys = _projectSnapshotManager.GetAllProjectKeys(guestPath);
var projectKeys = projectManager.GetAllProjectKeys(guestPath);
foreach (var projectKey in projectKeys)
{
_projectSnapshotManager.ProjectRemoved(projectKey);
projectManager.ProjectRemoved(projectKey);
}
}
else if (args.Kind == ProjectProxyChangeKind.ProjectChanged)
@ -112,37 +111,37 @@ internal class ProjectSnapshotSynchronizationService : ICollaborationService, IA
var guestPath = ResolveGuestPath(args.Newer.FilePath);
var guestIntermediateOutputPath = ResolveGuestPath(args.Newer.IntermediateOutputPath);
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, args.Newer.Configuration, args.Newer.RootNamespace);
_projectSnapshotManager.ProjectConfigurationChanged(hostProject);
projectManager.ProjectConfigurationChanged(hostProject);
}
else if (args.Older.ProjectWorkspaceState != args.Newer.ProjectWorkspaceState ||
args.Older.ProjectWorkspaceState?.Equals(args.Newer.ProjectWorkspaceState) == false)
{
var guestPath = ResolveGuestPath(args.Newer.FilePath);
var projectKeys = _projectSnapshotManager.GetAllProjectKeys(guestPath);
var projectKeys = projectManager.GetAllProjectKeys(guestPath);
foreach (var projectKey in projectKeys)
{
_projectSnapshotManager.ProjectWorkspaceStateChanged(projectKey, args.Newer.ProjectWorkspaceState);
projectManager.ProjectWorkspaceStateChanged(projectKey, args.Newer.ProjectWorkspaceState);
}
}
}
}
private async Task InitializeGuestProjectManagerAsync(
IReadOnlyList<ProjectSnapshotHandleProxy> projectHandles,
CancellationToken cancellationToken)
private async Task InitializeGuestProjectManagerAsync(IReadOnlyList<ProjectSnapshotHandleProxy> projectHandles)
{
await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
await _dispatcher.DispatcherScheduler;
var projectManager = _projectManagerAccessor.Instance;
foreach (var projectHandle in projectHandles)
{
var guestPath = ResolveGuestPath(projectHandle.FilePath);
var guestIntermediateOutputPath = ResolveGuestPath(projectHandle.IntermediateOutputPath);
var hostProject = new HostProject(guestPath, guestIntermediateOutputPath, projectHandle.Configuration, projectHandle.RootNamespace);
_projectSnapshotManager.ProjectAdded(hostProject);
projectManager.ProjectAdded(hostProject);
if (projectHandle.ProjectWorkspaceState is not null)
{
_projectSnapshotManager.ProjectWorkspaceStateChanged(hostProject.Key, projectHandle.ProjectWorkspaceState);
projectManager.ProjectWorkspaceStateChanged(hostProject.Key, projectHandle.ProjectWorkspaceState);
}
}
}
@ -158,13 +157,11 @@ internal class ProjectSnapshotSynchronizationService : ICollaborationService, IA
{
try
{
await _joinableTaskFactory.SwitchToMainThreadAsync();
UpdateGuestProjectManager(args);
await UpdateGuestProjectManagerAsync(args);
}
catch (Exception ex)
{
_projectSnapshotManager.ReportError(ex);
_errorReporter.ReportError(ex);
}
});
}
@ -173,9 +170,4 @@ internal class ProjectSnapshotSynchronizationService : ICollaborationService, IA
{
return _sessionContext.ConvertSharedUriToLocalPath(filePath);
}
ValueTask System.IAsyncDisposable.DisposeAsync()
{
return new ValueTask(DisposeAsync());
}
}

Просмотреть файл

@ -1,14 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LiveShare.Razor.Serialization;
using Microsoft.VisualStudio.Threading;
using Newtonsoft.Json;
@ -16,38 +13,13 @@ using Newtonsoft.Json;
namespace Microsoft.VisualStudio.LiveShare.Razor.Guest;
[ExportCollaborationService(typeof(ProjectSnapshotSynchronizationService), Scope = SessionScope.Guest)]
internal class ProjectSnapshotSynchronizationServiceFactory : ICollaborationServiceFactory
[method: ImportingConstructor]
internal class ProjectSnapshotSynchronizationServiceFactory(
JoinableTaskContext joinableTaskContext,
IProjectSnapshotManagerAccessor projectManagerAccessor,
IErrorReporter errorReporter,
ProjectSnapshotManagerDispatcher dispatcher) : ICollaborationServiceFactory
{
private readonly ProxyAccessor _proxyAccessor;
private readonly JoinableTaskContext _joinableTaskContext;
private readonly Workspace _workspace;
[ImportingConstructor]
public ProjectSnapshotSynchronizationServiceFactory(
ProxyAccessor proxyAccessor,
JoinableTaskContext joinableTaskContext,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
{
if (proxyAccessor is null)
{
throw new ArgumentNullException(nameof(proxyAccessor));
}
if (joinableTaskContext is null)
{
throw new ArgumentNullException(nameof(joinableTaskContext));
}
if (workspace is null)
{
throw new ArgumentNullException(nameof(workspace));
}
_proxyAccessor = proxyAccessor;
_joinableTaskContext = joinableTaskContext;
_workspace = workspace;
}
public async Task<ICollaborationService> CreateServiceAsync(CollaborationSession sessionContext, CancellationToken cancellationToken)
{
// This collaboration service depends on these serializers being immediately available so we need to register these now so the
@ -55,15 +27,14 @@ internal class ProjectSnapshotSynchronizationServiceFactory : ICollaborationServ
var serializer = (JsonSerializer)sessionContext.GetService(typeof(JsonSerializer));
serializer.Converters.RegisterRazorLiveShareConverters();
var languageServices = _workspace.Services.GetLanguageServices(RazorLanguage.Name);
var projectManager = (ProjectSnapshotManagerBase)languageServices.GetRequiredService<ProjectSnapshotManager>();
var projectSnapshotManagerProxy = await sessionContext.GetRemoteServiceAsync<IProjectSnapshotManagerProxy>(typeof(IProjectSnapshotManagerProxy).Name, cancellationToken);
var synchronizationService = new ProjectSnapshotSynchronizationService(
_joinableTaskContext.Factory,
joinableTaskContext.Factory,
sessionContext,
projectSnapshotManagerProxy,
projectManager);
projectManagerAccessor,
errorReporter,
dispatcher);
await synchronizationService.InitializeAsync(cancellationToken);

Просмотреть файл

@ -16,7 +16,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host;
internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, ICollaborationService, IDisposable
{
private readonly CollaborationSession _session;
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly ProjectSnapshotManagerDispatcher _dispatcher;
private readonly ProjectSnapshotManager _projectSnapshotManager;
private readonly JoinableTaskFactory _joinableTaskFactory;
private readonly AsyncSemaphore _latestStateSemaphore;
@ -28,7 +28,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
public DefaultProjectSnapshotManagerProxy(
CollaborationSession session,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectSnapshotManager projectSnapshotManager,
JoinableTaskFactory joinableTaskFactory)
{
@ -37,9 +37,9 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
throw new ArgumentNullException(nameof(session));
}
if (projectSnapshotManagerDispatcher is null)
if (dispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
throw new ArgumentNullException(nameof(dispatcher));
}
if (projectSnapshotManager is null)
@ -53,7 +53,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
}
_session = session;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_dispatcher = dispatcher;
_projectSnapshotManager = projectSnapshotManager;
_joinableTaskFactory = joinableTaskFactory;
@ -81,7 +81,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
public void Dispose()
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
_dispatcher.AssertDispatcherThread();
_projectSnapshotManager.Changed -= ProjectSnapshotManager_Changed;
_latestStateSemaphore.Dispose();
@ -133,7 +133,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args)
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
_dispatcher.AssertDispatcherThread();
if (_disposed)
{
@ -164,7 +164,7 @@ internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy
private void OnChanged(ProjectChangeEventProxyArgs args)
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
_dispatcher.AssertDispatcherThread();
if (_disposed)
{

Просмотреть файл

@ -5,10 +5,8 @@ using System;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LiveShare.Razor.Serialization;
using Microsoft.VisualStudio.Threading;
using Newtonsoft.Json;
@ -20,38 +18,12 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host;
Name = nameof(IProjectSnapshotManagerProxy),
Scope = SessionScope.Host,
Role = ServiceRole.RemoteService)]
internal class DefaultProjectSnapshotManagerProxyFactory : ICollaborationServiceFactory
[method: ImportingConstructor]
internal class DefaultProjectSnapshotManagerProxyFactory(
ProjectSnapshotManagerDispatcher dispatcher,
JoinableTaskContext joinableTaskContext,
IProjectSnapshotManagerAccessor projectManagerAccessor) : ICollaborationServiceFactory
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly JoinableTaskContext _joinableTaskContext;
private readonly Workspace _workspace;
[ImportingConstructor]
public DefaultProjectSnapshotManagerProxyFactory(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
JoinableTaskContext joinableTaskContext,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (joinableTaskContext is null)
{
throw new ArgumentNullException(nameof(joinableTaskContext));
}
if (workspace is null)
{
throw new ArgumentNullException(nameof(workspace));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_joinableTaskContext = joinableTaskContext;
_workspace = workspace;
}
public Task<ICollaborationService> CreateServiceAsync(CollaborationSession session, CancellationToken cancellationToken)
{
if (session is null)
@ -62,10 +34,8 @@ internal class DefaultProjectSnapshotManagerProxyFactory : ICollaborationService
var serializer = (JsonSerializer)session.GetService(typeof(JsonSerializer));
serializer.Converters.RegisterRazorLiveShareConverters();
var razorLanguageServices = _workspace.Services.GetLanguageServices(RazorLanguage.Name);
var projectSnapshotManager = razorLanguageServices.GetRequiredService<ProjectSnapshotManager>();
var service = new DefaultProjectSnapshotManagerProxy(session, _projectSnapshotManagerDispatcher, projectSnapshotManager, _joinableTaskContext.Factory);
var service = new DefaultProjectSnapshotManagerProxy(
session, dispatcher, projectManagerAccessor.Instance, joinableTaskContext.Factory);
return Task.FromResult<ICollaborationService>(service);
}
}

Просмотреть файл

@ -280,9 +280,6 @@ public class FormattingTestBase : RazorToolingIntegrationTestBase
documentSnapshot
.Setup(d => d.GetGeneratedOutputAsync())
.ReturnsAsync(codeDocument);
documentSnapshot
.Setup(d => d.GetImports())
.Returns(imports);
documentSnapshot
.Setup(d => d.FilePath)
.Returns(path);

Просмотреть файл

@ -4,7 +4,6 @@
#nullable disable
using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;

Просмотреть файл

@ -1011,7 +1011,9 @@ public partial class SemanticTokensTest(ITestOutputHelper testOutput) : TagHelpe
featureOptions,
LoggerFactory,
telemetryReporter: null);
service.ApplyCapabilities(new(), new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true });
var legend = new RazorSemanticTokensLegend(new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true });
service.SetTokensLegend(legend);
return service;
}

Просмотреть файл

@ -88,11 +88,6 @@ internal class TestDocumentSnapshot : DocumentSnapshot
return Task.FromResult(_codeDocument);
}
public override ImmutableArray<IDocumentSnapshot> GetImports()
{
return ImmutableArray<IDocumentSnapshot>.Empty;
}
public override bool TryGetGeneratedOutput(out RazorCodeDocument result)
{
if (_codeDocument is null)

Просмотреть файл

@ -11,15 +11,15 @@ using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.Test.Common;
internal class TestTagHelperResolver : ITagHelperResolver
internal class TestTagHelperResolver(ImmutableArray<TagHelperDescriptor> tagHelpers) : ITagHelperResolver
{
public ImmutableArray<TagHelperDescriptor> TagHelpers { get; set; } = ImmutableArray<TagHelperDescriptor>.Empty;
public ImmutableArray<TagHelperDescriptor> TagHelpers { get; } = tagHelpers;
public ValueTask<ImmutableArray<TagHelperDescriptor>> GetTagHelpersAsync(
Project workspaceProject,
IProjectSnapshot projectSnapshot,
CancellationToken cancellationToken)
{
return new(TagHelpers.ToImmutableArray());
return new(TagHelpers);
}
}

Просмотреть файл

@ -1,15 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.CodeAnalysis.Text;
using Xunit;
@ -60,11 +56,6 @@ public class DefaultDocumentSnapshotTest : WorkspaceTestBase
_nestedComponentDocument = new DocumentSnapshot(project, documentState);
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
services.Add(new TestTagHelperResolver());
}
[Fact]
public async Task GCCollect_OutputIsNoLongerCached()
{

Просмотреть файл

@ -1,16 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Xunit;
using Xunit.Abstractions;
@ -21,13 +17,10 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
private readonly HostDocument[] _documents;
private readonly HostProject _hostProject;
private readonly ProjectWorkspaceState _projectWorkspaceState;
private readonly TestTagHelperResolver _tagHelperResolver;
public DefaultProjectSnapshotTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_tagHelperResolver = new TestTagHelperResolver();
_hostProject = new HostProject(TestProjectData.SomeProject.FilePath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.SomeProject.RootNamespace);
_projectWorkspaceState = ProjectWorkspaceState.Create(ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()));
@ -42,11 +35,6 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
];
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
services.Add(_tagHelperResolver);
}
protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
{
builder.SetImportFeature(new TestImportProjectFeature());
@ -82,6 +70,7 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
var snapshot = new ProjectSnapshot(state);
var document = snapshot.GetDocument(_documents[0].FilePath);
Assert.NotNull(document);
// Act
var result = snapshot.IsImportDocument(document);
@ -100,6 +89,7 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
var snapshot = new ProjectSnapshot(state);
var document = snapshot.GetDocument(TestProjectData.SomeProjectImportFile.FilePath);
Assert.NotNull(document);
// Act
var result = snapshot.IsImportDocument(document);
@ -117,6 +107,7 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
var snapshot = new ProjectSnapshot(state);
var document = snapshot.GetDocument(_documents[0].FilePath);
Assert.NotNull(document);
// Act
var documents = snapshot.GetRelatedDocuments(document);
@ -136,6 +127,7 @@ public class DefaultProjectSnapshotTest : WorkspaceTestBase
var snapshot = new ProjectSnapshot(state);
var document = snapshot.GetDocument(TestProjectData.SomeProjectImportFile.FilePath);
Assert.NotNull(document);
// Act
var documents = snapshot.GetRelatedDocuments(document);

Просмотреть файл

@ -1,9 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
@ -11,7 +8,6 @@ using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Xunit;
using Xunit.Abstractions;
@ -23,7 +19,6 @@ public class ProjectStateGeneratedOutputTest : WorkspaceTestBase
private readonly HostDocument _hostDocument;
private readonly HostProject _hostProject;
private readonly HostProject _hostProjectWithConfigurationChange;
private readonly TestTagHelperResolver _tagHelperResolver;
private readonly ImmutableArray<TagHelperDescriptor> _someTagHelpers;
private readonly SourceText _text;
@ -33,8 +28,6 @@ public class ProjectStateGeneratedOutputTest : WorkspaceTestBase
_hostProject = new HostProject(TestProjectData.SomeProject.FilePath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.SomeProject.RootNamespace);
_hostProjectWithConfigurationChange = new HostProject(TestProjectData.SomeProject.FilePath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_1_0, TestProjectData.SomeProject.RootNamespace);
_tagHelperResolver = new TestTagHelperResolver();
_someTagHelpers = ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());
@ -43,11 +36,6 @@ public class ProjectStateGeneratedOutputTest : WorkspaceTestBase
_text = SourceText.From("Hello, world!");
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
services.Add(_tagHelperResolver);
}
protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
{
builder.SetImportFeature(new TestImportProjectFeature());

Просмотреть файл

@ -2,9 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
@ -12,7 +10,6 @@ using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Xunit;
using Xunit.Abstractions;
@ -25,13 +22,9 @@ public class ProjectStateTest : WorkspaceTestBase
private readonly HostProject _hostProject;
private readonly HostProject _hostProjectWithConfigurationChange;
private readonly ProjectWorkspaceState _projectWorkspaceState;
private readonly ImmutableArray<TagHelperDescriptor> _someTagHelpers;
private readonly Func<Task<TextAndVersion>> _textLoader;
private readonly SourceText _text;
[AllowNull]
private TestTagHelperResolver _tagHelperResolver;
public ProjectStateTest(ITestOutputHelper testOutput)
: base(testOutput)
{
@ -41,9 +34,6 @@ public class ProjectStateTest : WorkspaceTestBase
ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()));
_someTagHelpers = ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());
_documents = new HostDocument[]
{
TestProjectData.SomeProjectFile1,
@ -57,12 +47,6 @@ public class ProjectStateTest : WorkspaceTestBase
_textLoader = () => Task.FromResult(TextAndVersion.Create(_text, VersionStamp.Create()));
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
_tagHelperResolver = new TestTagHelperResolver();
services.Add(_tagHelperResolver);
}
protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
{
builder.SetImportFeature(new TestImportProjectFeature());
@ -556,8 +540,6 @@ public class ProjectStateTest : WorkspaceTestBase
var originalTagHelpers = original.TagHelpers;
var originalProjectWorkspaceStateVersion = original.ConfigurationVersion;
_tagHelperResolver.TagHelpers = _someTagHelpers;
// Act
var state = original.WithHostProject(_hostProjectWithConfigurationChange);
@ -601,8 +583,6 @@ public class ProjectStateTest : WorkspaceTestBase
_ = original.TagHelpers;
_ = original.ConfigurationVersion;
_tagHelperResolver.TagHelpers = _someTagHelpers;
// Act
var state = original.WithHostProject(hostProjectWithRootNamespaceChange);
@ -719,9 +699,6 @@ public class ProjectStateTest : WorkspaceTestBase
var changed = ProjectWorkspaceState.Default;
// Now create some tag helpers
_tagHelperResolver.TagHelpers = _someTagHelpers;
// Act
var state = original.WithProjectWorkspaceState(changed);
@ -756,9 +733,6 @@ public class ProjectStateTest : WorkspaceTestBase
var changed = ProjectWorkspaceState.Create(original.TagHelpers, original.CSharpLanguageVersion);
// Now create some tag helpers
_tagHelperResolver.TagHelpers = _someTagHelpers;
// Act
var state = original.WithProjectWorkspaceState(changed);

Просмотреть файл

@ -1,15 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Xunit;
using Xunit.Abstractions;
@ -18,11 +13,6 @@ namespace Microsoft.CodeAnalysis.Razor;
public class RazorDocumentExcerptServiceTest(ITestOutputHelper testOutput) : DocumentExcerptServiceTestBase(testOutput)
{
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
services.Add(new TestTagHelperResolver());
}
[Fact]
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp()
{

Просмотреть файл

@ -1,16 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Xunit;
@ -23,11 +19,6 @@ public class RazorSpanMappingServiceTest(ITestOutputHelper testOutput) : Workspa
private readonly HostProject _hostProject = TestProjectData.SomeProject;
private readonly HostDocument _hostDocument = TestProjectData.SomeProjectFile1;
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
services.Add(new TestTagHelperResolver());
}
[Fact]
public async Task TryGetMappedSpans_SpanMatchesSourceMapping_ReturnsTrue()
{
@ -41,6 +32,7 @@ public class RazorSpanMappingServiceTest(ITestOutputHelper testOutput) : Workspa
.WithAddedHostDocument(_hostDocument, () => Task.FromResult(TextAndVersion.Create(sourceText, VersionStamp.Create()))));
var document = project.GetDocument(_hostDocument.FilePath);
Assert.NotNull(document);
var service = new RazorSpanMappingService(document);
var output = await document.GetGeneratedOutputAsync();
@ -73,6 +65,7 @@ public class RazorSpanMappingServiceTest(ITestOutputHelper testOutput) : Workspa
.WithAddedHostDocument(_hostDocument, () => Task.FromResult(TextAndVersion.Create(sourceText, VersionStamp.Create()))));
var document = project.GetDocument(_hostDocument.FilePath);
Assert.NotNull(document);
var service = new RazorSpanMappingService(document);
var output = await document.GetGeneratedOutputAsync();
@ -106,6 +99,7 @@ public class RazorSpanMappingServiceTest(ITestOutputHelper testOutput) : Workspa
.WithAddedHostDocument(_hostDocument, () => Task.FromResult(TextAndVersion.Create(sourceText, VersionStamp.Create()))));
var document = project.GetDocument(_hostDocument.FilePath);
Assert.NotNull(document);
var service = new RazorSpanMappingService(document);
var output = await document.GetGeneratedOutputAsync();
@ -138,6 +132,7 @@ public class RazorSpanMappingServiceTest(ITestOutputHelper testOutput) : Workspa
.WithAddedHostDocument(_hostDocument, () => Task.FromResult(TextAndVersion.Create(sourceText, VersionStamp.Create()))));
var document = project.GetDocument(_hostDocument.FilePath);
Assert.NotNull(document);
var service = new RazorSpanMappingService(document);
var output = await document.GetGeneratedOutputAsync();

Просмотреть файл

@ -12,7 +12,7 @@ using Moq;
namespace Microsoft.CodeAnalysis.Remote.Razor;
public partial class OOPTagHelperResolverTest
public partial class OutOfProcTagHelperResolverTest
{
private static readonly Lazy<ProjectSnapshotManagerDispatcher> s_projectSnapshotManagerDispatcher = new(() =>
{

Просмотреть файл

@ -11,19 +11,19 @@ using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Xunit;
using Microsoft.CodeAnalysis.Razor.Workspaces;
#pragma warning disable VSTHRD110 // Observe result of async calls
namespace Microsoft.CodeAnalysis.Remote.Razor;
public partial class OOPTagHelperResolverTest
public partial class OutOfProcTagHelperResolverTest
{
private class TestResolver(
Workspace workspace,
IProjectSnapshotManagerAccessor projectManagerAccessor,
IErrorReporter errorReporter,
ITelemetryReporter telemetryReporter)
: OOPTagHelperResolver(workspace, errorReporter, telemetryReporter)
: OutOfProcTagHelperResolver(projectManagerAccessor, errorReporter, telemetryReporter)
{
public Func<IProjectSnapshot, ValueTask<ImmutableArray<TagHelperDescriptor>>>? OnResolveOutOfProcess { get; init; }

Просмотреть файл

@ -11,9 +11,9 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Serialization;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.AspNetCore.Razor.Utilities;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.CodeAnalysis.Remote.Razor.Test;
using Moq;
using Xunit;
@ -21,41 +21,47 @@ using Xunit.Abstractions;
namespace Microsoft.CodeAnalysis.Remote.Razor;
public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public partial class OutOfProcTagHelperResolverTest : TagHelperDescriptorTestBase
{
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly ImmutableArray<IProjectEngineFactory> _customFactories;
private readonly HostProject _hostProject_For_2_0;
private readonly HostProject _hostProject_For_NonSerializableConfiguration;
private readonly ProjectSnapshotManagerBase _projectManager;
private readonly Project _workspaceProject;
private readonly Workspace _workspace;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
public OOPTagHelperResolverTest(ITestOutputHelper testOutput)
public OutOfProcTagHelperResolverTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_hostProject_For_2_0 = new HostProject("Test.csproj", "/obj", FallbackRazorConfiguration.MVC_2_0, rootNamespace: null);
_hostProject_For_2_0 = new HostProject(
projectFilePath: "Test.csproj",
intermediateOutputPath: "/obj",
razorConfiguration: FallbackRazorConfiguration.MVC_2_0,
rootNamespace: null);
_hostProject_For_NonSerializableConfiguration = new HostProject(
"Test.csproj", "/obj",
new ProjectSystemRazorConfiguration(RazorLanguageVersion.Version_2_1, "Random-0.1", []), rootNamespace: null);
projectFilePath: "Test.csproj",
intermediateOutputPath: "/obj",
razorConfiguration: new ProjectSystemRazorConfiguration(RazorLanguageVersion.Version_2_1, "Random-0.1", []),
rootNamespace: null);
_customFactories = ImmutableArray.Create(
var workspace = new AdhocWorkspace();
AddDisposable(workspace);
var info = ProjectInfo.Create(ProjectId.CreateNewId("Test"), VersionStamp.Default, "Test", "Test", LanguageNames.CSharp, filePath: "Test.csproj");
_workspaceProject = workspace.CurrentSolution.AddProject(info).GetProject(info.Id).AssumeNotNull();
var customFactories = ImmutableArray.Create(
CreateFactory("MVC-2.0"),
// We don't really use this factory, we just use it to ensure that the call is going to go out of process.
CreateFactory("Test-2"));
_projectEngineFactoryProvider = new ProjectEngineFactoryProvider(_customFactories);
var projectEngineFactoryProvider = new ProjectEngineFactoryProvider(customFactories);
var projectManager = new TestProjectSnapshotManager(workspace, projectEngineFactoryProvider);
var testServices = TestServices.Create([], []);
_workspace = new AdhocWorkspace(testServices);
AddDisposable(_workspace);
var info = ProjectInfo.Create(ProjectId.CreateNewId("Test"), VersionStamp.Default, "Test", "Test", LanguageNames.CSharp, filePath: "Test.csproj");
_workspaceProject = _workspace.CurrentSolution.AddProject(info).GetProject(info.Id).AssumeNotNull();
_projectManager = new TestProjectSnapshotManager(_workspace, _projectEngineFactoryProvider);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(projectManager);
_projectManagerAccessor = projectManagerAccessorMock.Object;
static IProjectEngineFactory CreateFactory(string configurationName)
{
@ -72,13 +78,13 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public async Task GetTagHelpersAsync_WithSerializableCustomFactory_GoesOutOfProcess()
{
// Arrange
_projectManager.ProjectAdded(_hostProject_For_2_0);
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_2_0);
var projectSnapshot = _projectManager.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var calledOutOfProcess = false;
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveOutOfProcess = (p) =>
{
@ -101,13 +107,13 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public async Task GetTagHelpersAsync_WithNonSerializableCustomFactory_StaysInProcess()
{
// Arrange
_projectManager.ProjectAdded(_hostProject_For_NonSerializableConfiguration);
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_NonSerializableConfiguration);
var projectSnapshot = _projectManager.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var calledInProcess = false;
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveInProcess = (p) =>
{
@ -130,15 +136,15 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public async Task GetTagHelpersAsync_OperationCanceledException_DoesNotGetWrapped()
{
// Arrange
_projectManager.ProjectAdded(_hostProject_For_2_0);
_projectManagerAccessor.Instance.ProjectAdded(_hostProject_For_2_0);
var projectSnapshot = _projectManager.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var projectSnapshot = _projectManagerAccessor.Instance.GetLoadedProject(_hostProject_For_2_0.Key).AssumeNotNull();
var calledOutOfProcess = false;
var calledInProcess = false;
var cancellationToken = new CancellationToken(canceled: true);
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance)
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance)
{
OnResolveInProcess = (p) =>
{
@ -166,7 +172,7 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public void CalculateTagHelpersFromDelta_NewProject()
{
// Arrange
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
// Act
@ -180,7 +186,7 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public void CalculateTagHelpersFromDelta_DeltaFailedToApplyToKnownProject()
{
// Arrange
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var newTagHelperSet = ImmutableArray.Create(TagHelper1_Project1.Checksum);
@ -197,7 +203,7 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public void CalculateTagHelpersFromDelta_NoopResult()
{
// Arrange
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var noopDelta = new TagHelperDeltaResult(IsDelta: true, initialDelta.ResultId, ImmutableArray<Checksum>.Empty, ImmutableArray<Checksum>.Empty);
@ -213,7 +219,7 @@ public partial class OOPTagHelperResolverTest : TagHelperDescriptorTestBase
public void CalculateTagHelpersFromDelta_ReplacedTagHelpers()
{
// Arrange
var resolver = new TestResolver(_workspace, ErrorReporter, NoOpTelemetryReporter.Instance);
var resolver = new TestResolver(_projectManagerAccessor, ErrorReporter, NoOpTelemetryReporter.Instance);
var initialDelta = new TagHelperDeltaResult(IsDelta: false, ResultId: 1, Project1TagHelperChecksums, ImmutableArray<Checksum>.Empty);
resolver.PublicProduceChecksumsFromDelta(Project1Id, lastResultId: -1, initialDelta);
var changedDelta = new TagHelperDeltaResult(IsDelta: true, initialDelta.ResultId + 1, ImmutableArray.Create(TagHelper2_Project2.Checksum), ImmutableArray.Create(TagHelper2_Project1.Checksum));

Просмотреть файл

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
@ -28,7 +29,7 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
private readonly IContentType _razorCoreContentType;
private readonly IContentType _nonRazorCoreContentType;
private readonly ProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly WorkspaceEditorSettings _workspaceEditorSettings;
private readonly ImportDocumentManager _importDocumentManager;
@ -43,12 +44,19 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
c => c.IsOfType(It.IsAny<string>()) == false,
MockBehavior.Strict);
_projectManager = Mock.Of<ProjectSnapshotManager>(
var projectManager = Mock.Of<ProjectSnapshotManagerBase>(
p => p.GetProjects() == ImmutableArray<IProjectSnapshot>.Empty &&
p.GetLoadedProject(It.IsAny<ProjectKey>()) == null &&
p.GetAllProjectKeys(It.IsAny<string>()) == System.Collections.Immutable.ImmutableArray<ProjectKey>.Empty,
p.GetLoadedProject(It.IsAny<ProjectKey>()) == null &&
p.GetAllProjectKeys(It.IsAny<string>()) == ImmutableArray<ProjectKey>.Empty,
MockBehavior.Strict);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(projectManager);
_projectManagerAccessor = projectManagerAccessorMock.Object;
_workspaceEditorSettings = new DefaultWorkspaceEditorSettings(
Mock.Of<IClientSettingsManager>(MockBehavior.Strict));
@ -85,7 +93,7 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
Mock.Of<ITextBuffer>(b => b.ContentType == _razorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManagerAccessor, _workspaceEditorSettings,
ProjectEngineFactories.DefaultProvider, buffers[0], _importDocumentManager) as VisualStudioDocumentTracker;
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(
factoryService => factoryService.TryGetDocumentTracker(
@ -110,7 +118,7 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
Mock.Of<ITextBuffer>(b => b.ContentType == _nonRazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings, ProjectEngineFactories.DefaultProvider, buffers[0], _importDocumentManager) as VisualStudioDocumentTracker;
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManagerAccessor, _workspaceEditorSettings, ProjectEngineFactories.DefaultProvider, buffers[0], _importDocumentManager) as VisualStudioDocumentTracker;
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(f => f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true, MockBehavior.Strict);
var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService);
@ -156,14 +164,14 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
var documentTracker = new DefaultVisualStudioDocumentTracker(
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManagerAccessor, _workspaceEditorSettings,
ProjectEngineFactories.DefaultProvider, buffers[0], _importDocumentManager);
documentTracker.AddTextView(textView1);
documentTracker.AddTextView(textView2);
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
documentTracker = new DefaultVisualStudioDocumentTracker(
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManagerAccessor, _workspaceEditorSettings,
ProjectEngineFactories.DefaultProvider, buffers[1], _importDocumentManager);
documentTracker.AddTextView(textView1);
documentTracker.AddTextView(textView2);
@ -195,7 +203,7 @@ public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherT
Mock.Of<ITextBuffer>(b => b.ContentType == _nonRazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManager, _workspaceEditorSettings,
Dispatcher, JoinableTaskContext, FilePath, ProjectPath, _projectManagerAccessor, _workspaceEditorSettings,
ProjectEngineFactories.DefaultProvider, buffers[0], _importDocumentManager);
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(MockBehavior.Strict);

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
@ -10,10 +8,10 @@ using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Editor.Razor.Documents;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
@ -30,15 +28,13 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
private readonly ITextBuffer _textBuffer;
private readonly string _filePath;
private readonly string _projectPath;
private readonly string _rootNamespace;
private readonly string? _rootNamespace;
private readonly HostProject _hostProject;
private readonly HostProject _updatedHostProject;
private readonly HostProject _otherHostProject;
private Project _workspaceProject;
private Project? _workspaceProject;
private readonly ImportDocumentManager _importDocumentManager;
private readonly WorkspaceEditorSettings _workspaceEditorSettings;
private readonly List<TagHelperDescriptor> _someTagHelpers;
private TestTagHelperResolver _tagHelperResolver;
private readonly ProjectSnapshotManagerBase _projectManager;
private readonly DefaultVisualStudioDocumentTracker _documentTracker;
@ -58,13 +54,13 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
_workspaceEditorSettings = new DefaultWorkspaceEditorSettings(Mock.Of<IClientSettingsManager>(MockBehavior.Strict));
_someTagHelpers = new List<TagHelperDescriptor>()
{
TagHelperDescriptorBuilder.Create("test", "test").Build(),
};
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher) { AllowNotifyListeners = true };
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(_projectManager);
_hostProject = new HostProject(_projectPath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_1, _rootNamespace);
_updatedHostProject = new HostProject(_projectPath, TestProjectData.SomeProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_0, _rootNamespace);
_otherHostProject = new HostProject(TestProjectData.AnotherProject.FilePath, TestProjectData.AnotherProject.IntermediateOutputPath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.AnotherProject.RootNamespace);
@ -74,19 +70,13 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
JoinableTaskFactory.Context,
_filePath,
_projectPath,
_projectManager,
projectManagerAccessorMock.Object,
_workspaceEditorSettings,
ProjectEngineFactoryProvider,
_textBuffer,
_importDocumentManager);
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
_tagHelperResolver = new TestTagHelperResolver();
services.Add(_tagHelperResolver);
}
protected override void ConfigureWorkspace(AdhocWorkspace workspace)
{
_workspaceProject = workspace.AddProject(ProjectInfo.Create(
@ -164,7 +154,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
};
// Act
_documentTracker.EditorSettingsManager_Changed(null, null);
_documentTracker.EditorSettingsManager_Changed(null!, null!);
// Assert
Assert.True(called);
@ -176,7 +166,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_hostProject);
var e = new ProjectChangeEventArgs(null, _projectManager.GetLoadedProject(_hostProject.Key), ProjectChangeKind.ProjectAdded);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key)!, ProjectChangeKind.ProjectAdded);
var called = false;
_documentTracker.ContextChanged += (sender, args) =>
@ -199,7 +189,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_hostProject);
var e = new ProjectChangeEventArgs(null, _projectManager.GetLoadedProject(_hostProject.Key), ProjectChangeKind.ProjectChanged);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_hostProject.Key)!, ProjectChangeKind.ProjectChanged);
var called = false;
_documentTracker.ContextChanged += (sender, args) =>
@ -225,7 +215,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
var project = _projectManager.GetLoadedProject(_hostProject.Key);
_projectManager.ProjectRemoved(_hostProject.Key);
var e = new ProjectChangeEventArgs(project, null, ProjectChangeKind.ProjectRemoved);
var e = new ProjectChangeEventArgs(project!, null!, ProjectChangeKind.ProjectRemoved);
var called = false;
_documentTracker.ContextChanged += (sender, args) =>
@ -249,7 +239,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
// Arrange
_projectManager.ProjectAdded(_otherHostProject);
var e = new ProjectChangeEventArgs(null, _projectManager.GetLoadedProject(_otherHostProject.Key), ProjectChangeKind.ProjectChanged);
var e = new ProjectChangeEventArgs(null!, _projectManager.GetLoadedProject(_otherHostProject.Key)!, ProjectChangeKind.ProjectChanged);
var called = false;
_documentTracker.ContextChanged += (sender, args) => called = true;
@ -275,7 +265,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
var importChangedArgs = new ImportChangedEventArgs("path/to/import", FileChangeKind.Changed, new[] { _filePath });
// Act
_documentTracker.Import_Changed(null, importChangedArgs);
_documentTracker.Import_Changed(null!, importChangedArgs);
// Assert
Assert.True(called);
@ -290,7 +280,7 @@ public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDisp
var importChangedArgs = new ImportChangedEventArgs("path/to/import", FileChangeKind.Changed, new[] { "path/to/differentfile" });
// Act & Assert (Does not throw)
_documentTracker.Import_Changed(null, importChangedArgs);
_documentTracker.Import_Changed(null!, importChangedArgs);
}
[UIFact]

Просмотреть файл

@ -4,6 +4,7 @@
#nullable disable
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -14,6 +15,7 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Moq;
@ -764,8 +766,24 @@ public class DefaultVisualStudioRazorParserIntegrationTest : ProjectSnapshotMana
}
}
private class TestCompletionBroker : VisualStudioCompletionBroker
private class TestCompletionBroker : ICompletionBroker
{
public override bool IsCompletionActive(ITextView textView) => false;
public ICompletionSession CreateCompletionSession(ITextView textView, ITrackingPoint triggerPoint, bool trackCaret)
=> throw new NotImplementedException();
public void DismissAllSessions(ITextView textView)
=> throw new NotImplementedException();
public ReadOnlyCollection<ICompletionSession> GetSessions(ITextView textView)
=> throw new NotImplementedException();
public bool IsCompletionActive(ITextView textView)
=> false;
public ICompletionSession TriggerCompletion(ITextView textView)
=> throw new NotImplementedException();
public ICompletionSession TriggerCompletion(ITextView textView, ITrackingPoint triggerPoint, bool trackCaret)
=> throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Threading;
using System.Threading.Tasks;
@ -11,6 +9,7 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.Language.Intellisense;
using Moq;
using Xunit;
using Xunit.Abstractions;
@ -47,57 +46,54 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
}
private VisualStudioDocumentTracker CreateDocumentTracker(bool isSupportedProject = true, int versionNumber = 0)
{
var documentTracker = Mock.Of<VisualStudioDocumentTracker>(tracker =>
tracker.TextBuffer == new TestTextBuffer(new StringTextSnapshot(string.Empty, versionNumber), /* contentType */ null) &&
=> Mock.Of<VisualStudioDocumentTracker>(tracker =>
tracker.TextBuffer == new TestTextBuffer(new StringTextSnapshot(string.Empty, versionNumber), /* contentType */ null) &&
tracker.ProjectPath == "c:\\SomeProject.csproj" &&
tracker.ProjectSnapshot == _projectSnapshot &&
tracker.FilePath == "c:\\SomeFilePath.cshtml" &&
tracker.IsSupportedProject == isSupportedProject, MockBehavior.Strict);
return documentTracker;
}
private DefaultVisualStudioRazorParser CreateParser(VisualStudioDocumentTracker documentTracker)
=> new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<ICompletionBroker>(MockBehavior.Strict));
[UIFact]
public async Task GetLatestCodeDocumentAsync_WaitsForParse()
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
using var parser = CreateParser(documentTracker);
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(StringTextSnapshot.Empty);
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(StringTextSnapshot.Empty);
// Assert - 1
Assert.False(getLatestCodeDocumentTask.IsCompleted);
// Assert - 1
Assert.False(getLatestCodeDocumentTask.IsCompleted);
// Act - 2
await Task.Run(() => parser.OnResultsReady(sender: null, args));
// Act - 2
await Task.Run(() => parser.OnResultsReady(sender: null!, args));
// Assert - 2
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Assert - 2
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Act - 3
var latestCodeDocument = await getLatestCodeDocumentTask;
// Act - 3
var latestCodeDocument = await getLatestCodeDocumentTask;
// Assert - 3
Assert.Same(latestCodeDocument, codeDocument);
}
// Assert - 3
Assert.Same(latestCodeDocument, codeDocument);
}
[UIFact]
@ -105,38 +101,31 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
using var parser = CreateParser(documentTracker);
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
// Initialize the document with some content so we have a syntax tree to return.
await Task.Run(() => parser.OnResultsReady(sender: null, args));
// Initialize the document with some content so we have a syntax tree to return.
await Task.Run(() => parser.OnResultsReady(sender: null!, args));
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(StringTextSnapshot.Empty);
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(StringTextSnapshot.Empty);
// Assert - 1
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Assert - 1
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Act - 2
var latestCodeDocument = await getLatestCodeDocumentTask;
// Act - 2
var latestCodeDocument = await getLatestCodeDocumentTask;
// Assert - 2
Assert.Same(latestCodeDocument, codeDocument);
}
// Assert - 2
Assert.Same(latestCodeDocument, codeDocument);
}
[UIFact]
@ -144,25 +133,18 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var sameSnapshot = StringTextSnapshot.Empty;
using var parser = CreateParser(documentTracker);
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var sameSnapshot = StringTextSnapshot.Empty;
// Act
var getLatestCodeDocumentTask1 = parser.GetLatestCodeDocumentAsync(sameSnapshot);
var getLatestCodeDocumentTask2 = parser.GetLatestCodeDocumentAsync(sameSnapshot);
// Act
var getLatestCodeDocumentTask1 = parser.GetLatestCodeDocumentAsync(sameSnapshot);
var getLatestCodeDocumentTask2 = parser.GetLatestCodeDocumentAsync(sameSnapshot);
// Assert
Assert.Same(getLatestCodeDocumentTask1, getLatestCodeDocumentTask2);
}
// Assert
Assert.Same(getLatestCodeDocumentTask1, getLatestCodeDocumentTask2);
}
[UIFact]
@ -170,26 +152,19 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var snapshot1 = new StringTextSnapshot("Snapshot 1");
var snapshot2 = new StringTextSnapshot("Snapshot 2");
using var parser = CreateParser(documentTracker);
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var snapshot1 = new StringTextSnapshot("Snapshot 1");
var snapshot2 = new StringTextSnapshot("Snapshot 2");
// Act
var getLatestCodeDocumentTask1 = parser.GetLatestCodeDocumentAsync(snapshot1);
var getLatestCodeDocumentTask2 = parser.GetLatestCodeDocumentAsync(snapshot2);
// Act
var getLatestCodeDocumentTask1 = parser.GetLatestCodeDocumentAsync(snapshot1);
var getLatestCodeDocumentTask2 = parser.GetLatestCodeDocumentAsync(snapshot2);
// Assert
Assert.NotSame(getLatestCodeDocumentTask1, getLatestCodeDocumentTask2);
}
// Assert
Assert.NotSame(getLatestCodeDocumentTask1, getLatestCodeDocumentTask2);
}
[UIFact]
@ -198,38 +173,31 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
// Arrange
var documentTracker = CreateDocumentTracker(versionNumber: 1337);
var olderSnapshot = new StringTextSnapshot("Older", versionNumber: 910);
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
using var parser = CreateParser(documentTracker);
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
codeDocument.SetSyntaxTree(syntaxTree);
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
// Initialize the document with some content so we have a syntax tree to return.
await Task.Run(() => parser.OnResultsReady(sender: null, args));
// Initialize the document with some content so we have a syntax tree to return.
await Task.Run(() => parser.OnResultsReady(sender: null!, args));
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(olderSnapshot);
// Act - 1
var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(olderSnapshot);
// Assert - 1
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Assert - 1
Assert.True(getLatestCodeDocumentTask.IsCompleted);
// Act - 2
var latestCodeDocument = await getLatestCodeDocumentTask;
// Act - 2
var latestCodeDocument = await getLatestCodeDocumentTask;
// Assert - 2
Assert.Same(latestCodeDocument, codeDocument);
}
// Assert - 2
Assert.Same(latestCodeDocument, codeDocument);
}
[UIFact]
@ -241,12 +209,7 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
var syntaxTree = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
DefaultVisualStudioRazorParser parser;
codeDocument.SetSyntaxTree(syntaxTree);
using (parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
using (parser = CreateParser(documentTracker))
{
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
@ -256,7 +219,7 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
codeDocument);
// Initialize the document with some content so we have a syntax tree to return.
await Task.Run(() => parser.OnResultsReady(sender: null, args));
await Task.Run(() => parser.OnResultsReady(sender: null!, args));
}
var newerSnapshot = new StringTextSnapshot("Newer", versionNumber: 1337);
@ -383,12 +346,7 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
public void ReparseOnUIThread_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict));
var parser = CreateParser(CreateDocumentTracker());
parser.Dispose();
// Act & Assert
@ -399,12 +357,7 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
public void OnIdle_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict));
var parser = CreateParser(CreateDocumentTracker());
parser.Dispose();
// Act & Assert
@ -415,12 +368,7 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
public void OnDocumentStructureChanged_NoopsIfDisposed()
{
// Arrange
var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict));
var parser = CreateParser(CreateDocumentTracker());
parser.Dispose();
// Act & Assert
@ -431,26 +379,19 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
public void OnDocumentStructureChanged_IgnoresEditsThatAreOld()
{
// Arrange
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
parser._latestChangeReference = new BackgroundParser.ChangeReference(null, new StringTextSnapshot(string.Empty));
var args = new BackgroundParserResultsReadyEventArgs(
new BackgroundParser.ChangeReference(new SourceChange(0, 0, string.Empty), new StringTextSnapshot(string.Empty)),
TestRazorCodeDocument.CreateEmpty());
using var parser = CreateParser(CreateDocumentTracker());
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
parser._latestChangeReference = new BackgroundParser.ChangeReference(null, new StringTextSnapshot(string.Empty));
var args = new BackgroundParserResultsReadyEventArgs(
new BackgroundParser.ChangeReference(new SourceChange(0, 0, string.Empty), new StringTextSnapshot(string.Empty)),
TestRazorCodeDocument.CreateEmpty());
// Act
parser.OnDocumentStructureChanged(args);
// Act
parser.OnDocumentStructureChanged(args);
// Assert
Assert.False(called);
}
// Assert
Assert.False(called);
}
[UIFact]
@ -458,30 +399,23 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
using var parser = CreateParser(documentTracker);
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
var latestChange = new SourceChange(0, 0, string.Empty);
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
var args = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
// Act
parser.OnDocumentStructureChanged(args);
// Act
parser.OnDocumentStructureChanged(args);
// Assert
Assert.True(called);
}
// Assert
Assert.True(called);
}
[UIFact]
@ -489,96 +423,69 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
{
// Arrange
var documentTracker = CreateDocumentTracker();
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(null, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
var badArgs = new BackgroundParserResultsReadyEventArgs(
// This is a different reparse edit, shouldn't be fired for this call
new BackgroundParser.ChangeReference(null, latestSnapshot),
codeDocument);
var goodArgs = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
using var parser = CreateParser(documentTracker);
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
parser._latestChangeReference = new BackgroundParser.ChangeReference(null, latestSnapshot);
var codeDocument = TestRazorCodeDocument.CreateEmpty();
codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
var badArgs = new BackgroundParserResultsReadyEventArgs(
// This is a different reparse edit, shouldn't be fired for this call
new BackgroundParser.ChangeReference(null, latestSnapshot),
codeDocument);
var goodArgs = new BackgroundParserResultsReadyEventArgs(
parser._latestChangeReference,
codeDocument);
// Act - 1
parser.OnDocumentStructureChanged(badArgs);
// Act - 1
parser.OnDocumentStructureChanged(badArgs);
// Assert - 1
Assert.False(called);
// Assert - 1
Assert.False(called);
// Act - 2
parser.OnDocumentStructureChanged(goodArgs);
// Act - 2
parser.OnDocumentStructureChanged(goodArgs);
// Assert - 2
Assert.True(called);
}
// Assert - 2
Assert.True(called);
}
[UIFact]
public void StartIdleTimer_DoesNotRestartTimerWhenAlreadyRunning()
{
// Arrange
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict))
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
_idleDelay = TimeSpan.FromSeconds(5)
})
{
parser.StartIdleTimer();
using (var currentTimer = parser._idleTimer)
{
using var parser = CreateParser(CreateDocumentTracker());
parser.BlockBackgroundIdleWork = new ManualResetEventSlim();
parser._idleDelay = TimeSpan.FromSeconds(5);
parser.StartIdleTimer();
using var currentTimer = parser._idleTimer;
// Act
parser.StartIdleTimer();
var afterTimer = parser._idleTimer;
// Act
parser.StartIdleTimer();
var afterTimer = parser._idleTimer;
// Assert
Assert.NotNull(currentTimer);
Assert.Same(currentTimer, afterTimer);
}
}
// Assert
Assert.NotNull(currentTimer);
Assert.Same(currentTimer, afterTimer);
}
[UIFact]
public void StopIdleTimer_StopsTimer()
{
// Arrange
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict))
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
_idleDelay = TimeSpan.FromSeconds(5)
})
{
parser.StartIdleTimer();
var currentTimer = parser._idleTimer;
using var parser = CreateParser(CreateDocumentTracker());
parser.BlockBackgroundIdleWork = new ManualResetEventSlim();
parser._idleDelay = TimeSpan.FromSeconds(5);
parser.StartIdleTimer();
var currentTimer = parser._idleTimer;
// Act
parser.StopIdleTimer();
// Act
parser.StopIdleTimer();
// Assert
Assert.NotNull(currentTimer);
Assert.Null(parser._idleTimer);
}
// Assert
Assert.NotNull(currentTimer);
Assert.Null(parser._idleTimer);
}
[UIFact]
@ -587,22 +494,15 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
// Arrange
var documentTracker = CreateDocumentTracker();
var textBuffer = (TestTextBuffer)documentTracker.TextBuffer;
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
parser.StartParser();
using var parser = CreateParser(documentTracker);
parser.StartParser();
// Act
parser.StopParser();
// Act
parser.StopParser();
// Assert
Assert.Empty(textBuffer.AttachedChangedEvents);
Assert.Null(parser._parser);
}
// Assert
Assert.Empty(textBuffer.AttachedChangedEvents);
Assert.Null(parser._parser);
}
[UIFact]
@ -611,57 +511,39 @@ public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatch
// Arrange
var documentTracker = CreateDocumentTracker();
var textBuffer = (TestTextBuffer)documentTracker.TextBuffer;
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
documentTracker,
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
// Act
parser.StartParser();
using var parser = CreateParser(documentTracker);
// Assert
Assert.Single(textBuffer.AttachedChangedEvents);
Assert.NotNull(parser._parser);
}
// Act
parser.StartParser();
// Assert
Assert.Single(textBuffer.AttachedChangedEvents);
Assert.NotNull(parser._parser);
}
[UIFact]
public void TryReinitializeParser_ReturnsTrue_IfProjectIsSupported()
{
// Arrange
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(isSupportedProject: true),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
// Act
var result = parser.TryReinitializeParser();
using var parser = CreateParser(CreateDocumentTracker(isSupportedProject: true));
// Assert
Assert.True(result);
}
// Act
var result = parser.TryReinitializeParser();
// Assert
Assert.True(result);
}
[UIFact]
public void TryReinitializeParser_ReturnsFalse_IfProjectIsNotSupported()
{
// Arrange
using (var parser = new DefaultVisualStudioRazorParser(
JoinableTaskContext,
CreateDocumentTracker(isSupportedProject: false),
_projectEngineFactoryProvider,
ErrorReporter,
Mock.Of<VisualStudioCompletionBroker>(MockBehavior.Strict)))
{
// Act
var result = parser.TryReinitializeParser();
using var parser = CreateParser(CreateDocumentTracker(isSupportedProject: false));
// Assert
Assert.False(result);
}
// Act
var result = parser.TryReinitializeParser();
// Assert
Assert.False(result);
}
}

Просмотреть файл

@ -1,14 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.ProjectSystem;
@ -17,7 +15,6 @@ using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Moq;
using Xunit;
@ -28,7 +25,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces;
public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatcherTestBase
{
private readonly IProjectEngineFactoryProvider _projectEngineFactoryProvider;
private readonly ImmutableArray<TagHelperDescriptor> _resolvableTagHelpers;
private readonly TestTagHelperResolver _tagHelperResolver;
private readonly Workspace _workspace;
private readonly Project _workspaceProject;
private readonly ProjectSnapshot _projectSnapshot;
@ -39,14 +36,10 @@ public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatch
{
_projectEngineFactoryProvider = Mock.Of<IProjectEngineFactoryProvider>(MockBehavior.Strict);
var tagHelperResolver = new TestTagHelperResolver()
{
TagHelpers = ImmutableArray.Create(TagHelperDescriptorBuilder.Create("ResolvableTagHelper", "TestAssembly").Build())
};
_tagHelperResolver = new TestTagHelperResolver(
ImmutableArray.Create(TagHelperDescriptorBuilder.Create("ResolvableTagHelper", "TestAssembly").Build()));
_resolvableTagHelpers = tagHelperResolver.TagHelpers;
var workspaceServices = new List<IWorkspaceService>() { tagHelperResolver };
var testServices = TestServices.Create(workspaceServices, Enumerable.Empty<ILanguageService>());
var testServices = TestServices.Create([], []);
_workspace = TestWorkspace.Create(testServices);
AddDisposable(_workspace);
var projectId = ProjectId.CreateNewId("Test");
@ -57,109 +50,111 @@ public class ProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatch
"Test",
LanguageNames.CSharp,
TestProjectData.SomeProject.FilePath));
_workspaceProject = solution.GetProject(projectId);
_workspaceProject = solution.GetProject(projectId).AssumeNotNull();
_projectSnapshot = new ProjectSnapshot(
ProjectState.Create(_projectEngineFactoryProvider, TestProjectData.SomeProject, ProjectWorkspaceState.Default));
_projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()));
}
private IProjectSnapshotManagerAccessor CreateProjectManagerAccessor()
{
var projectManager = new TestProjectSnapshotManager(_workspace, _projectEngineFactoryProvider, Dispatcher);
var mock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
mock.SetupGet(x => x.Instance).Returns(projectManager);
return mock.Object;
}
[UIFact]
public void Dispose_MakesUpdateNoop()
{
// Arrange
using (var stateGenerator = new ProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
{
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var projectManagerAccessor = CreateProjectManagerAccessor();
using var stateGenerator = new ProjectWorkspaceStateGenerator(projectManagerAccessor, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
// Act
stateGenerator.Dispose();
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Act
stateGenerator.Dispose();
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Assert
Assert.Empty(stateGenerator.Updates);
}
// Assert
Assert.Empty(stateGenerator.Updates);
}
[UIFact]
public void Update_StartsUpdateTask()
{
// Arrange
using (var stateGenerator = new ProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
{
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
var projectManagerAccessor = CreateProjectManagerAccessor();
using var stateGenerator = new ProjectWorkspaceStateGenerator(projectManagerAccessor, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Assert
var update = Assert.Single(stateGenerator.Updates);
Assert.False(update.Value.Task.IsCompleted);
}
// Assert
var update = Assert.Single(stateGenerator.Updates);
Assert.False(update.Value.Task.IsCompleted);
}
[UIFact]
public void Update_SoftCancelsIncompleteTaskForSameProject()
{
// Arrange
using (var stateGenerator = new ProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
{
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
var initialUpdate = stateGenerator.Updates.Single().Value;
var projectManagerAccessor = CreateProjectManagerAccessor();
using var stateGenerator = new ProjectWorkspaceStateGenerator(projectManagerAccessor, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
var initialUpdate = stateGenerator.Updates.Single().Value;
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Assert
Assert.True(initialUpdate.Cts.IsCancellationRequested);
}
// Assert
Assert.True(initialUpdate.Cts.IsCancellationRequested);
}
[UIFact]
public async Task Update_NullWorkspaceProject_ClearsProjectWorkspaceState()
{
// Arrange
using (var stateGenerator = new ProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
{
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
var projectManager = new TestProjectSnapshotManager(_workspace, _projectEngineFactoryProvider, Dispatcher);
stateGenerator.Initialize(projectManager);
projectManager.ProjectAdded(_projectSnapshot.HostProject);
projectManager.ProjectWorkspaceStateChanged(_projectSnapshot.Key, _projectWorkspaceStateWithTagHelpers);
var projectManagerAccessor = CreateProjectManagerAccessor();
using var stateGenerator = new ProjectWorkspaceStateGenerator(projectManagerAccessor, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
projectManagerAccessor.Instance.ProjectAdded(_projectSnapshot.HostProject);
projectManagerAccessor.Instance.ProjectWorkspaceStateChanged(_projectSnapshot.Key, _projectWorkspaceStateWithTagHelpers);
// Act
stateGenerator.Update(workspaceProject: null, _projectSnapshot, DisposalToken);
// Act
stateGenerator.Update(workspaceProject: null, _projectSnapshot, DisposalToken);
// Jump off the UI thread so the background work can complete.
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Jump off the UI thread so the background work can complete.
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Assert
var newProjectSnapshot = projectManager.GetLoadedProject(_projectSnapshot.Key);
Assert.Empty(newProjectSnapshot.TagHelpers);
}
// Assert
var newProjectSnapshot = projectManagerAccessor.Instance.GetLoadedProject(_projectSnapshot.Key);
Assert.NotNull(newProjectSnapshot);
Assert.Empty(newProjectSnapshot.TagHelpers);
}
[UIFact]
public async Task Update_ResolvesTagHelpersAndUpdatesWorkspaceState()
{
// Arrange
using (var stateGenerator = new ProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
{
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
var projectManager = new TestProjectSnapshotManager(_workspace, _projectEngineFactoryProvider, Dispatcher);
stateGenerator.Initialize(projectManager);
projectManager.ProjectAdded(_projectSnapshot.HostProject);
var projectManagerAccessor = CreateProjectManagerAccessor();
using var stateGenerator = new ProjectWorkspaceStateGenerator(projectManagerAccessor, _tagHelperResolver, Dispatcher, ErrorReporter, NoOpTelemetryReporter.Instance);
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
projectManagerAccessor.Instance.ProjectAdded(_projectSnapshot.HostProject);
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Act
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
// Jump off the UI thread so the background work can complete.
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Jump off the UI thread so the background work can complete.
await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));
// Assert
var newProjectSnapshot = projectManager.GetLoadedProject(_projectSnapshot.Key);
Assert.Equal<TagHelperDescriptor>(_resolvableTagHelpers, newProjectSnapshot.TagHelpers);
}
// Assert
var newProjectSnapshot = projectManagerAccessor.Instance.GetLoadedProject(_projectSnapshot.Key);
Assert.NotNull(newProjectSnapshot);
Assert.Equal<TagHelperDescriptor>(_tagHelperResolver.TagHelpers, newProjectSnapshot.TagHelpers);
}
}

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@ -14,7 +12,6 @@ using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Moq;
using Xunit;
@ -29,7 +26,6 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
private readonly HostProject _hostProject2;
private readonly HostProject _hostProjectWithConfigurationChange;
private readonly ProjectWorkspaceState _projectWorkspaceStateWithTagHelpers;
private readonly TestTagHelperResolver _tagHelperResolver;
private readonly TestProjectSnapshotManager _projectManager;
private readonly SourceText _sourceText;
@ -39,11 +35,6 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
var someTagHelpers = ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());
_tagHelperResolver = new TestTagHelperResolver()
{
TagHelpers = someTagHelpers,
};
_documents = new HostDocument[]
{
TestProjectData.SomeProjectFile1,
@ -62,21 +53,11 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager = new TestProjectSnapshotManager(triggers: [], Workspace, ProjectEngineFactoryProvider, Dispatcher);
_projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(_tagHelperResolver.TagHelpers);
_projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(someTagHelpers);
_sourceText = SourceText.From("Hello world");
}
protected override void ConfigureWorkspaceServices(List<IWorkspaceService> services)
{
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
services.Add(_tagHelperResolver);
}
[UIFact]
public void Initialize_DoneInCorrectOrderBasedOnInitializePriorityPriority()
{
@ -103,7 +84,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager.Reset();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -120,7 +101,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager.Reset();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -129,7 +110,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
d =>
{
Assert.Equal(_documents[0].FilePath, d);
Assert.Equal(FileKinds.Legacy, snapshot.GetDocument(d).FileKind);
Assert.Equal(FileKinds.Legacy, snapshot.GetDocument(d)!.FileKind);
});
Assert.Equal(ProjectChangeKind.DocumentAdded, _projectManager.ListenersNotifiedOf);
@ -143,7 +124,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager.Reset();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[3], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[3], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -152,7 +133,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
d =>
{
Assert.Equal(_documents[3].FilePath, d);
Assert.Equal(FileKinds.Component, snapshot.GetDocument(d).FileKind);
Assert.Equal(FileKinds.Component, snapshot.GetDocument(d)!.FileKind);
});
Assert.Equal(ProjectChangeKind.DocumentAdded, _projectManager.ListenersNotifiedOf);
@ -163,11 +144,11 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.Reset();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -182,7 +163,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
// Arrange
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -197,11 +178,12 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager.Reset();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
var document = snapshot.GetDocument(snapshot.DocumentFilePaths.Single());
Assert.NotNull(document);
var text = await document.GetTextAsync();
Assert.Equal(0, text.Length);
@ -222,6 +204,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
// Assert
var snapshot = _projectManager.GetSnapshot(_hostProject);
var document = snapshot.GetDocument(snapshot.DocumentFilePaths.Single());
Assert.NotNull(document);
var actual = await document.GetTextAsync();
Assert.Same(expected, actual);
@ -238,7 +221,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
var originalTagHelpers = _projectManager.GetSnapshot(_hostProject).TagHelpers;
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
var newTagHelpers = _projectManager.GetSnapshot(_hostProject).TagHelpers;
@ -261,7 +244,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
var projectEngine = snapshot.GetProjectEngine();
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
snapshot = _projectManager.GetSnapshot(_hostProject);
@ -273,9 +256,9 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null!);
_projectManager.Reset();
// Act
@ -327,9 +310,9 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.ProjectWorkspaceStateChanged(_hostProject.Key, _projectWorkspaceStateWithTagHelpers);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null!);
_projectManager.Reset();
var originalTagHelpers = _projectManager.GetSnapshot(_hostProject).TagHelpers;
@ -352,9 +335,9 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[1], null!);
_projectManager.DocumentAdded(_hostProject.Key, _documents[2], null!);
_projectManager.Reset();
var snapshot = _projectManager.GetSnapshot(_hostProject);
@ -372,7 +355,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.Reset();
// Act
@ -382,7 +365,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
Assert.Equal(ProjectChangeKind.DocumentChanged, _projectManager.ListenersNotifiedOf);
var snapshot = _projectManager.GetSnapshot(_hostProject);
var text = await snapshot.GetDocument(_documents[0].FilePath).GetTextAsync();
var text = await snapshot.GetDocument(_documents[0].FilePath)!.GetTextAsync();
Assert.Same(_sourceText, text);
Assert.True(_projectManager.IsDocumentOpen(_documents[0].FilePath));
@ -393,7 +376,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentOpened(_hostProject.Key, _documents[0].FilePath, _sourceText);
_projectManager.Reset();
@ -409,7 +392,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
Assert.Equal(ProjectChangeKind.DocumentChanged, _projectManager.ListenersNotifiedOf);
var snapshot = _projectManager.GetSnapshot(_hostProject);
var text = await snapshot.GetDocument(_documents[0].FilePath).GetTextAsync();
var text = await snapshot.GetDocument(_documents[0].FilePath)!.GetTextAsync();
Assert.Same(expected, text);
Assert.False(_projectManager.IsDocumentOpen(_documents[0].FilePath));
}
@ -419,7 +402,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.Reset();
var expected = SourceText.From("Hi");
@ -432,7 +415,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
Assert.Equal(ProjectChangeKind.DocumentChanged, _projectManager.ListenersNotifiedOf);
var snapshot = _projectManager.GetSnapshot(_hostProject);
var text = await snapshot.GetDocument(_documents[0].FilePath).GetTextAsync();
var text = await snapshot.GetDocument(_documents[0].FilePath)!.GetTextAsync();
Assert.Same(expected, text);
}
@ -441,7 +424,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentOpened(_hostProject.Key, _documents[0].FilePath, _sourceText);
_projectManager.Reset();
@ -454,7 +437,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
Assert.Equal(ProjectChangeKind.DocumentChanged, _projectManager.ListenersNotifiedOf);
var snapshot = _projectManager.GetSnapshot(_hostProject);
var text = await snapshot.GetDocument(_documents[0].FilePath).GetTextAsync();
var text = await snapshot.GetDocument(_documents[0].FilePath)!.GetTextAsync();
Assert.Same(expected, text);
}
@ -463,7 +446,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
{
// Arrange
_projectManager.ProjectAdded(_hostProject);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
_projectManager.DocumentOpened(_hostProject.Key, _documents[0].FilePath, _sourceText);
_projectManager.Reset();
@ -477,7 +460,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
Assert.Equal(ProjectChangeKind.DocumentChanged, _projectManager.ListenersNotifiedOf);
var snapshot = _projectManager.GetSnapshot(_hostProject);
var text = await snapshot.GetDocument(_documents[0].FilePath).GetTextAsync();
var text = await snapshot.GetDocument(_documents[0].FilePath)!.GetTextAsync();
Assert.Same(expected, text);
}
@ -637,7 +620,7 @@ public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatche
_projectManager.NotifyChangedEvents = true;
// Act
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null);
_projectManager.DocumentAdded(_hostProject.Key, _documents[0], null!);
// Assert
Assert.Equal(new[] { ProjectChangeKind.DocumentAdded, ProjectChangeKind.DocumentChanged, ProjectChangeKind.DocumentRemoved }, listenerNotifications);

Просмотреть файл

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Moq;
@ -31,12 +32,20 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
private readonly PropertyCollection _razorGeneralProperties;
private readonly PropertyCollection _configurationGeneral;
private readonly TestProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
public DefaultWindowsRazorProjectHostTest(ITestOutputHelper testOutput)
: base(testOutput)
{
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(_projectManager);
_projectManagerAccessor = projectManagerAccessorMock.Object;
var projectConfigurationFilePathStore = new Mock<ProjectConfigurationFilePathStore>(MockBehavior.Strict);
projectConfigurationFilePathStore.Setup(s => s.Remove(It.IsAny<ProjectKey>())).Verifiable();
_projectConfigurationFilePathStore = projectConfigurationFilePathStore.Object;
@ -621,7 +630,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
{
// Arrange
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
// Act & Assert
await host.LoadAsync();
@ -636,7 +645,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
{
// Arrange
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
// Act & Assert
await Task.Run(async () => await host.LoadAsync());
@ -655,7 +664,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
// Act & Assert
await Task.Run(async () => await host.LoadAsync());
@ -699,7 +708,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());
@ -763,7 +772,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
await Task.Run(async () => await host.LoadAsync());
Assert.Empty(_projectManager.GetProjects());
@ -814,7 +823,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());
@ -865,7 +874,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());
@ -1021,7 +1030,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());
@ -1096,7 +1105,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
};
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());
@ -1176,7 +1185,7 @@ public class DefaultWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatch
var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath);
var host = new DefaultWindowsRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new DefaultWindowsRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore, languageServerFeatureOptions: null);
host.SkipIntermediateOutputPathExistCheck_TestOnly = true;
await Task.Run(async () => await host.LoadAsync());

Просмотреть файл

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Moq;
@ -26,6 +27,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
{
private readonly ItemCollection _referenceItems;
private readonly TestProjectSnapshotManager _projectManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly ProjectConfigurationFilePathStore _projectConfigurationFilePathStore;
private readonly ItemCollection _contentItems;
private readonly ItemCollection _noneItems;
@ -35,6 +37,13 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
{
_projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, Dispatcher);
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(_projectManager);
_projectManagerAccessor = projectManagerAccessorMock.Object;
var projectConfigurationFilePathStore = new Mock<ProjectConfigurationFilePathStore>(MockBehavior.Strict);
projectConfigurationFilePathStore.Setup(s => s.Remove(It.IsAny<ProjectKey>())).Verifiable();
_projectConfigurationFilePathStore = projectConfigurationFilePathStore.Object;
@ -62,7 +71,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
});
var services = new TestProjectSystemServices("C:\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var changes = new TestProjectChangeDescription[]
{
afterChangeContentItems.ToChange(_contentItems.ToSnapshot()),
@ -104,7 +113,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
});
var services = new TestProjectSystemServices("C:\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var changes = new TestProjectChangeDescription[]
{
_contentItems.ToChange(),
@ -147,7 +156,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
});
var services = new TestProjectSystemServices("C:\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var changes = new TestProjectChangeDescription[]
{
_contentItems.ToChange(),
@ -168,7 +177,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
// Arrange
var services = new TestProjectSystemServices("C:\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.LinkPropertyName] = "Index.cshtml",
@ -188,7 +197,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
// Arrange
var services = new TestProjectSystemServices("C:\\Path\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.FullPathPropertyName] = "C:\\Path\\site.css",
@ -208,7 +217,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
// Arrange
var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.LinkPropertyName] = "site.html",
@ -230,7 +239,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var expectedPath = "C:\\Path\\Index.cshtml";
var services = new TestProjectSystemServices("C:\\Path\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.FullPathPropertyName] = expectedPath,
@ -253,7 +262,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var expectedTargetPath = "C:\\Path\\To\\Index.cshtml";
var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.LinkPropertyName] = "Index.cshtml",
@ -277,7 +286,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var expectedTargetPath = "C:\\Path\\To\\Index.cshtml";
var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
var itemState = new Dictionary<string, string>()
{
[ItemReference.LinkPropertyName] = "Index.cshtml",
@ -300,7 +309,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
// Arrange
var services = new TestProjectSystemServices("C:\\To\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
// Act & Assert
await host.LoadAsync();
@ -316,7 +325,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
// Arrange
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
// Act & Assert
await Task.Run(async () => await host.LoadAsync());
@ -336,7 +345,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0),
};
@ -372,7 +381,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("C:\\Path\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0), // Mock for reading the assembly's version
};
@ -407,7 +416,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
};
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
await Task.Run(async () => await host.LoadAsync());
Assert.Empty(_projectManager.GetProjects());
@ -435,7 +444,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager);
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore);
await Task.Run(async () => await host.LoadAsync());
Assert.Empty(_projectManager.GetProjects());
@ -474,7 +483,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("C:\\Path\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0),
};
@ -519,7 +528,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0),
};
@ -564,7 +573,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("C:\\Path\\Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0),
};
@ -609,7 +618,7 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
var services = new TestProjectSystemServices("Test.csproj");
var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, _projectConfigurationFilePathStore, _projectManager)
var host = new TestFallbackRazorProjectHost(services, _projectManagerAccessor, Dispatcher, _projectConfigurationFilePathStore)
{
AssemblyVersion = new Version(2, 0), // Mock for reading the assembly's version
};
@ -642,11 +651,10 @@ public class FallbackWindowsRazorProjectHostTest : ProjectSnapshotManagerDispatc
{
internal TestFallbackRazorProjectHost(
IUnconfiguredProjectCommonServices commonServices,
Workspace workspace,
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore,
ProjectSnapshotManagerBase projectManager)
: base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager)
IProjectSnapshotManagerAccessor projectManagerAccessor,
ProjectSnapshotManagerDispatcher dispatcher,
ProjectConfigurationFilePathStore projectConfigurationFilePathStore)
: base(commonServices, projectManagerAccessor, dispatcher, projectConfigurationFilePathStore, languageServerFeatureOptions: null)
{
base.SkipIntermediateOutputPathExistCheck_TestOnly = true;
}

Просмотреть файл

@ -1,8 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Immutable;
using System.Linq;
@ -12,8 +10,8 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.LiveShare.Razor.Test;
using Moq;
using Xunit;
@ -21,10 +19,10 @@ using Xunit.Abstractions;
namespace Microsoft.VisualStudio.LiveShare.Razor.Guest;
public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
public class ProjectSnapshotSynchronizationServiceTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase
{
private readonly CollaborationSession _sessionContext;
private readonly TestProjectSnapshotManager _projectSnapshotManager;
private readonly IProjectSnapshotManagerAccessor _projectManagerAccessor;
private readonly ProjectWorkspaceState _projectWorkspaceStateWithTagHelpers;
public ProjectSnapshotSynchronizationServiceTest(ITestOutputHelper testOutput)
@ -32,7 +30,14 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
{
_sessionContext = new TestCollaborationSession(isHost: false);
_projectSnapshotManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher());
var projectManager = new TestProjectSnapshotManager(Workspace, ProjectEngineFactoryProvider, new TestProjectSnapshotManagerDispatcher());
var projectManagerAccessorMock = new Mock<IProjectSnapshotManagerAccessor>(MockBehavior.Strict);
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(projectManager);
_projectManagerAccessor = projectManagerAccessorMock.Object;
_projectWorkspaceStateWithTagHelpers = ProjectWorkspaceState.Create(ImmutableArray.Create(
TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build()));
@ -55,13 +60,17 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
JoinableTaskFactory,
_sessionContext,
hostProjectManagerProxy,
_projectSnapshotManager);
_projectManagerAccessor,
ErrorReporter,
Dispatcher);
// Act
await synchronizationService.InitializeAsync(DisposalToken);
// Assert
var project = Assert.Single(_projectSnapshotManager.GetProjects());
var projects = await Dispatcher.RunOnDispatcherThreadAsync(
_projectManagerAccessor.Instance.GetProjects, DisposalToken);
var project = Assert.Single(projects);
Assert.Equal("/guest/path/project.csproj", project.FilePath);
Assert.Same(RazorConfiguration.Default, project.Configuration);
@ -73,7 +82,7 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
}
[Fact]
public void UpdateGuestProjectManager_ProjectAdded()
public async Task UpdateGuestProjectManager_ProjectAdded()
{
// Arrange
var newHandle = new ProjectSnapshotHandleProxy(
@ -86,14 +95,18 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
JoinableTaskFactory,
_sessionContext,
Mock.Of<IProjectSnapshotManagerProxy>(MockBehavior.Strict),
_projectSnapshotManager);
_projectManagerAccessor,
ErrorReporter,
Dispatcher);
var args = new ProjectChangeEventProxyArgs(older: null, newHandle, ProjectProxyChangeKind.ProjectAdded);
// Act
synchronizationService.UpdateGuestProjectManager(args);
await synchronizationService.UpdateGuestProjectManagerAsync(args);
// Assert
var project = Assert.Single(_projectSnapshotManager.GetProjects());
var projects = await Dispatcher.RunOnDispatcherThreadAsync(
_projectManagerAccessor.Instance.GetProjects, DisposalToken);
var project = Assert.Single(projects);
Assert.Equal("/guest/path/project.csproj", project.FilePath);
Assert.Same(RazorConfiguration.Default, project.Configuration);
@ -105,7 +118,7 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
}
[Fact]
public void UpdateGuestProjectManager_ProjectRemoved()
public async Task UpdateGuestProjectManager_ProjectRemoved()
{
// Arrange
var olderHandle = new ProjectSnapshotHandleProxy(
@ -118,20 +131,27 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
JoinableTaskFactory,
_sessionContext,
Mock.Of<IProjectSnapshotManagerProxy>(MockBehavior.Strict),
_projectSnapshotManager);
_projectManagerAccessor,
ErrorReporter,
Dispatcher);
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
_projectSnapshotManager.ProjectAdded(hostProject);
await Dispatcher.RunOnDispatcherThreadAsync(
() => _projectManagerAccessor.Instance.ProjectAdded(hostProject),
DisposalToken);
var args = new ProjectChangeEventProxyArgs(olderHandle, newer: null, ProjectProxyChangeKind.ProjectRemoved);
// Act
synchronizationService.UpdateGuestProjectManager(args);
await synchronizationService.UpdateGuestProjectManagerAsync(args);
// Assert
Assert.Empty(_projectSnapshotManager.GetProjects());
var projects = await Dispatcher.RunOnDispatcherThreadAsync(
_projectManagerAccessor.Instance.GetProjects, DisposalToken);
Assert.Empty(projects);
}
[Fact]
public void UpdateGuestProjectManager_ProjectChanged_ConfigurationChange()
public async Task UpdateGuestProjectManager_ProjectChanged_ConfigurationChange()
{
// Arrange
var oldHandle = new ProjectSnapshotHandleProxy(
@ -151,24 +171,32 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
JoinableTaskFactory,
_sessionContext,
Mock.Of<IProjectSnapshotManagerProxy>(MockBehavior.Strict),
_projectSnapshotManager);
_projectManagerAccessor,
ErrorReporter,
Dispatcher);
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
_projectSnapshotManager.ProjectAdded(hostProject);
_projectSnapshotManager.ProjectConfigurationChanged(hostProject);
await Dispatcher.RunOnDispatcherThreadAsync(() =>
{
var projectManager = _projectManagerAccessor.Instance;
projectManager.ProjectAdded(hostProject);
projectManager.ProjectConfigurationChanged(hostProject);
}, DisposalToken);
var args = new ProjectChangeEventProxyArgs(oldHandle, newHandle, ProjectProxyChangeKind.ProjectChanged);
// Act
synchronizationService.UpdateGuestProjectManager(args);
await synchronizationService.UpdateGuestProjectManagerAsync(args);
// Assert
var project = Assert.Single(_projectSnapshotManager.GetProjects());
var projects = await Dispatcher.RunOnDispatcherThreadAsync(
_projectManagerAccessor.Instance.GetProjects, DisposalToken);
var project = Assert.Single(projects);
Assert.Equal("/guest/path/project.csproj", project.FilePath);
Assert.Same(newConfiguration, project.Configuration);
Assert.Empty(project.TagHelpers);
}
[Fact]
public void UpdateGuestProjectManager_ProjectChanged_ProjectWorkspaceStateChange()
public async Task UpdateGuestProjectManager_ProjectChanged_ProjectWorkspaceStateChange()
{
// Arrange
var oldHandle = new ProjectSnapshotHandleProxy(
@ -188,17 +216,25 @@ public class ProjectSnapshotSynchronizationServiceTest : WorkspaceTestBase
JoinableTaskFactory,
_sessionContext,
Mock.Of<IProjectSnapshotManagerProxy>(MockBehavior.Strict),
_projectSnapshotManager);
_projectManagerAccessor,
ErrorReporter,
Dispatcher);
var hostProject = new HostProject("/guest/path/project.csproj", "/guest/path/obj", RazorConfiguration.Default, "project");
_projectSnapshotManager.ProjectAdded(hostProject);
_projectSnapshotManager.ProjectWorkspaceStateChanged(hostProject.Key, oldHandle.ProjectWorkspaceState);
await Dispatcher.RunOnDispatcherThreadAsync(() =>
{
var projectManager = _projectManagerAccessor.Instance;
projectManager.ProjectAdded(hostProject);
projectManager.ProjectWorkspaceStateChanged(hostProject.Key, oldHandle.ProjectWorkspaceState);
}, DisposalToken);
var args = new ProjectChangeEventProxyArgs(oldHandle, newHandle, ProjectProxyChangeKind.ProjectChanged);
// Act
synchronizationService.UpdateGuestProjectManager(args);
await synchronizationService.UpdateGuestProjectManagerAsync(args);
// Assert
var project = Assert.Single(_projectSnapshotManager.GetProjects());
var projects = await Dispatcher.RunOnDispatcherThreadAsync(
_projectManagerAccessor.Instance.GetProjects, DisposalToken);
var project = Assert.Single(projects);
Assert.Equal("/guest/path/project.csproj", project.FilePath);
Assert.Same(RazorConfiguration.Default, project.Configuration);