summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs')
-rw-r--r--Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs152
1 files changed, 152 insertions, 0 deletions
diff --git a/Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs b/Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs
new file mode 100644
index 00000000..f4b2f52c
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/DebugXamlCTask.cs
@@ -0,0 +1,152 @@
+using System;
+using System.IO;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+
+namespace Xamarin.Forms.Build.Tasks
+{
+ public class DebugXamlCTask : XamlCTask
+ {
+ public override bool Execute()
+ {
+ InMsBuild = true;
+ Verbosity = Int32.MaxValue;
+ LogLine(1, "Preparing debug code for xamlc");
+ LogLine(1, "\nAssembly: {0}", Assembly);
+
+ var resolver = new DefaultAssemblyResolver();
+ if (!string.IsNullOrEmpty(DependencyPaths))
+ {
+ foreach (var dep in DependencyPaths.Split(';'))
+ {
+ LogLine(3, "Adding searchpath {0}", dep);
+ resolver.AddSearchDirectory(dep);
+ }
+ }
+ if (!string.IsNullOrEmpty(ReferencePath))
+ {
+ var paths = ReferencePath.Replace("//", "/").Split(';');
+ foreach (var p in paths)
+ {
+ var searchpath = Path.GetDirectoryName(p);
+ LogLine(3, "Adding searchpath {0}", searchpath);
+ resolver.AddSearchDirectory(searchpath);
+ // LogLine (3, "Referencing {0}", p);
+ // resolver.AddAssembly (p);
+ }
+ }
+ var assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly, new ReaderParameters
+ {
+ //ReadSymbols = DebugSymbols,
+ AssemblyResolver = resolver
+ });
+
+ foreach (var module in assemblyDefinition.Modules)
+ {
+ LogLine(2, " Module: {0}", module.Name);
+ foreach (var resource in module.Resources.OfType<EmbeddedResource>())
+ {
+ Log(2, " Resource: {0}... ", resource.Name);
+ string classname;
+ if (!resource.IsXaml(out classname))
+ {
+ LogLine(2, "skipped.");
+ continue;
+ }
+ TypeDefinition typeDef = module.GetType(classname);
+ if (typeDef == null)
+ {
+ LogLine(2, "no type found... skipped.");
+ continue;
+ }
+ var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
+ if (initComp == null)
+ {
+ LogLine(2, "no InitializeComponent found... skipped.");
+ continue;
+ }
+ if (typeDef.Methods.FirstOrDefault(md => md.Name == "InitCompRuntime") != null)
+ {
+ LogLine(2, "InitCompRuntime already exists... skipped");
+ continue;
+ }
+ LogLine(2, "");
+
+ Log(2, " Duplicating {0}.InitializeComponent () into {0}.InitCompRuntime ... ", typeDef.Name);
+ var initCompRuntime = new MethodDefinition("InitCompRuntime", initComp.Attributes, initComp.ReturnType);
+ initCompRuntime.Body = initComp.Body;
+ typeDef.Methods.Add(initCompRuntime);
+ LogLine(2, "done.");
+
+ // IL_0000: ldarg.0
+ // IL_0001: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ContentPage::'.ctor'()
+ //
+ // IL_0006: nop
+ // IL_0007: ldarg.1
+ // IL_0008: brfalse IL_0018
+ //
+ // IL_000d: ldarg.0
+ // IL_000e: callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitializeComponent()
+ // IL_0013: br IL_001e
+ //
+ // IL_0018: ldarg.0
+ // IL_0019: callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitCompRuntime()
+ // IL_001e: ret
+
+ var altCtor =
+ typeDef.Methods.Where(
+ md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType == module.TypeSystem.Boolean)
+ .FirstOrDefault();
+ if (altCtor != null)
+ Log(2, " Replacing body of {0}.{0} (bool {1}) ... ", typeDef.Name, altCtor.Parameters[0].Name);
+ else
+ {
+ Log(2, " Adding {0}.{0} (bool useCompiledXaml) ... ", typeDef.Name);
+ altCtor = new MethodDefinition(".ctor",
+ MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.RTSpecialName, module.TypeSystem.Void);
+ altCtor.Parameters.Add(new ParameterDefinition("useCompiledXaml", ParameterAttributes.None,
+ module.TypeSystem.Boolean));
+ }
+
+ var body = new MethodBody(altCtor);
+ var il = body.GetILProcessor();
+ var br2 = Instruction.Create(OpCodes.Ldarg_0);
+ var ret = Instruction.Create(OpCodes.Ret);
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Callvirt,
+ module.Import(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false)));
+
+ il.Emit(OpCodes.Nop);
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Brfalse, br2);
+
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Callvirt, initComp);
+ il.Emit(OpCodes.Br, ret);
+
+ il.Append(br2);
+ il.Emit(OpCodes.Callvirt, initCompRuntime);
+ il.Append(ret);
+
+ altCtor.Body = body;
+ if (!typeDef.Methods.Contains(altCtor))
+ typeDef.Methods.Add(altCtor);
+ LogLine(2, "done.");
+ }
+
+ LogLine(2, "");
+ }
+ Log(1, "Writing the assembly... ");
+ assemblyDefinition.Write(Assembly, new WriterParameters
+ {
+ WriteSymbols = DebugSymbols
+ });
+ LogLine(1, "done.");
+
+ return true;
+ }
+ }
+} \ No newline at end of file