Files
sbox-public/engine/Sandbox.Compiling/Compiler/IncrementalCompileState.cs
James King 6e71079a04 Fix ILHotload falling apart when doing incremental compiles (#5376)
* Simplify by removing BeforeILHotloadProcessingTrees
* Strip ILHotload attribs when comparing syntax trees
* MethodBodyChanged attribute is versioned to support incremental compiles
* Possible fix for Facepunch/sbox-public#11275
2026-07-21 15:18:18 +02:00

100 lines
2.5 KiB
C#

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Immutable;
using System.IO;
namespace Sandbox;
/// <summary>
/// Holds state for incremental compilation. Ask Matt or James to add comments, I don't know.
/// </summary>
class IncrementalCompileState
{
public ImmutableArray<SyntaxTree> OldSyntaxTrees;
public ImmutableArray<SyntaxTree> SyntaxTrees;
public ImmutableDictionary<string, ulong> FileHashMap { get; private set; }
public CSharpCompilation Compilation;
public bool HasState => Compilation is not null;
internal void Reset()
{
Compilation = null;
OldSyntaxTrees = default;
SyntaxTrees = default;
FileHashMap = [];
}
internal void Update( CodeArchive archive, IEnumerable<SyntaxTree> syntaxTrees, CSharpCompilation compiler )
{
OldSyntaxTrees = SyntaxTrees;
SyntaxTrees = syntaxTrees.ToImmutableArray();
Compilation = compiler;
FileHashMap = archive.FileHashMap.ToImmutableDictionary();
}
public Dictionary<string, object> GetChangeSummary( IReadOnlyList<BaseFileSystem> fileLocations = null )
{
if ( OldSyntaxTrees.IsDefaultOrEmpty || SyntaxTrees.IsDefaultOrEmpty )
{
return new Dictionary<string, object>();
}
var filePaths = OldSyntaxTrees.Select( x => x.FilePath )
.Union( SyntaxTrees.Select( x => x.FilePath ) )
.OrderBy( x => x )
.ToArray();
var result = new Dictionary<string, object>();
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;
}
}