Skip to content

Commit bdab719

Browse files
committed
refactor loading solution in workspace
1 parent 2284559 commit bdab719

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,34 +105,49 @@ public async Task LoadSolutionInWorkspace(SharpIdeSolutionModel solutionModel, S
105105

106106
Guard.Against.Null(_workspace);
107107

108+
await LoadSolutionCoreAsync(_sharpIdeSolutionModel.FilePath, cancellationToken);
109+
110+
timer.Stop();
111+
_logger.LogInformation("RoslynAnalysis: Solution loaded in {ElapsedMilliseconds}ms", timer.ElapsedMilliseconds);
112+
}
113+
114+
private async Task LoadSolutionCoreAsync(string solutionFilePath, CancellationToken cancellationToken)
115+
{
108116
using (var ___ = SharpIdeOtel.Source.StartActivity("RestoreSolution"))
109117
{
110118
// MsBuildProjectLoader doesn't do a restore which is absolutely required for resolving PackageReferences, if they have changed. I am guessing it just reads from project.assets.json
111-
await _buildService.MsBuildAsync(_sharpIdeSolutionModel.FilePath, BuildType.Restore, BuildStartedFlags.UserFacing, cancellationToken);
119+
// It is important to note that a Workspace has no concept of MSBuild, nuget packages etc. It is just told about project references and "metadata" references, which are dlls. This is what MSBuild does - it reads the csproj, and most importantly resolves nuget package references to dlls
120+
await _buildService.MsBuildAsync(solutionFilePath, BuildType.Restore, BuildStartedFlags.UserFacing, cancellationToken);
112121
}
122+
113123
using (var ___ = SharpIdeOtel.Source.StartActivity("OpenSolution"))
114124
{
115125
//_msBuildProjectLoader!.LoadMetadataForReferencedProjects = true;
116-
var (solutionInfo, projectFileInfos) = await _msBuildProjectLoader!.LoadSolutionInfoAsync(_sharpIdeSolutionModel.FilePath, cancellationToken: cancellationToken);
126+
127+
// This call is the expensive part - MSBuild is slow. There doesn't seem to be any incrementalism for solutions.
128+
// The best we could do to speed it up is do .LoadProjectInfoAsync for the single project, and somehow munge that into the existing solution
129+
var (solutionInfo, projectFileInfos) = await _msBuildProjectLoader!.LoadSolutionInfoAsync(solutionFilePath, cancellationToken: cancellationToken);
117130
_projectFileInfoMap = projectFileInfos;
131+
118132
var analyzerReferencePaths = solutionInfo.Projects
119133
.SelectMany(p => p.AnalyzerReferences.OfType<IsolatedAnalyzerFileReference>().Select(a => a.FullPath))
120134
.OfType<string>()
121135
.Distinct()
122136
.ToImmutableArray();
123-
124137
await _analyzerFileWatcher.StartWatchingFiles(analyzerReferencePaths);
125-
_workspace.ClearSolution();
126-
var solution = _workspace.AddSolution(solutionInfo);
138+
139+
// There doesn't appear to be any noticeable difference between ClearSolution + AddSolution vs OnSolutionReloaded
140+
//_workspace.OnSolutionReloaded(newSolutionInfo);
141+
_workspace!.ClearSolution();
142+
_workspace.AddSolution(solutionInfo);
127143

128144
// If these aren't added, IDiagnosticAnalyzerService will not return compiler analyzer diagnostics
129145
// Note that we aren't currently using IDiagnosticAnalyzerService
130146
//var solutionAnalyzerReferences = CreateSolutionLevelAnalyzerReferencesForWorkspace(_workspace);
131147
//solution = solution.WithAnalyzerReferences(solutionAnalyzerReferences);
132148
//_workspace.SetCurrentSolution(solution);
133149
}
134-
timer.Stop();
135-
_logger.LogInformation("RoslynAnalysis: Solution loaded in {ElapsedMilliseconds}ms", timer.ElapsedMilliseconds);
150+
136151
_solutionLoadedTcs.SetResult();
137152
}
138153

@@ -199,24 +214,12 @@ public async Task ReloadSolution(CancellationToken cancellationToken = default)
199214
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(ReloadSolution)}");
200215
_logger.LogInformation("RoslynAnalysis: Reloading solution");
201216
await _solutionLoadedTcs.Task;
217+
_solutionLoadedTcs = new TaskCompletionSource();
202218
Guard.Against.Null(_workspace, nameof(_workspace));
203219
Guard.Against.Null(_msBuildProjectLoader, nameof(_msBuildProjectLoader));
204220

205-
// It is important to note that a Workspace has no concept of MSBuild, nuget packages etc. It is just told about project references and "metadata" references, which are dlls. This is the what MSBuild does - it reads the csproj, and most importantly resolves nuget package references to dlls
206-
await _buildService.MsBuildAsync(_sharpIdeSolutionModel!.FilePath, BuildType.Restore, BuildStartedFlags.UserFacing, cancellationToken);
207-
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.MSBuildProjectLoader.LoadSolutionInfoAsync");
208-
// This call is the expensive part - MSBuild is slow. There doesn't seem to be any incrementalism for solutions.
209-
// The best we could do to speed it up is do .LoadProjectInfoAsync for the single project, and somehow munge that into the existing solution
210-
var (newSolutionInfo, projectFileInfos) = await _msBuildProjectLoader.LoadSolutionInfoAsync(_sharpIdeSolutionModel!.FilePath, cancellationToken: cancellationToken);
211-
_projectFileInfoMap = projectFileInfos;
212-
__?.Dispose();
221+
await LoadSolutionCoreAsync(_sharpIdeSolutionModel!.FilePath, cancellationToken);
213222

214-
var ___ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.Workspace.OnSolutionReloaded");
215-
// There doesn't appear to be any noticeable difference between ClearSolution + AddSolution vs OnSolutionReloaded
216-
//_workspace.OnSolutionReloaded(newSolutionInfo);
217-
_workspace.ClearSolution();
218-
_workspace.AddSolution(newSolutionInfo);
219-
___?.Dispose();
220223
_logger.LogInformation("RoslynAnalysis: Solution reloaded");
221224
}
222225

0 commit comments

Comments
 (0)