|
|
@@ -469,88 +469,9 @@ namespace Avalonia.Build.Tasks
|
|
|
|
|
|
foreach (var (populateMethod, resourceFilePath) in populateMethodsToTransform)
|
|
|
{
|
|
|
- foreach (var instruction in populateMethod.Body.Instructions.ToArray())
|
|
|
+ if (!TransformXamlIncludes(engine, typeSystem, populateMethod, resourceFilePath, createRootServiceProviderMethod))
|
|
|
{
|
|
|
- const string resolveStyleIncludeName = "ResolveStyleInclude";
|
|
|
- const string resolveResourceInclude = "ResolveResourceInclude";
|
|
|
- if (instruction.OpCode == OpCodes.Call
|
|
|
- && instruction.Operand is MethodReference
|
|
|
- {
|
|
|
- Name: resolveStyleIncludeName or resolveResourceInclude,
|
|
|
- DeclaringType: { Name: "XamlIlRuntimeHelpers" }
|
|
|
- })
|
|
|
- {
|
|
|
- int lineNumber = 0, linePosition = 0;
|
|
|
- bool instructionsModified = false;
|
|
|
- try
|
|
|
- {
|
|
|
- var assetSource = (string)instruction.Previous.Previous.Previous.Operand;
|
|
|
- lineNumber = Convert.ToInt32(instruction.Previous.Previous.Operand);
|
|
|
- linePosition = Convert.ToInt32(instruction.Previous.Operand);
|
|
|
-
|
|
|
- var index = populateMethod.Body.Instructions.IndexOf(instruction);
|
|
|
-
|
|
|
- assetSource = assetSource.Replace("avares://", "");
|
|
|
-
|
|
|
- var assemblyNameSeparator = assetSource.IndexOf('/');
|
|
|
- var fileNameSeparator = assetSource.LastIndexOf('/');
|
|
|
- if (assemblyNameSeparator < 0 || fileNameSeparator < 0)
|
|
|
- {
|
|
|
- throw new InvalidProgramException(
|
|
|
- $"Invalid asset source \"{assetSource}\". It must contain assembly name and relative path.");
|
|
|
- }
|
|
|
-
|
|
|
- var assetAssemblyName = assetSource.Substring(0, assemblyNameSeparator);
|
|
|
- var assetAssembly = typeSystem.FindAssembly(assetAssemblyName)
|
|
|
- ?? throw new InvalidProgramException($"Unable to resolve assembly \"{assetAssemblyName}\"");
|
|
|
-
|
|
|
- var fileName = Path.GetFileNameWithoutExtension(assetSource.Replace('/', '.'));
|
|
|
- if (assetAssembly.FindType(fileName) is { } type
|
|
|
- && type.FindConstructor() is { } ctor)
|
|
|
- {
|
|
|
- var ctorMethod =
|
|
|
- asm.MainModule.ImportReference(typeSystem.GetMethodReference(ctor));
|
|
|
- instructionsModified = true;
|
|
|
- populateMethod.Body.Instructions[index - 3] = Instruction.Create(OpCodes.Nop);
|
|
|
- populateMethod.Body.Instructions[index - 2] = Instruction.Create(OpCodes.Nop);
|
|
|
- populateMethod.Body.Instructions[index - 1] = Instruction.Create(OpCodes.Nop);
|
|
|
- populateMethod.Body.Instructions[index] = Instruction.Create(OpCodes.Newobj, ctorMethod);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- var resources = assetAssembly.FindType("CompiledAvaloniaXaml.!AvaloniaResources")
|
|
|
- ?? throw new InvalidOperationException($"Unable to resolve \"!AvaloniaResources\" type on \"{assetAssemblyName}\" assembly");
|
|
|
-
|
|
|
- var relativeName = "Build:" + assetSource.Substring(assemblyNameSeparator);
|
|
|
- var buildMethod = resources.FindMethod(m => m.Name == relativeName)
|
|
|
- ?? throw new InvalidOperationException($"Unable to resolve build method \"{relativeName}\" resource on the \"{assetAssemblyName}\" assembly");
|
|
|
-
|
|
|
- var methodReference = asm.MainModule.ImportReference(typeSystem.GetMethodReference(buildMethod));
|
|
|
- instructionsModified = true;
|
|
|
- populateMethod.Body.Instructions[index - 3] = Instruction.Create(OpCodes.Nop);
|
|
|
- populateMethod.Body.Instructions[index - 2] = Instruction.Create(OpCodes.Nop);
|
|
|
- populateMethod.Body.Instructions[index - 1] = Instruction.Create(OpCodes.Call, createRootServiceProviderMethod);
|
|
|
- populateMethod.Body.Instructions[index] = Instruction.Create(OpCodes.Call, methodReference);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- if (instructionsModified)
|
|
|
- {
|
|
|
- engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", resourceFilePath,
|
|
|
- lineNumber, linePosition, lineNumber, linePosition,
|
|
|
- e.Message, "", "Avalonia"));
|
|
|
- return false;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- engine.LogWarningEvent(new BuildWarningEventArgs("Avalonia", "XAMLIL",
|
|
|
- resourceFilePath,
|
|
|
- lineNumber, linePosition, lineNumber, linePosition,
|
|
|
- e.Message, "", "Avalonia"));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -630,5 +551,116 @@ namespace Avalonia.Build.Tasks
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+ private static bool TransformXamlIncludes(
|
|
|
+ IBuildEngine engine, CecilTypeSystem typeSystem,
|
|
|
+ MethodDefinition populateMethod, string resourceFilePath,
|
|
|
+ MethodReference createRootServiceProviderMethod)
|
|
|
+ {
|
|
|
+ var asm = typeSystem.TargetAssemblyDefinition;
|
|
|
+ foreach (var instruction in populateMethod.Body.Instructions.ToArray())
|
|
|
+ {
|
|
|
+ const string resolveStyleIncludeName = "ResolveStyleInclude";
|
|
|
+ const string resolveResourceInclude = "ResolveResourceInclude";
|
|
|
+ if (instruction.OpCode == OpCodes.Call
|
|
|
+ && instruction.Operand is MethodReference
|
|
|
+ {
|
|
|
+ Name: resolveStyleIncludeName or resolveResourceInclude,
|
|
|
+ DeclaringType: { Name: "XamlIlRuntimeHelpers" }
|
|
|
+ })
|
|
|
+ {
|
|
|
+ int lineNumber = 0, linePosition = 0;
|
|
|
+ bool instructionsModified = false;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var assetSource = (string)instruction.Previous.Previous.Previous.Operand;
|
|
|
+ lineNumber = GetConstValue(instruction.Previous.Previous);
|
|
|
+ linePosition = GetConstValue(instruction.Previous);
|
|
|
+
|
|
|
+ var index = populateMethod.Body.Instructions.IndexOf(instruction);
|
|
|
+
|
|
|
+ assetSource = assetSource.Replace("avares://", "");
|
|
|
+
|
|
|
+ var assemblyNameSeparator = assetSource.IndexOf('/');
|
|
|
+ var fileNameSeparator = assetSource.LastIndexOf('/');
|
|
|
+ if (assemblyNameSeparator < 0 || fileNameSeparator < 0)
|
|
|
+ {
|
|
|
+ throw new InvalidProgramException(
|
|
|
+ $"Invalid asset source \"{assetSource}\". It must contain assembly name and relative path.");
|
|
|
+ }
|
|
|
+
|
|
|
+ var assetAssemblyName = assetSource.Substring(0, assemblyNameSeparator);
|
|
|
+ var assetAssembly = typeSystem.FindAssembly(assetAssemblyName)
|
|
|
+ ?? throw new InvalidProgramException(
|
|
|
+ $"Unable to resolve assembly \"{assetAssemblyName}\"");
|
|
|
+
|
|
|
+ var fileName = Path.GetFileNameWithoutExtension(assetSource.Replace('/', '.'));
|
|
|
+ if (assetAssembly.FindType(fileName) is { } type
|
|
|
+ && type.FindConstructor() is { } ctor)
|
|
|
+ {
|
|
|
+ var ctorMethod =
|
|
|
+ asm.MainModule.ImportReference(typeSystem.GetMethodReference(ctor));
|
|
|
+ instructionsModified = true;
|
|
|
+ populateMethod.Body.Instructions[index - 3] = Instruction.Create(OpCodes.Nop);
|
|
|
+ populateMethod.Body.Instructions[index - 2] = Instruction.Create(OpCodes.Nop);
|
|
|
+ populateMethod.Body.Instructions[index - 1] = Instruction.Create(OpCodes.Nop);
|
|
|
+ populateMethod.Body.Instructions[index] = Instruction.Create(OpCodes.Newobj, ctorMethod);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var resources = assetAssembly.FindType("CompiledAvaloniaXaml.!AvaloniaResources")
|
|
|
+ ?? throw new InvalidOperationException(
|
|
|
+ $"Unable to resolve \"!AvaloniaResources\" type on \"{assetAssemblyName}\" assembly");
|
|
|
+
|
|
|
+ var relativeName = "Build:" + assetSource.Substring(assemblyNameSeparator);
|
|
|
+ var buildMethod = resources.FindMethod(m => m.Name == relativeName)
|
|
|
+ ?? throw new InvalidOperationException(
|
|
|
+ $"Unable to resolve build method \"{relativeName}\" resource on the \"{assetAssemblyName}\" assembly");
|
|
|
+
|
|
|
+ var methodReference = asm.MainModule.ImportReference(typeSystem.GetMethodReference(buildMethod));
|
|
|
+ instructionsModified = true;
|
|
|
+ populateMethod.Body.Instructions[index - 3] = Instruction.Create(OpCodes.Nop);
|
|
|
+ populateMethod.Body.Instructions[index - 2] = Instruction.Create(OpCodes.Nop);
|
|
|
+ populateMethod.Body.Instructions[index - 1] =
|
|
|
+ Instruction.Create(OpCodes.Call, createRootServiceProviderMethod);
|
|
|
+ populateMethod.Body.Instructions[index] = Instruction.Create(OpCodes.Call, methodReference);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ if (instructionsModified)
|
|
|
+ {
|
|
|
+ engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", resourceFilePath,
|
|
|
+ lineNumber, linePosition, lineNumber, linePosition,
|
|
|
+ e.Message, "", "Avalonia"));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ engine.LogWarningEvent(new BuildWarningEventArgs("Avalonia", "XAMLIL",
|
|
|
+ resourceFilePath,
|
|
|
+ lineNumber, linePosition, lineNumber, linePosition,
|
|
|
+ e.Message, "", "Avalonia"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static int GetConstValue(Instruction instruction)
|
|
|
+ {
|
|
|
+ if (instruction.OpCode is { Code : >= Code.Ldc_I4_0 and <= Code.Ldc_I4_8 })
|
|
|
+ {
|
|
|
+ return instruction.OpCode.Code - Code.Ldc_I4_0;
|
|
|
+ }
|
|
|
+ if (instruction.Operand is not null)
|
|
|
+ {
|
|
|
+ return Convert.ToInt32(instruction.Operand);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
}
|