Skip to content

Commit

Permalink
SLVS-1536 Add IRoslynWorkspaceWrapper & IRoslynSolutionWrapper implem…
Browse files Browse the repository at this point in the history
  • Loading branch information
georgii-borovinskikh-sonarsource authored Oct 22, 2024
1 parent fcd8b3f commit 86e68a7
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 4 deletions.
103 changes: 103 additions & 0 deletions src/Infrastructure.VS.UnitTests/Roslyn/RoslynSolutionWrapperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using SonarLint.VisualStudio.Infrastructure.VS.Roslyn;

namespace SonarLint.VisualStudio.Infrastructure.VS.UnitTests.Roslyn;

[TestClass]
public class RoslynWrappersTests
{
[TestMethod]
public void MefCtor_CheckIsSingleton()
{
MefTestHelpers.CheckIsSingletonMefComponent<RoslynWorkspaceWrapper>();
}

[TestMethod]
public void AddAnalyzer_CurrentSolutionContainsAnalyzer()
{
var analyzerFileReference = new AnalyzerFileReference(@"C:\abc", Substitute.For<IAnalyzerAssemblyLoader>());
var roslynWorkspaceWrapper = CreateWorkspaceWrapper();
var analyzers = ImmutableArray.Create(analyzerFileReference);

var solutionAfterAddition = roslynWorkspaceWrapper.CurrentSolution.WithAnalyzerReferences(analyzers);
roslynWorkspaceWrapper.TryApplyChanges(solutionAfterAddition).Should().BeTrue();

roslynWorkspaceWrapper.CurrentSolution.GetRoslynSolution().AnalyzerReferences.Contains(analyzerFileReference).Should().BeTrue();
}

[TestMethod]
public void AddAndRemoveAnalyzer_CurrentSolutionNoLongerContainsAnalyzer()
{
var analyzerFileReference = new AnalyzerFileReference(@"C:\abc", Substitute.For<IAnalyzerAssemblyLoader>());
var roslynWorkspaceWrapper = CreateWorkspaceWrapper();
var analyzers = ImmutableArray.Create(analyzerFileReference);

var solutionAfterAddition = roslynWorkspaceWrapper.CurrentSolution.WithAnalyzerReferences(analyzers);
roslynWorkspaceWrapper.TryApplyChanges(solutionAfterAddition).Should().BeTrue();

var solutionAfterRemoval = roslynWorkspaceWrapper.CurrentSolution.RemoveAnalyzerReferences(analyzers);
roslynWorkspaceWrapper.TryApplyChanges(solutionAfterRemoval).Should().BeTrue();

roslynWorkspaceWrapper.CurrentSolution.GetRoslynSolution().AnalyzerReferences.Contains(analyzerFileReference).Should().BeFalse();
}

[TestMethod]
public void RemoveAnalyzer_IsNotPresentInTheCurrentSolution_AppliesNoChange()
{
var analyzerFileReference = new AnalyzerFileReference(@"C:\abc", Substitute.For<IAnalyzerAssemblyLoader>());
var analyzers = ImmutableArray.Create(analyzerFileReference);
var roslynWorkspaceWrapper = CreateWorkspaceWrapper();

var solutionAfterRemoval = roslynWorkspaceWrapper.CurrentSolution.RemoveAnalyzerReferences(analyzers);
roslynWorkspaceWrapper.TryApplyChanges(solutionAfterRemoval).Should().BeTrue();

roslynWorkspaceWrapper.CurrentSolution.GetRoslynSolution().AnalyzerReferences.Contains(analyzerFileReference).Should().BeFalse();
}

[TestMethod]
public void AddMultipleAndRemoveOneAnalyzer_CurrentSolutionContainsOneAnalyzer()
{
var analyzerFileReference1 = new AnalyzerFileReference(@"C:\abc", Substitute.For<IAnalyzerAssemblyLoader>());
var analyzerFileReference2 = new AnalyzerFileReference(@"C:\abc", Substitute.For<IAnalyzerAssemblyLoader>());
var analyzersToAdd = ImmutableArray.Create(analyzerFileReference1, analyzerFileReference2);
var analyzersToRemove = ImmutableArray.Create(analyzerFileReference1);
var roslynWorkspaceWrapper = CreateWorkspaceWrapper();

roslynWorkspaceWrapper.TryApplyChanges(roslynWorkspaceWrapper.CurrentSolution.WithAnalyzerReferences(analyzersToAdd)).Should().BeTrue();
roslynWorkspaceWrapper.TryApplyChanges(roslynWorkspaceWrapper.CurrentSolution.RemoveAnalyzerReferences(analyzersToRemove)).Should().BeTrue();
roslynWorkspaceWrapper.CurrentSolution.GetRoslynSolution().AnalyzerReferences.Contains(analyzerFileReference1).Should().BeFalse();
roslynWorkspaceWrapper.CurrentSolution.GetRoslynSolution().AnalyzerReferences.Contains(analyzerFileReference2).Should().BeTrue();
}

private static IRoslynWorkspaceWrapper CreateWorkspaceWrapper()
{
var adhocWorkspace = new AdhocWorkspace();

var slnInfo = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default, null, []);
adhocWorkspace.AddSolution(slnInfo);

return new RoslynWorkspaceWrapper(adhocWorkspace);
}
}
18 changes: 18 additions & 0 deletions src/Infrastructure.VS/Roslyn/IRoslynSolutionWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,21 @@ internal interface IRoslynSolutionWrapper
IRoslynSolutionWrapper WithAnalyzerReferences(ImmutableArray<AnalyzerFileReference> analyzers);
Solution GetRoslynSolution();
}

