2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
23 using System.ComponentModel;
27 using Tizen.NUI.Binding;
28 using Tizen.NUI.EXaml;
29 using Tizen.NUI.EXaml.Build.Tasks;
30 using static Microsoft.Build.Framework.MessageImportance;
31 using static Mono.Cecil.Cil.OpCodes;
33 namespace Tizen.NUI.Xaml.Build.Tasks
35 [EditorBrowsable(EditorBrowsableState.Never)]
36 public class XamlCTask : XamlTask
38 bool hasCompiledXamlResources;
39 public bool KeepXamlResources { get; set; }
40 public bool OptimizeIL { get; set; }
42 [Obsolete("OutputGeneratedILAsCode is obsolete as of version 2.3.4. This option is no longer available.")]
43 public bool OutputGeneratedILAsCode { get; set; }
45 public bool CompileByDefault { get; set; }
46 public bool ForceCompile { get; set; }
48 public bool UseInjection { get; set; }
50 public int XamlOptimization { get; set; } = 2;
52 public IAssemblyResolver DefaultAssemblyResolver { get; set; }
54 public string Type { get; set; }
55 public MethodDefinition InitCompForType { get; private set; }
56 internal bool ReadOnly { get; set; }
58 public string outputRootPath { get; set; }
60 public bool PrintReferenceAssemblies { get; set; }
62 private void PrintParam(string logFileName, string log)
64 FileStream stream = null;
65 if (false == File.Exists(logFileName))
67 stream = File.Create(logFileName);
71 stream = File.Open(logFileName, FileMode.Append);
74 byte[] buffer = System.Text.Encoding.Default.GetBytes(log + "\n");
75 stream.Write(buffer, 0, buffer.Length);
79 private void PrintParam(string logFileName)
81 FileStream stream = File.Create(logFileName);
83 string str = "Assembly is " + Assembly + "\n";
84 str += "DependencyPaths is " + DependencyPaths + "\n";
85 str += "ReferencePath is " + ReferencePath + "\n";
86 str += "DebugType is " + DebugType + "\n";
87 str += "Type is " + Type + "\n";
88 str += "ReadOnly is " + ReadOnly + "\n";
90 byte[] buffer = Encoding.Default.GetBytes(str);
91 stream.Write(buffer, 0, buffer.Length);
96 static private TypeDefinition baseTypeDefiniation = null;
97 static public TypeDefinition BaseTypeDefiniation
101 return baseTypeDefiniation;
105 private void GatherAssemblyInfo(string p)
109 ModuleDefinition module = ModuleDefinition.ReadModule(p);
111 if (null == baseTypeDefiniation)
113 baseTypeDefiniation = module.GetType("Tizen.NUI.Binding.BindableObject");
116 foreach (var attr in module.Assembly.CustomAttributes)
118 if (attr.AttributeType.FullName == "Tizen.NUI.XmlnsDefinitionAttribute")
120 string xmlNamespace = attr.ConstructorArguments[0].Value as string;
121 string clrNamespace = attr.ConstructorArguments[1].Value as string;
124 string assemblyName = module.Assembly.FullName;
126 if (true == attr.HasProperties)
128 foreach (var property in attr.Properties)
130 if ("Level" == property.Name)
132 level = int.Parse(property.Argument.Value.ToString());
134 if ("AssemblyName" == property.Name)
136 assemblyName = property.Argument.Value as string;
141 XmlnsDefinitionAttribute attribute = new XmlnsDefinitionAttribute(xmlNamespace, clrNamespace, level);
142 attribute.AssemblyName = assemblyName;
143 s_xmlnsDefinitions.Add(attribute);
155 public override bool Execute(out IList<Exception> thrownExceptions)
157 if (true == PrintReferenceAssemblies)
159 PrintParam(@"XamlC_Log.txt", "ReferencePath is " + ReferencePath);
162 LoggingHelper.LogWarning("Assembly is " + Assembly);
164 thrownExceptions = null;
166 LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Compiling Xaml, assembly: {Assembly}");
167 var skipassembly = !CompileByDefault;
170 if (!File.Exists(Assembly))
172 throw new Exception(String.Format("Assembly file {0} is not exist", Assembly));
173 //LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}Assembly file not found. Skipping XamlC.");
177 s_xmlnsDefinitions.Clear();
179 var resolver = DefaultAssemblyResolver ?? new XamlCAssemblyResolver();
180 if (resolver is XamlCAssemblyResolver xamlCResolver)
182 if (!string.IsNullOrEmpty(DependencyPaths))
184 foreach (var dep in DependencyPaths.Split(';'))
186 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {dep}");
187 xamlCResolver.AddSearchDirectory(dep);
191 if (!string.IsNullOrEmpty(ReferencePath))
193 var paths = ReferencePath.Replace("//", "/").Split(';');
195 foreach (var p in paths)
197 GatherAssemblyInfo(p);
199 var searchpath = System.IO.Path.GetDirectoryName(p);
200 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
201 xamlCResolver.AddSearchDirectory(searchpath);
206 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Ignoring dependency and reference paths due to an unsupported resolver");
208 var readerParameters = new ReaderParameters
210 AssemblyResolver = resolver,
211 ReadWrite = !ReadOnly,
212 ReadSymbols = NeedDebug,
215 using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(System.IO.Path.GetFullPath(Assembly), readerParameters))
217 if (null != XamlFilePath)
219 return GenerateEXaml(XamlFilePath, assemblyDefinition.MainModule, out thrownExceptions);
222 CustomAttribute xamlcAttr;
223 if (assemblyDefinition.HasCustomAttributes &&
225 assemblyDefinition.CustomAttributes.FirstOrDefault(
226 ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
228 var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
229 if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
231 if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
232 skipassembly = false;
235 foreach (var module in assemblyDefinition.Modules)
237 var skipmodule = skipassembly;
238 if (module.HasCustomAttributes &&
240 module.CustomAttributes.FirstOrDefault(
241 ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
243 var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
244 if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
246 if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
250 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
251 var resourcesToPrune = new List<EmbeddedResource>();
252 foreach (var resource in module.Resources.OfType<EmbeddedResource>())
254 LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
256 if (!resource.IsXaml(module, out classname))
258 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
261 TypeDefinition typeDef = module.GetType(classname);
264 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
267 var skiptype = skipmodule;
268 if (typeDef.HasCustomAttributes &&
270 typeDef.CustomAttributes.FirstOrDefault(
271 ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
273 var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
274 if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
276 if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
281 skiptype = !(Type == classname);
283 if (skiptype && !ForceCompile)
285 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}has XamlCompilationAttribute set to Skip and not Compile... skipped.");
289 bool currentRetOfType = false;
290 IList<Exception> currentExceptionsOfType = null;
292 if(UseInjection) XamlOptimization = 1;
293 LoggingHelper.LogWarning($"XamlOptimization is {XamlOptimization}.");
294 if (0 == XamlOptimization)
296 currentRetOfType = true;
298 else if (1 == XamlOptimization)
300 currentRetOfType = DoInjection(typeDef, resource, out currentExceptionsOfType);
304 currentRetOfType = GenerateEXaml(typeDef, resource, out currentExceptionsOfType);
306 if (currentRetOfType)
308 InjectionMethodGetEXamlPath(typeDef);
312 if (null != currentExceptionsOfType)
314 if (null == thrownExceptions)
316 thrownExceptions = new List<Exception>();
319 foreach (var e in currentExceptionsOfType)
321 thrownExceptions.Add(e);
325 if (false == currentRetOfType)
331 resourcesToPrune.Add(resource);
334 if (hasCompiledXamlResources)
336 LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Changing the module MVID");
337 module.Mvid = Guid.NewGuid();
338 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}done.");
340 if (!KeepXamlResources)
342 if (resourcesToPrune.Any())
343 LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Removing compiled xaml resources");
344 foreach (var resource in resourcesToPrune)
346 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Removing {resource.Name}");
347 module.Resources.Remove(resource);
348 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
353 if (!hasCompiledXamlResources)
355 LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}No compiled resources. Skipping writing assembly.");
362 LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}Writing the assembly");
365 assemblyDefinition.Write(new WriterParameters
367 WriteSymbols = NeedDebug,
369 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}done.");
373 LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}failed.");
374 LoggingHelper.LogErrorFromException(e);
375 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
376 LoggingHelper.LogMessage(Low, e.StackTrace);
383 bool DoInjection(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
385 thrownExceptions = null;
387 var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
388 if (initComp == null)
390 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
394 CustomAttribute xamlFilePathAttr;
395 var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
396 (string)xamlFilePathAttr.ConstructorArguments[0].Value :
399 var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
400 if (initCompRuntime != null)
401 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
404 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
405 initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
406 initCompRuntime.Body.InitLocals = true;
407 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
408 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
409 initCompRuntime.Body = new MethodBody(initCompRuntime);
410 var iCRIl = initCompRuntime.Body.GetILProcessor();
411 foreach (var instr in initComp.Body.Instructions)
413 initComp.Body.Instructions.Clear();
414 initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
415 initComp.Body.InitLocals = true;
417 typeDef.Methods.Add(initCompRuntime);
418 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
421 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
422 var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
423 if (rootnode == null)
425 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
428 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
430 hasCompiledXamlResources = true;
432 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
434 if (!TryCoreCompile(initComp, rootnode, out e))
436 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
437 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
438 if (e is XamlParseException xpe)
439 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
440 else if (e is XmlException xe)
441 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
443 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
445 if (null != e.StackTrace)
447 LoggingHelper.LogMessage(Low, e.StackTrace);
453 InitCompForType = initComp;
455 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
459 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
460 initComp.Body.Optimize();
461 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
464 #pragma warning disable 0618
465 if (OutputGeneratedILAsCode)
466 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated");
467 #pragma warning restore 0618
472 bool GenerateEXaml(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
474 thrownExceptions = null;
476 ModuleDefinition module = typeDef.Module;
478 CustomAttribute xamlFilePathAttr;
479 var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
480 (string)xamlFilePathAttr.ConstructorArguments[0].Value :
483 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
484 var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
485 if (rootnode == null)
487 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
490 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
492 hasCompiledXamlResources = true;
494 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
497 var visitorContext = new EXamlContext(typeDef, typeDef.Module);
499 if (!TryCoreCompile(rootnode, visitorContext, out e))
501 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
502 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
503 if (e is XamlParseException xpe)
504 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
505 else if (e is XmlException xe)
506 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
508 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
510 if (null != e.StackTrace)
512 LoggingHelper.LogError(e.StackTrace);
519 var examlDir = outputRootPath + @"res/examl/";
520 if (Directory.Exists(examlDir))
522 Directory.CreateDirectory(examlDir);
525 var examlFilePath = examlDir + typeDef.FullName + ".examl";
527 EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
533 bool GenerateEXaml(string xamlFilePath, ModuleDefinition module, out IList<Exception> thrownExceptions)
535 thrownExceptions = null;
537 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
538 Stream xamlStream = File.Open(xamlFilePath, FileMode.Open);
541 if (!CecilExtensions.IsXaml(xamlStream, module, out className))
543 thrownExceptions.Add(new Exception($"{xamlFilePath} is not xaml format file"));
546 xamlStream.Seek(0, SeekOrigin.Begin);
547 var typeDef = module.GetTypeDefinition(className);
551 throw new Exception($"Can't find type \"{className}\" in assembly \"{module.Assembly.FullName}\"");
554 var rootnode = ParseXaml(xamlStream, typeDef);
558 if (rootnode == null)
560 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
563 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
565 hasCompiledXamlResources = true;
567 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
570 var visitorContext = new EXamlContext(typeDef, module);
572 if (!TryCoreCompile(rootnode, visitorContext, out e))
574 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
575 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
576 if (e is XamlParseException xpe)
577 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
578 else if (e is XmlException xe)
579 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
581 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
583 if (null != e.StackTrace)
585 LoggingHelper.LogMessage(Low, e.StackTrace);
592 var examlDir = outputRootPath + @"res/examl/";
593 if (Directory.Exists(examlDir))
595 Directory.CreateDirectory(examlDir);
598 var examlFilePath = examlDir + typeDef.FullName + ".examl";
600 EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
607 bool InjectionMethodGetEXamlPath(TypeDefinition typeDef)
609 var getEXamlPathComp = typeDef.Methods.FirstOrDefault(md => md.Name == "GetEXamlPath");
610 if (getEXamlPathComp == null)
612 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no GetEXamlPath found... skipped.");
616 var examlRelativePath = @"examl/" + typeDef.FullName + ".examl";
617 getEXamlPathComp.Body.Instructions.Clear();
618 getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ldstr, examlRelativePath);
619 getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ret);
624 bool TryCoreCompile(MethodDefinition initComp, ILRootNode rootnode, out Exception exception)
628 var body = new MethodBody(initComp);
629 var module = body.Method.Module;
630 var type = initComp.DeclaringType;
632 MethodDefinition constructorOfRemoveEventsType;
633 TypeDefinition typeOfRemoveEvents = CreateTypeForRemoveEvents(type, out constructorOfRemoveEventsType);
635 var field = type.GetOrCreateField("___Info_Of_RemoveEvent___", FieldAttributes.Private, typeOfRemoveEvents);
637 body.InitLocals = true;
638 var il = body.GetILProcessor();
639 il.Emit(OpCodes.Ldarg_0);
640 il.Emit(OpCodes.Newobj, constructorOfRemoveEventsType);
641 il.Emit(OpCodes.Stfld, field);
643 var resourcePath = GetPathForType(module, type);
647 List<Instruction> insOfAddEvent = new List<Instruction>();
649 var visitorContext = new ILContext(il, body, insOfAddEvent, module);
651 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
652 rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
653 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
654 rootnode.Accept(new CreateObjectVisitor(visitorContext), null);
656 Set(visitorContext, visitorContext.Variables[rootnode], "IsCreateByXaml", new ValueNode("true", rootnode.NamespaceResolver), null);
658 rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null);
659 rootnode.Accept(new SetFieldVisitor(visitorContext), null);
660 rootnode.Accept(new SetResourcesVisitor(visitorContext), null);
661 rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null);
663 AddInsOfRemoveEvent(il, visitorContext.InsOfAddEvent, typeOfRemoveEvents);
666 initComp.Body = body;
672 XamlParseException xamlParseException = e as XamlParseException;
673 if (null != xamlParseException)
675 XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
687 private void AddInsOfRemoveEvent(ILProcessor ilOfInit, List<Instruction> instructions, TypeDefinition typeDef)
689 MethodDefinition methodCall = typeDef.GetOrCreateMethod("Call", MethodAttributes.Public, typeof(void));
690 methodCall.Body.Instructions.Clear();
692 var fieldOfRemoveEvent = typeDef.DeclaringType.Fields.FirstOrDefault(a => a.Name == "___Info_Of_RemoveEvent___");
694 var il = methodCall.Body.GetILProcessor();
696 foreach (var ins in instructions)
698 if (ins.OpCode == OpCodes.Ldloc
700 ins.Operand is VariableDefinition variable)
702 var fieldName = "field" + variable.Index;
703 var field = typeDef.GetOrCreateField(fieldName, FieldAttributes.Public, variable.VariableType);
705 ilOfInit.Emit(OpCodes.Ldarg_0);
706 ilOfInit.Emit(OpCodes.Ldfld, fieldOfRemoveEvent);
707 ilOfInit.Emit(OpCodes.Ldloc, variable);
708 ilOfInit.Emit(OpCodes.Stfld, field);
710 methodCall.Body.Instructions.Add(Instruction.Create(Ldarg_0));
711 methodCall.Body.Instructions.Add(Instruction.Create(Ldfld, field));
715 bool isReplaced = false;
716 if (ins.OpCode == OpCodes.Callvirt && ins.Operand is MethodReference method)
718 if (method.Name.StartsWith("add_"))
720 var eventName = method.Name.Substring("add_".Length);
722 var typeOfEvent = method.DeclaringType.GetEvent(a => a.Name == eventName, out _);
724 if (typeOfEvent is EventDefinition)
726 var methodOfRemoveEvent = typeDef.Module.ImportReference(method.DeclaringType.ResolveCached()?.Methods.FirstOrDefault(a => a.Name == "remove_" + eventName));
727 if (null != methodOfRemoveEvent)
729 var newIns = Instruction.Create(ins.OpCode, methodOfRemoveEvent);
730 methodCall.Body.Instructions.Add(newIns);
738 if (false == isReplaced)
740 methodCall.Body.Instructions.Add(ins);
745 methodCall.Body.Instructions.Add(Instruction.Create(Ret));
747 var removeEventMethod = typeDef.DeclaringType.Methods.FirstOrDefault(a => a.Name == "RemoveEventsInXaml");
748 if (null != removeEventMethod)
750 removeEventMethod.Body.Instructions.Clear();
751 var ilRemoveEvent = removeEventMethod.Body.GetILProcessor();
753 ilRemoveEvent.Emit(Ldarg_0);
754 ilRemoveEvent.Emit(Ldfld, fieldOfRemoveEvent);
755 ilRemoveEvent.Emit(Dup);
757 var insOfCall = Instruction.Create(Call, methodCall.Resolve());
759 ilRemoveEvent.Emit(Brtrue_S, insOfCall);
760 ilRemoveEvent.Emit(Pop);
762 var endIns = Instruction.Create(Ret);
764 ilRemoveEvent.Emit(Br_S, endIns);
765 ilRemoveEvent.Append(insOfCall);
767 ilRemoveEvent.Append(endIns);
771 TypeDefinition CreateTypeForRemoveEvents(TypeDefinition typeDef, out MethodDefinition constructor)
773 var module = typeDef.Module;
775 var name = "___Type___For___RemoveEvent___";
776 var nestType = typeDef.NestedTypes.FirstOrDefault(a => a.Name == name);
778 if (null == nestType)
780 nestType = new TypeDefinition(typeDef.Namespace, name, TypeAttributes.NestedPrivate | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed | TypeAttributes.AnsiClass);
781 nestType.BaseType = module.ImportReference(typeof(object));
782 typeDef.NestedTypes.Add(nestType);
784 constructor = nestType.AddDefaultConstructor();
788 constructor = nestType.Methods.FirstOrDefault(a => a.IsConstructor);
794 bool TryCoreCompile(ILRootNode rootnode, EXamlContext visitorContext, out Exception exception)
798 XmlTypeExtensions.s_xmlnsDefinitions?.Clear();
799 XmlTypeExtensions.s_xmlnsDefinitions = null;
801 visitorContext.Values[rootnode] = new EXamlCreateObject(visitorContext, null, rootnode.TypeReference);
803 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
804 rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
805 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
806 rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
807 rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
808 rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
809 rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
810 rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
817 XamlParseException xamlParseException = e as XamlParseException;
818 if (null != xamlParseException)
820 XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
832 private void Set(ILContext Context, VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo)
834 var module = Context.Body.Method.Module;
835 TypeReference declaringTypeReference;
836 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
837 if (null == property)
841 var propertySetter = property.SetMethod;
843 module.ImportReference(parent.VariableType.ResolveCached());
844 var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
845 propertySetterRef.ImportTypes(module);
846 var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
847 var valueNode = node as ValueNode;
848 var elementNode = node as IElementNode;
850 if (parent.VariableType.IsValueType)
851 Context.IL.Emit(OpCodes.Ldloca, parent);
853 Context.IL.Emit(OpCodes.Ldloc, parent);
855 if (valueNode != null)
857 foreach (var instruction in valueNode.PushConvertedValue(Context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(Context, propertyRef: property), false, true))
859 Context.IL.Append(instruction);
862 if (parent.VariableType.IsValueType)
863 Context.IL.Emit(OpCodes.Call, propertySetterRef);
865 Context.IL.Emit(OpCodes.Callvirt, propertySetterRef);
869 internal static string GetPathForType(ModuleDefinition module, TypeReference type)
871 foreach (var ca in type.Module.GetCustomAttributes())
873 if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
875 if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
877 return ca.ConstructorArguments[1].Value as string;
882 internal static string GetResourceIdForPath(ModuleDefinition module, string path)
884 foreach (var ca in module.GetCustomAttributes())
886 if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
888 if (ca.ConstructorArguments[1].Value as string != path)
890 return ca.ConstructorArguments[0].Value as string;