Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
Expand Down Expand Up @@ -39,4 +40,10 @@ public ProjectSnapshotManagerBase Instance
return _instance;
}
}

public bool TryGetInstance([NotNullWhen(true)] out ProjectSnapshotManagerBase? instance)
{
instance = _instance;
return instance is not null;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;

namespace Microsoft.CodeAnalysis.Razor.Workspaces;

internal interface IProjectSnapshotManagerAccessor
{
ProjectSnapshotManagerBase Instance { get; }

/// <summary>
/// Retrieves the <see cref="ProjectSnapshotManagerBase"/> instance. Returns <see langword="true"/>
/// if the instance has been created; otherwise, <see langword="false"/>.
/// </summary>
bool TryGetInstance([NotNullWhen(true)] out ProjectSnapshotManagerBase? instance);
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ internal async Task DynamicFileAddedAsync(
{
try
{
if (_projectManagerAccessor.Instance.TryGetLoadedProject(razorProjectKey, out var project))
if (_projectManagerAccessor.TryGetInstance(out var projectSnapshotManager) &&
projectSnapshotManager.TryGetLoadedProject(razorProjectKey, out var project))
{
if (project is ProjectSnapshot { HostProject: FallbackHostProject })
{
Expand Down Expand Up @@ -76,7 +77,8 @@ internal async Task DynamicFileRemovedAsync(
{
try
{
if (_projectManagerAccessor.Instance.TryGetLoadedProject(razorProjectKey, out var project) &&
if (_projectManagerAccessor.TryGetInstance(out var projectSnapshotManager) &&
projectSnapshotManager.TryGetLoadedProject(razorProjectKey, out var project) &&
project is ProjectSnapshot { HostProject: FallbackHostProject })
{
// If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand Down Expand Up @@ -192,7 +193,9 @@ private IEnumerable<ProjectKey> GetProjectKeys(Uri hostDocumentUri)
yield break;
}

var projects = _projectSnapshotManagerAccessor.Instance.GetProjects();
var projects = _projectSnapshotManagerAccessor.TryGetInstance(out var projectSnapshotManager)
? projectSnapshotManager.GetProjects()
: ImmutableArray<IProjectSnapshot>.Empty;

var inAny = false;
var normalizedDocumentPath = FilePathService.GetProjectSystemFilePath(hostDocumentUri);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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;
Expand Down Expand Up @@ -59,4 +60,10 @@ ProjectSnapshotManagerBase Create()
}
}
}

public bool TryGetInstance([NotNullWhen(true)] out ProjectSnapshotManagerBase? instance)
{
instance = _projectManager;
return instance is not null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X;
Expand Down Expand Up @@ -180,6 +181,14 @@ internal static IProjectSnapshotManagerAccessor CreateProjectSnapshotManagerAcce

internal class TestProjectSnapshotManagerAccessor(ProjectSnapshotManagerBase instance) : IProjectSnapshotManagerAccessor
{
public ProjectSnapshotManagerBase Instance => instance;
private readonly ProjectSnapshotManagerBase _instance = instance;

public ProjectSnapshotManagerBase Instance => _instance;

public bool TryGetInstance([NotNullWhen(true)] out ProjectSnapshotManagerBase instance)
{
instance = _instance;
return instance is not null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Test;

internal class TestProjectSnapshotManagerAccessor(ProjectSnapshotManagerBase instance) : IProjectSnapshotManagerAccessor
{
public ProjectSnapshotManagerBase Instance => instance;
private readonly ProjectSnapshotManagerBase _instance = instance;

public ProjectSnapshotManagerBase Instance => _instance;

public bool TryGetInstance([NotNullWhen(true)] out ProjectSnapshotManagerBase? instance)
{
instance = _instance;
return instance is not null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer;
using Microsoft.AspNetCore.Razor.Test.Common.Workspaces;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.LanguageServer.ContainedLanguage;
Expand Down Expand Up @@ -78,6 +79,40 @@ public void TryCreateMultipleFor_NonRazorLSPBuffer_ReturnsFalse()
Assert.Null(virtualDocuments);
}

[Fact]
public void TryCreateMultipleFor_NoProjectSnapshotManager_ReturnsFalse()
{
// Arrange
var uri = new Uri("C:/path/to/file.razor");
var uriProvider = StrictMock.Of<FileUriProvider>(x =>
x.GetOrCreate(It.IsAny<ITextBuffer>()) == uri);

var projectManagerAccessorMock = new StrictMock<IProjectSnapshotManagerAccessor>();

ProjectSnapshotManagerBase instance = null;
projectManagerAccessorMock
.Setup(x => x.TryGetInstance(out instance))
.Returns(false);

var factory = new CSharpVirtualDocumentFactory(
_contentTypeRegistryService,
_textBufferFactoryService,
StrictMock.Of<ITextDocumentFactoryService>(),
uriProvider,
_filePathService,
projectManagerAccessorMock.Object,
TestLanguageServerFeatureOptions.Instance,
LoggerFactory,
telemetryReporter: null!);

// Act
var result = factory.TryCreateMultipleFor(_nonRazorLSPBuffer, out var virtualDocuments);

// Assert
Assert.False(result);
Assert.Null(virtualDocuments);
}

[Fact]
public void TryCreateMultipleFor_RazorLSPBuffer_ReturnsCSharpVirtualDocumentAndTrue()
{
Expand Down Expand Up @@ -117,7 +152,18 @@ public void TryCreateMultipleFor_RazorLSPBuffer_ReturnsMultipleCSharpVirtualDocu
project = TestProjectSnapshot.Create(@"C:\path\to\project2.csproj", @"C:\path\to\obj2", Array.Empty<string>(), RazorConfiguration.Default, projectWorkspaceState: null);
projectSnapshotManager.ProjectAdded(project.HostProject);
projectSnapshotManager.CreateAndAddDocument(project, @"C:\path\to\file.razor");
var projectSnapshotManagerAccessor = Mock.Of<IProjectSnapshotManagerAccessor>(a => a.Instance == projectSnapshotManager, MockBehavior.Strict);

var projectManagerAccessorMock = new StrictMock<IProjectSnapshotManagerAccessor>();
projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(projectSnapshotManager);

ProjectSnapshotManagerBase instance = projectSnapshotManager;
projectManagerAccessorMock
.Setup(x => x.TryGetInstance(out instance))
.Returns(true);

var projectSnapshotManagerAccessor = projectManagerAccessorMock.Object;

var languageServerFeatureOptions = new TestLanguageServerFeatureOptions(includeProjectKeyInGeneratedFilePath: true);
var filePathService = new FilePathService(languageServerFeatureOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,21 @@ public FallbackProjectManagerTest(ITestOutputHelper testOutputHelper)

_projectManager = new TestProjectSnapshotManager(ProjectEngineFactoryProvider, Dispatcher);

var projectManagerAccessor = StrictMock.Of<IProjectSnapshotManagerAccessor>(a =>
a.Instance == _projectManager);
var projectManagerAccessorMock = new StrictMock<IProjectSnapshotManagerAccessor>();

projectManagerAccessorMock
.SetupGet(x => x.Instance)
.Returns(_projectManager);

ProjectSnapshotManagerBase? instanceResult = _projectManager;
projectManagerAccessorMock
.Setup(x => x.TryGetInstance(out instanceResult))
.Returns(true);

_fallbackProjectManger = new FallbackProjectManager(
_projectConfigurationFilePathStore,
languageServerFeatureOptions,
projectManagerAccessor,
projectManagerAccessorMock.Object,
Dispatcher,
WorkspaceProvider,
NoOpTelemetryReporter.Instance);
Expand Down