diff --git a/src/SharedCompilation/VBCSCompilerReporter.cs b/src/SharedCompilation/VBCSCompilerReporter.cs index db4c6d0..ff3128b 100644 --- a/src/SharedCompilation/VBCSCompilerReporter.cs +++ b/src/SharedCompilation/VBCSCompilerReporter.cs @@ -9,6 +9,8 @@ #endif using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.Emit; using Microsoft.Build.Experimental.FileAccess; using Microsoft.Build.Framework; using Microsoft.CodeAnalysis; @@ -20,8 +22,6 @@ namespace Microsoft.MSBuildCache.SharedCompilation; /// internal static class VBCSCompilerReporter { - private delegate void ReportFileAccessFn(FileAccessData fileAccessData); - /// /// Resolve and report file accesses given the , , /// and of a project. @@ -221,10 +221,27 @@ private static string ComputeOutputFileName(CommandLineArguments args) /// private sealed class AccessRegistrar { + private delegate void ReportFileAccessFn(FileAccessData fileAccessData); + + private delegate FileAccessData CreateFileAccessFn( + ReportedFileOperation operation, + RequestedAccess requestedAccess, + uint processId, + uint id, + uint correlationId, + uint error, + DesiredAccess desiredAccess, + FlagsAndAttributes flagsAndAttributes, + string path, + string processArgs, + bool isAnAugmentedFileAccess); + private readonly string _basePath; private readonly ReportFileAccessFn _reportFileAccess; + private readonly CreateFileAccessFn _createFileAccess; + private static readonly uint ProcessId = (uint) #if NET472 Process.GetCurrentProcess().Id; @@ -240,6 +257,57 @@ public AccessRegistrar(string basePath, EngineServices engineServices) // Use reflection to get the ReportFileAccess method since it's not exposed. // TODO: Once there is a proper API for this, use it. _reportFileAccess = (ReportFileAccessFn)Delegate.CreateDelegate(typeof(ReportFileAccessFn), engineServices, "ReportFileAccess"); + + ConstructorInfo fileAccessDataCtor = typeof(FileAccessData).GetConstructors()[0]; + ParameterInfo[] fileAccessDataCtorParams = fileAccessDataCtor.GetParameters(); + if (fileAccessDataCtorParams.Length == 9) + { + // This is the one we compiled against so just use it. + _createFileAccess = ( + ReportedFileOperation operation, + RequestedAccess requestedAccess, + uint processId, + uint id, + uint correlationId, + uint error, + DesiredAccess desiredAccess, + FlagsAndAttributes flagsAndAttributes, + string path, + string processArgs, + bool isAnAugmentedFileAccess) + => new FileAccessData(operation, requestedAccess, processId, error, desiredAccess, flagsAndAttributes, path, processArgs, isAnAugmentedFileAccess); + } + else if (fileAccessDataCtorParams.Length == 11) + { + // Adjust to a breaking change made in MSBuild to the FileAccessData ctor. See: https://github.com/dotnet/msbuild/pull/9615 + // Create a dynamic method which basically just invokes the ctor with all the params from the CreateFileAccessFn delegate. + DynamicMethod dynamicMethod = new( + name: string.Empty, + returnType: typeof(FileAccessData), + parameterTypes: fileAccessDataCtorParams.Select(param => param.ParameterType).ToArray(), + owner: typeof(FileAccessData)); + + ILGenerator il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Ldarg_3); + il.Emit(OpCodes.Ldarg_S, 4); + il.Emit(OpCodes.Ldarg_S, 5); + il.Emit(OpCodes.Ldarg_S, 6); + il.Emit(OpCodes.Ldarg_S, 7); + il.Emit(OpCodes.Ldarg_S, 8); + il.Emit(OpCodes.Ldarg_S, 9); + il.Emit(OpCodes.Ldarg_S, 10); + il.Emit(OpCodes.Newobj, fileAccessDataCtor); + il.Emit(OpCodes.Ret); + + _createFileAccess = (CreateFileAccessFn)dynamicMethod.CreateDelegate(typeof(CreateFileAccessFn)); + } + else + { + throw new MissingMethodException("Could not find supported constructor for FileAccessData"); + } } public void RegisterOutput(string? filePath) => RegisterAccess(filePath, RequestedAccess.Write, DesiredAccess.GENERIC_WRITE); @@ -270,11 +338,13 @@ private void RegisterAccess(string? filePath, RequestedAccess requestedAccess, D return; } - FileAccessData fileAccessData = new( + FileAccessData fileAccessData = _createFileAccess( ReportedFileOperation.CreateFile, requestedAccess, ProcessId, - 0, + id: 0, + correlationId: 0, + error: 0, desiredAccess, FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, MakeAbsoluteIfNeeded(filePath!), diff --git a/tests/TestProject/Directory.Build.props b/tests/TestProject/Directory.Build.props index 3cc1fad..080b44a 100644 --- a/tests/TestProject/Directory.Build.props +++ b/tests/TestProject/Directory.Build.props @@ -1,3 +1,6 @@ + + false +