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 private string GetNameSpaceOfResource(EmbeddedResource resource)
385 var index = resource.Name.LastIndexOf('.');
386 var resourceNameWithoutSubfix = resource.Name.Substring(0, index);
388 index = resourceNameWithoutSubfix.LastIndexOf('.');
389 var nameSpace = resourceNameWithoutSubfix.Substring(0, index);
394 bool DoInjection(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
396 thrownExceptions = null;
398 var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
399 if (initComp == null)
401 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
405 CustomAttribute xamlFilePathAttr;
406 var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
407 (string)xamlFilePathAttr.ConstructorArguments[0].Value :
410 var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
411 if (initCompRuntime != null)
412 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
415 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
416 initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
417 initCompRuntime.Body.InitLocals = true;
418 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
419 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
420 initCompRuntime.Body = new MethodBody(initCompRuntime);
421 var iCRIl = initCompRuntime.Body.GetILProcessor();
422 foreach (var instr in initComp.Body.Instructions)
424 initComp.Body.Instructions.Clear();
425 initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
426 initComp.Body.InitLocals = true;
428 typeDef.Methods.Add(initCompRuntime);
429 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
432 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
433 var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
434 if (rootnode == null)
436 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
439 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
441 hasCompiledXamlResources = true;
443 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
446 var embeddedResourceNameSpace = GetNameSpaceOfResource(resource);
447 if (!TryCoreCompile(initComp, rootnode, embeddedResourceNameSpace, out e))
449 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
450 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
451 if (e is XamlParseException xpe)
452 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
453 else if (e is XmlException xe)
454 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
456 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
458 if (null != e.StackTrace)
460 LoggingHelper.LogMessage(Low, e.StackTrace);
466 InitCompForType = initComp;
468 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
472 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
473 initComp.Body.Optimize();
474 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
477 #pragma warning disable 0618
478 if (OutputGeneratedILAsCode)
479 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated");
480 #pragma warning restore 0618
485 bool GenerateEXaml(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
487 thrownExceptions = null;
489 ModuleDefinition module = typeDef.Module;
491 CustomAttribute xamlFilePathAttr;
492 var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
493 (string)xamlFilePathAttr.ConstructorArguments[0].Value :
496 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
497 var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
498 if (rootnode == null)
500 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
503 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
505 hasCompiledXamlResources = true;
507 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
510 var embeddedResourceNameSpace = GetNameSpaceOfResource(resource);
511 var visitorContext = new EXamlContext(typeDef, typeDef.Module, embeddedResourceNameSpace);
513 if (!TryCoreCompile(rootnode, visitorContext, out e))
515 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
516 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
517 if (e is XamlParseException xpe)
518 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
519 else if (e is XmlException xe)
520 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
522 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
524 if (null != e.StackTrace)
526 LoggingHelper.LogError(e.StackTrace);
533 var examlDir = outputRootPath + @"res/examl/";
534 if (Directory.Exists(examlDir))
536 Directory.CreateDirectory(examlDir);
539 var examlFilePath = examlDir + typeDef.FullName + ".examl";
541 EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
547 bool GenerateEXaml(string xamlFilePath, ModuleDefinition module, out IList<Exception> thrownExceptions)
549 thrownExceptions = null;
551 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
552 Stream xamlStream = File.Open(xamlFilePath, FileMode.Open);
555 if (!CecilExtensions.IsXaml(xamlStream, module, out className))
557 thrownExceptions.Add(new Exception($"{xamlFilePath} is not xaml format file"));
560 xamlStream.Seek(0, SeekOrigin.Begin);
561 var typeDef = module.GetTypeDefinition(className);
565 throw new Exception($"Can't find type \"{className}\" in assembly \"{module.Assembly.FullName}\"");
568 var rootnode = ParseXaml(xamlStream, typeDef);
572 if (rootnode == null)
574 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
577 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
579 hasCompiledXamlResources = true;
581 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
584 var visitorContext = new EXamlContext(typeDef, module, null);
586 if (!TryCoreCompile(rootnode, visitorContext, out e))
588 LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
589 (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
590 if (e is XamlParseException xpe)
591 LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
592 else if (e is XmlException xe)
593 LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
595 LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
597 if (null != e.StackTrace)
599 LoggingHelper.LogMessage(Low, e.StackTrace);
606 var examlDir = outputRootPath + @"res/examl/";
607 if (Directory.Exists(examlDir))
609 Directory.CreateDirectory(examlDir);
612 var examlFilePath = examlDir + typeDef.FullName + ".examl";
614 EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
621 bool InjectionMethodGetEXamlPath(TypeDefinition typeDef)
623 var getEXamlPathComp = typeDef.Methods.FirstOrDefault(md => md.Name == "GetEXamlPath");
624 if (getEXamlPathComp == null)
626 LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no GetEXamlPath found... skipped.");
630 var examlRelativePath = @"examl/" + typeDef.FullName + ".examl";
631 getEXamlPathComp.Body.Instructions.Clear();
632 getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ldstr, examlRelativePath);
633 getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ret);
638 bool TryCoreCompile(MethodDefinition initComp, ILRootNode rootnode, string embeddedResourceNameSpace, out Exception exception)
642 var body = new MethodBody(initComp);
643 var module = body.Method.Module;
644 var type = initComp.DeclaringType;
646 MethodDefinition constructorOfRemoveEventsType;
647 TypeDefinition typeOfRemoveEvents = CreateTypeForRemoveEvents(type, out constructorOfRemoveEventsType);
649 var field = type.GetOrCreateField("___Info_Of_RemoveEvent___", FieldAttributes.Private, typeOfRemoveEvents);
651 body.InitLocals = true;
652 var il = body.GetILProcessor();
653 il.Emit(OpCodes.Ldarg_0);
654 il.Emit(OpCodes.Newobj, constructorOfRemoveEventsType);
655 il.Emit(OpCodes.Stfld, field);
657 var resourcePath = GetPathForType(module, type);
661 List<Instruction> insOfAddEvent = new List<Instruction>();
663 var visitorContext = new ILContext(il, body, insOfAddEvent, module, embeddedResourceNameSpace);
665 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
666 rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
667 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
668 rootnode.Accept(new CreateObjectVisitor(visitorContext), null);
670 Set(visitorContext, visitorContext.Variables[rootnode], "IsCreateByXaml", new ValueNode("true", rootnode.NamespaceResolver), null);
672 rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null);
673 rootnode.Accept(new SetFieldVisitor(visitorContext), null);
674 rootnode.Accept(new SetResourcesVisitor(visitorContext), null);
675 rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null);
677 AddInsOfRemoveEvent(il, visitorContext.InsOfAddEvent, typeOfRemoveEvents);
680 initComp.Body = body;
686 XamlParseException xamlParseException = e as XamlParseException;
687 if (null != xamlParseException)
689 XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
701 private void AddInsOfRemoveEvent(ILProcessor ilOfInit, List<Instruction> instructions, TypeDefinition typeDef)
703 MethodDefinition methodCall = typeDef.GetOrCreateMethod("Call", MethodAttributes.Public, typeof(void));
704 methodCall.Body.Instructions.Clear();
706 var fieldOfRemoveEvent = typeDef.DeclaringType.Fields.FirstOrDefault(a => a.Name == "___Info_Of_RemoveEvent___");
708 var il = methodCall.Body.GetILProcessor();
710 foreach (var ins in instructions)
712 if (ins.OpCode == OpCodes.Ldloc
714 ins.Operand is VariableDefinition variable)
716 var fieldName = "field" + variable.Index;
717 var field = typeDef.GetOrCreateField(fieldName, FieldAttributes.Public, variable.VariableType);
719 ilOfInit.Emit(OpCodes.Ldarg_0);
720 ilOfInit.Emit(OpCodes.Ldfld, fieldOfRemoveEvent);
721 ilOfInit.Emit(OpCodes.Ldloc, variable);
722 ilOfInit.Emit(OpCodes.Stfld, field);
724 methodCall.Body.Instructions.Add(Instruction.Create(Ldarg_0));
725 methodCall.Body.Instructions.Add(Instruction.Create(Ldfld, field));
729 bool isReplaced = false;
730 if (ins.OpCode == OpCodes.Callvirt && ins.Operand is MethodReference method)
732 if (method.Name.StartsWith("add_"))
734 var eventName = method.Name.Substring("add_".Length);
736 var typeOfEvent = method.DeclaringType.GetEvent(a => a.Name == eventName, out _);
738 if (typeOfEvent is EventDefinition)
740 var methodOfRemoveEvent = typeDef.Module.ImportReference(method.DeclaringType.ResolveCached()?.Methods.FirstOrDefault(a => a.Name == "remove_" + eventName));
741 if (null != methodOfRemoveEvent)
743 var newIns = Instruction.Create(ins.OpCode, methodOfRemoveEvent);
744 methodCall.Body.Instructions.Add(newIns);
752 if (false == isReplaced)
754 methodCall.Body.Instructions.Add(ins);
759 methodCall.Body.Instructions.Add(Instruction.Create(Ret));
761 var removeEventMethod = typeDef.DeclaringType.Methods.FirstOrDefault(a => a.Name == "RemoveEventsInXaml");
762 if (null != removeEventMethod)
764 removeEventMethod.Body.Instructions.Clear();
765 var ilRemoveEvent = removeEventMethod.Body.GetILProcessor();
767 ilRemoveEvent.Emit(Ldarg_0);
768 ilRemoveEvent.Emit(Ldfld, fieldOfRemoveEvent);
769 ilRemoveEvent.Emit(Dup);
771 var insOfCall = Instruction.Create(Call, methodCall.Resolve());
773 ilRemoveEvent.Emit(Brtrue_S, insOfCall);
774 ilRemoveEvent.Emit(Pop);
776 var endIns = Instruction.Create(Ret);
778 ilRemoveEvent.Emit(Br_S, endIns);
779 ilRemoveEvent.Append(insOfCall);
781 ilRemoveEvent.Append(endIns);
785 TypeDefinition CreateTypeForRemoveEvents(TypeDefinition typeDef, out MethodDefinition constructor)
787 var module = typeDef.Module;
789 var name = "___Type___For___RemoveEvent___";
790 var nestType = typeDef.NestedTypes.FirstOrDefault(a => a.Name == name);
792 if (null == nestType)
794 nestType = new TypeDefinition(typeDef.Namespace, name, TypeAttributes.NestedPrivate | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed | TypeAttributes.AnsiClass);
795 nestType.BaseType = module.ImportReference(typeof(object));
796 typeDef.NestedTypes.Add(nestType);
798 constructor = nestType.AddDefaultConstructor();
802 constructor = nestType.Methods.FirstOrDefault(a => a.IsConstructor);
808 bool TryCoreCompile(ILRootNode rootnode, EXamlContext visitorContext, out Exception exception)
812 XmlTypeExtensions.s_xmlnsDefinitions?.Clear();
813 XmlTypeExtensions.s_xmlnsDefinitions = null;
815 visitorContext.Values[rootnode] = new EXamlCreateObject(visitorContext, null, rootnode.TypeReference);
817 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
818 rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
819 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
820 rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
821 rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
822 rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
823 rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
824 rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
831 XamlParseException xamlParseException = e as XamlParseException;
832 if (null != xamlParseException)
834 XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
846 private void Set(ILContext Context, VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo)
848 var module = Context.Body.Method.Module;
849 TypeReference declaringTypeReference;
850 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
851 if (null == property)
855 var propertySetter = property.SetMethod;
857 module.ImportReference(parent.VariableType.ResolveCached());
858 var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
859 propertySetterRef.ImportTypes(module);
860 var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
861 var valueNode = node as ValueNode;
862 var elementNode = node as IElementNode;
864 if (parent.VariableType.IsValueType)
865 Context.IL.Emit(OpCodes.Ldloca, parent);
867 Context.IL.Emit(OpCodes.Ldloc, parent);
869 if (valueNode != null)
871 foreach (var instruction in valueNode.PushConvertedValue(Context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(Context, propertyRef: property), false, true))
873 Context.IL.Append(instruction);
876 if (parent.VariableType.IsValueType)
877 Context.IL.Emit(OpCodes.Call, propertySetterRef);
879 Context.IL.Emit(OpCodes.Callvirt, propertySetterRef);
883 internal static string GetPathForType(ModuleDefinition module, TypeReference type)
885 foreach (var ca in type.Module.GetCustomAttributes())
887 if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
889 if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
891 return ca.ConstructorArguments[1].Value as string;
896 internal static string GetResourceIdForPath(ModuleDefinition module, string path)
898 foreach (var ca in module.GetCustomAttributes())
900 if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
902 if (ca.ConstructorArguments[1].Value as string != path)
904 return ca.ConstructorArguments[0].Value as string;