internal class RoslynSolutionWrapper(Solution solution) : IRoslynSolutionWrapper
{
public IRoslynSolutionWrapper RemoveAnalyzerReferences(ImmutableArray<AnalyzerFileReference> analyzers) =>
new RoslynSolutionWrapper(
analyzers
.Aggregate<AnalyzerFileReference, Solution>(
solution,
(current, analyzer) =>
current.AnalyzerReferences.Contains(analyzer)
? current.RemoveAnalyzerReference(analyzer)
: current));

public IRoslynSolutionWrapper WithAnalyzerReferences(ImmutableArray<AnalyzerFileReference> analyzers) =>
new RoslynSolutionWrapper(solution.WithAnalyzerReferences(analyzers));

public Solution GetRoslynSolution() => solution;
}
28 changes: 28 additions & 0 deletions src/Infrastructure.VS/Roslyn/IRoslynWorkspaceWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,38 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices;

namespace SonarLint.VisualStudio.Infrastructure.VS.Roslyn;

internal interface IRoslynWorkspaceWrapper
{
IRoslynSolutionWrapper CurrentSolution { get; }
bool TryApplyChanges(IRoslynSolutionWrapper solution);
}

[Export(typeof(IRoslynWorkspaceWrapper))]
[PartCreationPolicy(CreationPolicy.Shared)]
internal class RoslynWorkspaceWrapper : IRoslynWorkspaceWrapper
{
private readonly Workspace workspace;

[ImportingConstructor]
[ExcludeFromCodeCoverage] // not mef-testable
public RoslynWorkspaceWrapper(VisualStudioWorkspace workspace) : this(workspace as Workspace)
{
}

internal /* for testing */ RoslynWorkspaceWrapper(Workspace workspace)
{
this.workspace = workspace;
}

public IRoslynSolutionWrapper CurrentSolution =>
new RoslynSolutionWrapper(workspace.CurrentSolution);
public bool TryApplyChanges(IRoslynSolutionWrapper solution) =>
workspace.TryApplyChanges(solution.GetRoslynSolution());
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
# Report date/time: 2024-10-18T13:49:00.8690276Z
# Report date/time: 2024-10-21T14:35:45.2223924Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
Expand Down Expand Up @@ -239,6 +239,7 @@ Referenced assemblies:
- 'Microsoft.VisualStudio.CoreUtility, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Editor, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Interop, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.LanguageServices, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
- 'Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Shell.Framework, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Text.Data, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Expand All @@ -252,7 +253,7 @@ Referenced assemblies:
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.IO.Abstractions, Version=9.0.0.0, Culture=neutral, PublicKeyToken=96bf224d23c43e59'
# Number of references: 18
# Number of references: 19

---
Assembly: 'SonarLint.VisualStudio.Integration, Version=8.6.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
# Report date/time: 2024-10-18T13:49:00.8690276Z
# Report date/time: 2024-10-21T14:35:45.2223924Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
Expand Down Expand Up @@ -239,6 +239,7 @@ Referenced assemblies:
- 'Microsoft.VisualStudio.CoreUtility, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Editor, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Interop, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.LanguageServices, Version=3.11.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
- 'Microsoft.VisualStudio.Shell.15.0, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Shell.Framework, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'Microsoft.VisualStudio.Text.Data, Version=17.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Expand All @@ -252,7 +253,7 @@ Referenced assemblies:
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.IO.Abstractions, Version=9.0.0.0, Culture=neutral, PublicKeyToken=96bf224d23c43e59'
# Number of references: 18
# Number of references: 19

---
Assembly: 'SonarLint.VisualStudio.Integration, Version=8.6.0.0, Culture=neutral, PublicKeyToken=null'
Expand Down

0 comments on commit 86e68a7

Please sign in to comment.