using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using System.Collections.Immutable; using System.IO; namespace Sandbox; /// /// Holds state for incremental compilation. Ask Matt or James to add comments, I don't know. /// class IncrementalCompileState { public ImmutableArray OldSyntaxTrees; public ImmutableArray SyntaxTrees; public ImmutableArray PreHotloadSyntaxTrees; public CSharpCompilation Compilation; public bool HasState => Compilation is not null; internal void Reset() { Compilation = null; OldSyntaxTrees = default; SyntaxTrees = default; PreHotloadSyntaxTrees = default; } internal void Update( ImmutableArray syntaxTrees, ImmutableArray beforeIlHotloadProcessingTrees, CSharpCompilation compiler ) { OldSyntaxTrees = SyntaxTrees; SyntaxTrees = syntaxTrees; PreHotloadSyntaxTrees = beforeIlHotloadProcessingTrees; Compilation = compiler; } public Dictionary GetChangeSummary( IEnumerable fileLocations = default ) { if ( OldSyntaxTrees.IsDefaultOrEmpty || SyntaxTrees.IsDefaultOrEmpty ) { return new Dictionary(); } var filePaths = OldSyntaxTrees.Select( x => x.FilePath ) .Union( SyntaxTrees.Select( x => x.FilePath ) ) .OrderBy( x => x ) .ToArray(); var result = new Dictionary(); using var writer = new StringWriter(); foreach ( var filePath in filePaths ) { var localPath = fileLocations?.Select( x => { try { return x.GetRelativePath( filePath ); } catch { return null; } } ).FirstOrDefault( x => x != null ) ?? Path.GetFileName( filePath ); var oldTree = OldSyntaxTrees.FirstOrDefault( x => x.FilePath.Equals( filePath, StringComparison.OrdinalIgnoreCase ) ); var newTree = SyntaxTrees.FirstOrDefault( x => x.FilePath.Equals( filePath, StringComparison.OrdinalIgnoreCase ) ); if ( oldTree == null && newTree != null ) { writer.WriteLine( $"{localPath}: Added" ); continue; } if ( oldTree != null && newTree == null ) { writer.WriteLine( $"{localPath}: Removed" ); continue; } var changes = Generator.ILHotloadProcessor.GetChanges( oldTree, newTree ); if ( string.IsNullOrEmpty( changes ) ) { continue; } writer.WriteLine( $"{localPath}: Modified" ); writer.WriteLine( $" {changes.Replace( "\n", "\n " )}" ); } result["Details"] = writer.ToString(); return result; } }