RoslynAnalysis - use ilogger

This commit is contained in:
Matt Parker
2025-10-24 19:22:44 +10:00
parent 5ec788c305
commit 990c743f98
2 changed files with 27 additions and 23 deletions

View File

@@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Razor.SemanticTokens;
using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Logging;
using Roslyn.LanguageServer.Protocol; using Roslyn.LanguageServer.Protocol;
using SharpIDE.Application.Features.Analysis.FixLoaders; using SharpIDE.Application.Features.Analysis.FixLoaders;
using SharpIDE.Application.Features.Analysis.Razor; using SharpIDE.Application.Features.Analysis.Razor;
@@ -32,8 +33,10 @@ using DiagnosticSeverity = Microsoft.CodeAnalysis.DiagnosticSeverity;
namespace SharpIDE.Application.Features.Analysis; namespace SharpIDE.Application.Features.Analysis;
public class RoslynAnalysis public class RoslynAnalysis(ILogger<RoslynAnalysis> logger)
{ {
private readonly ILogger<RoslynAnalysis> _logger = logger;
public static AdhocWorkspace? _workspace; public static AdhocWorkspace? _workspace;
private static CustomMsBuildProjectLoader? _msBuildProjectLoader; private static CustomMsBuildProjectLoader? _msBuildProjectLoader;
private static RemoteSnapshotManager? _snapshotManager; private static RemoteSnapshotManager? _snapshotManager;
@@ -54,14 +57,14 @@ public class RoslynAnalysis
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine($"RoslynAnalysis: Error during analysis: {e}"); _logger.LogError(e, "An error occurred during analysis");
} }
}); });
} }
public async Task Analyse(SharpIdeSolutionModel solutionModel, CancellationToken cancellationToken = default) public async Task Analyse(SharpIdeSolutionModel solutionModel, CancellationToken cancellationToken = default)
{ {
Console.WriteLine($"RoslynAnalysis: Loading solution");
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(Analyse)}"); using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(Analyse)}");
_logger.LogInformation("RoslynAnalysis: Loading solution {SolutionPath}", solutionModel.FilePath);
_sharpIdeSolutionModel = solutionModel; _sharpIdeSolutionModel = solutionModel;
var timer = Stopwatch.StartNew(); var timer = Stopwatch.StartNew();
if (_workspace is null) if (_workspace is null)
@@ -76,7 +79,7 @@ public class RoslynAnalysis
var host = MefHostServices.Create(container); var host = MefHostServices.Create(container);
_workspace = new AdhocWorkspace(host); _workspace = new AdhocWorkspace(host);
_workspace.RegisterWorkspaceFailedHandler(o => Console.WriteLine($"Workspace failed: {o.Diagnostic.Message}")); _workspace.RegisterWorkspaceFailedHandler(o => _logger.LogError("WorkspaceFailedHandler - Workspace failure: {DiagnosticMessage}", o.Diagnostic.Message));
var snapshotManager = container.GetExports<RemoteSnapshotManager>().FirstOrDefault(); var snapshotManager = container.GetExports<RemoteSnapshotManager>().FirstOrDefault();
_snapshotManager = snapshotManager; _snapshotManager = snapshotManager;
@@ -102,7 +105,7 @@ public class RoslynAnalysis
var solution = _workspace.AddSolution(solutionInfo); var solution = _workspace.AddSolution(solutionInfo);
} }
timer.Stop(); timer.Stop();
Console.WriteLine($"RoslynAnalysis: Solution loaded in {timer.ElapsedMilliseconds}ms"); _logger.LogInformation("RoslynAnalysis: Solution loaded in {ElapsedMilliseconds}ms", timer.ElapsedMilliseconds);
_solutionLoadedTcs.SetResult(); _solutionLoadedTcs.SetResult();
using (var ____ = SharpIdeOtel.Source.StartActivity("LoadAnalyzersAndFixers")) using (var ____ = SharpIdeOtel.Source.StartActivity("LoadAnalyzersAndFixers"))
@@ -154,15 +157,15 @@ public class RoslynAnalysis
// // // } // // // }
// // } // // }
// } // }
Console.WriteLine("RoslynAnalysis: Analysis completed."); _logger.LogInformation("RoslynAnalysis: Analysis completed");
} }
/// Callers should call UpdateSolutionDiagnostics after this /// Callers should call UpdateSolutionDiagnostics after this
/// Ensure that the SharpIdeSolutionModel has been updated before calling this and any subsequent calls /// Ensure that the SharpIdeSolutionModel has been updated before calling this and any subsequent calls
public async Task ReloadSolution(CancellationToken cancellationToken = default) public async Task ReloadSolution(CancellationToken cancellationToken = default)
{ {
Console.WriteLine($"RoslynAnalysis: Reloading Solution");
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(ReloadSolution)}"); using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(ReloadSolution)}");
_logger.LogInformation("RoslynAnalysis: Reloading solution");
await _solutionLoadedTcs.Task; await _solutionLoadedTcs.Task;
Guard.Against.Null(_workspace, nameof(_workspace)); Guard.Against.Null(_workspace, nameof(_workspace));
Guard.Against.Null(_msBuildProjectLoader, nameof(_msBuildProjectLoader)); Guard.Against.Null(_msBuildProjectLoader, nameof(_msBuildProjectLoader));
@@ -181,21 +184,21 @@ public class RoslynAnalysis
_workspace.ClearSolution(); _workspace.ClearSolution();
_workspace.AddSolution(newSolutionInfo); _workspace.AddSolution(newSolutionInfo);
___?.Dispose(); ___?.Dispose();
Console.WriteLine("RoslynAnalysis: Solution reloaded"); _logger.LogInformation("RoslynAnalysis: Solution reloaded");
} }
/// Callers should call UpdateSolutionDiagnostics after this /// Callers should call UpdateSolutionDiagnostics after this
/// Ensure that the SharpIdeSolutionModel has been updated before calling this and any subsequent calls /// Ensure that the SharpIdeSolutionModel has been updated before calling this and any subsequent calls
public async Task ReloadProject(SharpIdeProjectModel projectModel, CancellationToken cancellationToken = default) public async Task ReloadProject(SharpIdeProjectModel projectModel, CancellationToken cancellationToken = default)
{ {
Console.WriteLine($"RoslynAnalysis: Reloading Project {projectModel.FilePath}"); using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(ReloadProject)}");
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(ReloadSolution)}"); _logger.LogInformation("RoslynAnalysis: Reloading project {ProjectPath}", projectModel.FilePath);
await _solutionLoadedTcs.Task; await _solutionLoadedTcs.Task;
Guard.Against.Null(_workspace, nameof(_workspace)); Guard.Against.Null(_workspace, nameof(_workspace));
Guard.Against.Null(_msBuildProjectLoader, nameof(_msBuildProjectLoader)); Guard.Against.Null(_msBuildProjectLoader, nameof(_msBuildProjectLoader));
await BuildService.Instance.MsBuildAsync(_sharpIdeSolutionModel!.FilePath, BuildType.Restore, cancellationToken); await BuildService.Instance.MsBuildAsync(_sharpIdeSolutionModel!.FilePath, BuildType.Restore, cancellationToken);
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(MSBuildProjectLoader)}.{nameof(MSBuildProjectLoader.LoadProjectInfoAsync)}"); var __ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(CustomMsBuildProjectLoader)}.{nameof(CustomMsBuildProjectLoader.LoadProjectInfosAsync)}");
var thisProject = _workspace.CurrentSolution.Projects.Single(s => s.FilePath == projectModel.FilePath); var thisProject = _workspace.CurrentSolution.Projects.Single(s => s.FilePath == projectModel.FilePath);
@@ -209,7 +212,7 @@ public class RoslynAnalysis
var loadedProjectInfos = await _msBuildProjectLoader.LoadProjectInfosAsync(projectPathsToReload, null, cancellationToken: cancellationToken); var loadedProjectInfos = await _msBuildProjectLoader.LoadProjectInfosAsync(projectPathsToReload, null, cancellationToken: cancellationToken);
__?.Dispose(); __?.Dispose();
var ___ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.Workspace.asdf"); var ___ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.Workspace.UpdateSolution");
var oldProjectIdFilePathMap = _workspace.CurrentSolution.Projects.ToDictionary(keySelector: static p => (p.FilePath!, p.Name), elementSelector: static p => p.Id); var oldProjectIdFilePathMap = _workspace.CurrentSolution.Projects.ToDictionary(keySelector: static p => (p.FilePath!, p.Name), elementSelector: static p => p.Id);
@@ -257,7 +260,7 @@ public class RoslynAnalysis
_workspace.UpdateReferencesAfterAdd(); _workspace.UpdateReferencesAfterAdd();
___?.Dispose(); ___?.Dispose();
Console.WriteLine("RoslynAnalysis: Project reloaded"); _logger.LogInformation("RoslynAnalysis: Project reloaded");
return; return;
ProjectReference MapProjectReference(ProjectReference oldRef) => new ProjectReference(projectIdMap[oldRef.ProjectId], oldRef.Aliases, oldRef.EmbedInteropTypes); ProjectReference MapProjectReference(ProjectReference oldRef) => new ProjectReference(projectIdMap[oldRef.ProjectId], oldRef.Aliases, oldRef.EmbedInteropTypes);
@@ -271,9 +274,9 @@ public class RoslynAnalysis
public async Task UpdateSolutionDiagnostics(CancellationToken cancellationToken = default) public async Task UpdateSolutionDiagnostics(CancellationToken cancellationToken = default)
{ {
Console.WriteLine("RoslynAnalysis: Updating solution diagnostics");
var timer = Stopwatch.StartNew();
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(UpdateSolutionDiagnostics)}"); using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(UpdateSolutionDiagnostics)}");
_logger.LogInformation("RoslynAnalysis: Updating solution diagnostics");
var timer = Stopwatch.StartNew();
await _solutionLoadedTcs.Task; await _solutionLoadedTcs.Task;
foreach (var project in _sharpIdeSolutionModel!.AllProjects) foreach (var project in _sharpIdeSolutionModel!.AllProjects)
{ {
@@ -283,7 +286,7 @@ public class RoslynAnalysis
project.Diagnostics.AddRange(projectDiagnostics); project.Diagnostics.AddRange(projectDiagnostics);
} }
timer.Stop(); timer.Stop();
Console.WriteLine($"RoslynAnalysis: Solution diagnostics updated in {timer.ElapsedMilliseconds}ms"); _logger.LogInformation("RoslynAnalysis: Solution diagnostics updated in {ElapsedMilliseconds}ms", timer.ElapsedMilliseconds);
} }
public async Task<ImmutableArray<Diagnostic>> GetProjectDiagnostics(SharpIdeProjectModel projectModel, CancellationToken cancellationToken = default) public async Task<ImmutableArray<Diagnostic>> GetProjectDiagnostics(SharpIdeProjectModel projectModel, CancellationToken cancellationToken = default)
@@ -461,7 +464,7 @@ public class RoslynAnalysis
]; ];
var result = sharpIdeRazorSpans.OrderBy(s => s.Span.AbsoluteIndex).ToImmutableArray(); var result = sharpIdeRazorSpans.OrderBy(s => s.Span.AbsoluteIndex).ToImmutableArray();
timer.Stop(); timer.Stop();
Console.WriteLine($"RoslynAnalysis: Razor syntax highlighting for {fileModel.Name} took {timer.ElapsedMilliseconds}ms"); _logger.LogInformation("RoslynAnalysis: Razor syntax highlighting for {FileName} took {ElapsedMilliseconds}ms", fileModel.Name, timer.ElapsedMilliseconds);
return result; return result;
} }
@@ -668,7 +671,7 @@ public class RoslynAnalysis
return (symbol, linePositionSpan); return (symbol, linePositionSpan);
} }
private static async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan)> LookupSymbolInRazor(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default) private async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan)> LookupSymbolInRazor(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default)
{ {
var sharpIdeProjectModel = ((IChildSharpIdeNode) fileModel).GetNearestProjectNode()!; var sharpIdeProjectModel = ((IChildSharpIdeNode) fileModel).GetNearestProjectNode()!;
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == sharpIdeProjectModel!.FilePath); var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == sharpIdeProjectModel!.FilePath);
@@ -691,7 +694,7 @@ public class RoslynAnalysis
return (symbol, linePositionSpan); return (symbol, linePositionSpan);
} }
private static async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan)> LookupSymbolInCs(SharpIdeFile fileModel, LinePosition linePosition) private async Task<(ISymbol? symbol, LinePositionSpan? linePositionSpan)> LookupSymbolInCs(SharpIdeFile fileModel, LinePosition linePosition)
{ {
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath); var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath);
var document = project.Documents.Single(s => s.FilePath == fileModel.Path); var document = project.Documents.Single(s => s.FilePath == fileModel.Path);
@@ -704,18 +707,18 @@ public class RoslynAnalysis
return GetSymbolAtPosition(semanticModel, syntaxRoot!, position); return GetSymbolAtPosition(semanticModel, syntaxRoot!, position);
} }
private static (ISymbol? symbol, LinePositionSpan? linePositionSpan) GetSymbolAtPosition(SemanticModel semanticModel, SyntaxNode root, int position) private (ISymbol? symbol, LinePositionSpan? linePositionSpan) GetSymbolAtPosition(SemanticModel semanticModel, SyntaxNode root, int position)
{ {
var node = root.FindToken(position).Parent!; var node = root.FindToken(position).Parent!;
var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetDeclaredSymbol(node); var symbol = semanticModel.GetSymbolInfo(node).Symbol ?? semanticModel.GetDeclaredSymbol(node);
if (symbol is null) if (symbol is null)
{ {
Console.WriteLine("No symbol found at position"); _logger.LogInformation("No symbol found at position {Position}", position);
return (null, null); return (null, null);
} }
var linePositionSpan = root.SyntaxTree.GetLineSpan(node.Span).Span; var linePositionSpan = root.SyntaxTree.GetLineSpan(node.Span).Span;
Console.WriteLine($"Symbol found: {symbol.Name} ({symbol.Kind}) - {symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}"); _logger.LogInformation("Symbol found: {SymbolName} ({SymbolKind}) - {SymbolDisplayString}", symbol.Name, symbol.Kind, symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
return (symbol, linePositionSpan); return (symbol, linePositionSpan);
} }

View File

@@ -73,6 +73,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
private CancellationTokenSource _solutionAlteredCts = new(); private CancellationTokenSource _solutionAlteredCts = new();
private async Task OnSolutionAltered() private async Task OnSolutionAltered()
{ {
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(SharpIdeCodeEdit)}.{nameof(OnSolutionAltered)}");
if (_currentFile is null) return; if (_currentFile is null) return;
if (_fileDeleted) return; if (_fileDeleted) return;
GD.Print($"[{_currentFile.Name}] Solution altered, updating project diagnostics for file"); GD.Print($"[{_currentFile.Name}] Solution altered, updating project diagnostics for file");
@@ -286,9 +287,9 @@ public partial class SharpIdeCodeEdit : CodeEdit
private void OnTextChanged() private void OnTextChanged()
{ {
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(SharpIdeCodeEdit)}.{nameof(OnTextChanged)}");
_ = Task.GodotRun(async () => _ = Task.GodotRun(async () =>
{ {
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(SharpIdeCodeEdit)}.{nameof(OnTextChanged)}");
_currentFile.IsDirty.Value = true; _currentFile.IsDirty.Value = true;
await _fileChangedService.SharpIdeFileChanged(_currentFile, Text, FileChangeType.IdeUnsavedChange); await _fileChangedService.SharpIdeFileChanged(_currentFile, Text, FileChangeType.IdeUnsavedChange);
__?.Dispose(); __?.Dispose();