public AvaloniaAttachedInstanceProperty(XamlIlAstNamePropertyReference prop, XamlIlTransformerConfiguration config, IXamlIlType declaringType, IXamlIlType type, IXamlIlType avaloniaPropertyType, IXamlIlType avaloniaObject, IXamlIlField field) : base(prop, prop.Name, declaringType, null) { _config = config; _declaringType = declaringType; _avaloniaPropertyType = avaloniaPropertyType; // XamlIl doesn't support generic methods yet if (_avaloniaPropertyType.GenericArguments?.Count > 0) { _avaloniaPropertyType = _avaloniaPropertyType.BaseType; } _avaloniaObject = avaloniaObject; _field = field; PropertyType = type; Setters.Add(new SetterMethod(this)); Getter = new GetterMethod(this); }
private CompilerTestBase(IXamlIlTypeSystem typeSystem) { _typeSystem = typeSystem; Configuration = new XamlIlTransformerConfiguration(typeSystem, typeSystem.FindAssembly("XamlParserTests"), new XamlIlLanguageTypeMappings(typeSystem) { XmlnsAttributes = { typeSystem.GetType("XamlParserTests.XmlnsDefinitionAttribute"), }, ContentAttributes = { typeSystem.GetType("XamlParserTests.ContentAttribute") }, UsableDuringInitializationAttributes = { typeSystem.GetType("XamlParserTests.UsableDuringInitializationAttribute") }, DeferredContentPropertyAttributes = { typeSystem.GetType("XamlParserTests.DeferredContentAttribute") }, RootObjectProvider = typeSystem.GetType("XamlParserTests.ITestRootObjectProvider"), UriContextProvider = typeSystem.GetType("XamlParserTests.ITestUriContext"), ProvideValueTarget = typeSystem.GetType("XamlParserTests.ITestProvideValueTarget"), ParentStackProvider = typeSystem.GetType("XamlIl.Runtime.IXamlIlParentStackProviderV1"), XmlNamespaceInfoProvider = typeSystem.GetType("XamlIl.Runtime.IXamlIlXmlNamespaceInfoProviderV1") } ); }
public XamlIlAstClrProperty(IXamlIlLineInfo lineInfo, IXamlIlProperty property, XamlIlTransformerConfiguration cfg) : base(lineInfo) { Name = property.Name; Getter = property.Getter; if (property.Setter != null) { Setters.Add(new XamlIlDirectCallPropertySetter(property.Setter)); } CustomAttributes = property.CustomAttributes.ToList(); DeclaringType = (property.Getter ?? property.Setter)?.DeclaringType; var typeConverterAttributes = cfg.GetCustomAttribute(property, cfg.TypeMappings.TypeConverterAttributes); if (typeConverterAttributes != null) { foreach (var attr in typeConverterAttributes) { var typeConverter = XamlIlTransformHelpers.TryGetTypeConverterFromCustomAttribute(cfg, attr); if (typeConverter != null) { TypeConverters[property.PropertyType] = typeConverter; break; } } } }
public XamlIlDeferredContentNode(IXamlIlAstValueNode value, XamlIlTransformerConfiguration config) : base(value) { Value = value; var funcType = config.TypeSystem.GetType("System.Func`2") .MakeGenericType(config.TypeMappings.ServiceProvider, config.WellKnownTypes.Object); Type = new XamlIlAstClrTypeReference(value, funcType); }
public CompilerTestBase(IXamlIlTypeSystem typeSystem) { _typeSystem = typeSystem; Configuration = new XamlIlTransformerConfiguration(typeSystem, typeSystem.FindAssembly("XamlParserTests"), new XamlIlLanguageTypeMappings(typeSystem) { XmlnsAttributes = { typeSystem.FindType("XamlParserTests.XmlnsDefinitionAttribute"), }, ContentAttributes = { typeSystem.FindType("XamlParserTests.ContentAttribute") }, RootObjectProvider = typeSystem.FindType("XamlParserTests.ITestRootObjectProvider"), ApplyNonMatchingMarkupExtension = typeSystem.GetType("XamlParserTests.CompilerTestBase") .Methods.First(m => m.Name == "ApplyNonMatchingMarkupExtension") } ); }
private AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration) : base(configuration, true) { _configuration = configuration; void InsertAfter <T>(params IXamlIlAstTransformer[] t) => Transformers.InsertRange(Transformers.FindIndex(x => x is T) + 1, t); void InsertBefore <T>(params IXamlIlAstTransformer[] t) => Transformers.InsertRange(Transformers.FindIndex(x => x is T), t); // Before everything else Transformers.Insert(0, new XNameTransformer()); Transformers.Insert(1, new IgnoredDirectivesTransformer()); Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); Transformers.Insert(3, new AvaloniaBindingExtensionHackTransformer()); // Targeted InsertBefore <XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlTransformInstanceAttachedProperties()); InsertAfter <XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver()); InsertBefore <XamlIlContentConvertTransformer>( new AvaloniaXamlIlSelectorTransformer(), new AvaloniaXamlIlSetterTransformer(), new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(), new AvaloniaXamlIlConstructorServiceProviderTransformer(), new AvaloniaXamlIlTransitionsTypeMetadataTransformer() ); // After everything else Transformers.Add(new AddNameScopeRegistration()); Transformers.Add(new AvaloniaXamlIlMetadataRemover()); }
public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory, string output) { var typeSystem = new CecilTypeSystem(references.Concat(new[] { input }), input); var asm = typeSystem.TargetAssemblyDefinition; var emres = new EmbeddedResources(asm); var avares = new AvaloniaResources(asm, projectDirectory); if (avares.Resources.Count(CheckXamlName) == 0 && emres.Resources.Count(CheckXamlName) == 0) { // Nothing to do return(new CompileResult(true)); } var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem); var compilerConfig = new XamlIlTransformerConfiguration(typeSystem, typeSystem.TargetAssembly, xamlLanguage, XamlIlXmlnsMappings.Resolve(typeSystem, xamlLanguage), AvaloniaXamlIlLanguage.CustomValueConverter); var contextDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlContext", TypeAttributes.Class, asm.MainModule.TypeSystem.Object); asm.MainModule.Types.Add(contextDef); var contextClass = XamlIlContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem, xamlLanguage); var compiler = new AvaloniaXamlIlCompiler(compilerConfig, contextClass); var editorBrowsableAttribute = typeSystem .GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute")) .Resolve(); var editorBrowsableCtor = asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors() .First(c => c.Parameters.Count == 1)); var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers"); var createRootServiceProviderMethod = asm.MainModule.ImportReference( typeSystem.GetTypeReference(runtimeHelpers).Resolve().Methods .First(x => x.Name == "CreateRootServiceProviderV2")); var loaderDispatcherDef = new TypeDefinition("CompiledAvaloniaXaml", "!XamlLoader", TypeAttributes.Class, asm.MainModule.TypeSystem.Object); loaderDispatcherDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor) { ConstructorArguments = { new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1) } }); var loaderDispatcherMethod = new MethodDefinition("TryLoad", MethodAttributes.Static | MethodAttributes.Public, asm.MainModule.TypeSystem.Object) { Parameters = { new ParameterDefinition(asm.MainModule.TypeSystem.String) } }; loaderDispatcherDef.Methods.Add(loaderDispatcherMethod); asm.MainModule.Types.Add(loaderDispatcherDef); var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First( m => m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 && m.ReturnType.FullName == "System.Boolean" && m.Parameters[0].ParameterType.FullName == "System.String" && m.Parameters[1].ParameterType.FullName == "System.String")); bool CompileGroup(IResourceGroup group) { var typeDef = new TypeDefinition("CompiledAvaloniaXaml", "!" + group.Name, TypeAttributes.Class, asm.MainModule.TypeSystem.Object); typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor) { ConstructorArguments = { new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1) } }); asm.MainModule.Types.Add(typeDef); var builder = typeSystem.CreateTypeBuilder(typeDef); foreach (var res in group.Resources.Where(CheckXamlName)) { try { // StreamReader is needed here to handle BOM var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd(); var parsed = XDocumentXamlIlParser.Parse(xaml); var initialRoot = (XamlIlAstObjectNode)parsed.Root; var precompileDirective = initialRoot.Children.OfType <XamlIlAstXmlDirective>() .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Precompile"); if (precompileDirective != null) { var precompileText = (precompileDirective.Values[0] as XamlIlAstTextNode)?.Text.Trim() .ToLowerInvariant(); if (precompileText == "false") { continue; } if (precompileText != "true") { throw new XamlIlParseException("Invalid value for x:Precompile", precompileDirective); } } var classDirective = initialRoot.Children.OfType <XamlIlAstXmlDirective>() .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class"); IXamlIlType classType = null; if (classDirective != null) { if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlIlAstTextNode tn)) { throw new XamlIlParseException("x:Class should have a string value", classDirective); } classType = typeSystem.TargetAssembly.FindType(tn.Text); if (classType == null) { throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective); } compiler.OverrideRootType(parsed, new XamlIlAstClrTypeReference(classDirective, classType, false)); initialRoot.Children.Remove(classDirective); } compiler.Transform(parsed); var populateName = classType == null ? "Populate:" + res.Name : "!XamlIlPopulate"; var buildName = classType == null ? "Build:" + res.Name : null; var classTypeDefinition = classType == null ? null : typeSystem.GetTypeReference(classType).Resolve(); var populateBuilder = classTypeDefinition == null ? builder : typeSystem.CreateTypeBuilder(classTypeDefinition); compiler.Compile(parsed, contextClass, compiler.DefinePopulateMethod(populateBuilder, parsed, populateName, classTypeDefinition == null), buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true), builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, true), (closureName, closureBaseType) => populateBuilder.DefineSubType(closureBaseType, closureName, false), res.Uri, res ); if (classTypeDefinition != null) { var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve() .Methods.First(m => m.Name == populateName); var designLoaderFieldType = typeSystem .GetType("System.Action`1") .MakeGenericType(typeSystem.GetType("System.Object")); var designLoaderFieldTypeReference = (GenericInstanceType)typeSystem.GetTypeReference(designLoaderFieldType); designLoaderFieldTypeReference.GenericArguments[0] = asm.MainModule.ImportReference(designLoaderFieldTypeReference.GenericArguments[0]); designLoaderFieldTypeReference = (GenericInstanceType) asm.MainModule.ImportReference(designLoaderFieldTypeReference); var designLoaderLoad = typeSystem.GetMethodReference( designLoaderFieldType.Methods.First(m => m.Name == "Invoke")); designLoaderLoad = asm.MainModule.ImportReference(designLoaderLoad); designLoaderLoad.DeclaringType = designLoaderFieldTypeReference; var designLoaderField = new FieldDefinition("!XamlIlPopulateOverride", FieldAttributes.Static | FieldAttributes.Private, designLoaderFieldTypeReference); classTypeDefinition.Fields.Add(designLoaderField); const string TrampolineName = "!XamlIlPopulateTrampoline"; var trampoline = new MethodDefinition(TrampolineName, MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void); trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition)); classTypeDefinition.Methods.Add(trampoline); var regularStart = Instruction.Create(OpCodes.Call, createRootServiceProviderMethod); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, regularStart)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, designLoaderLoad)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); trampoline.Body.Instructions.Add(regularStart); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod)); trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); CopyDebugDocument(trampoline, compiledPopulateMethod); var foundXamlLoader = false; // Find AvaloniaXamlLoader.Load(this) and replace it with !XamlIlPopulateTrampoline(this) foreach (var method in classTypeDefinition.Methods .Where(m => !m.Attributes.HasFlag(MethodAttributes.Static))) { var i = method.Body.Instructions; for (var c = 1; c < i.Count; c++) { if (i[c].OpCode == OpCodes.Call) { var op = i[c].Operand as MethodReference; // TODO: Throw an error // This usually happens when same XAML resource was added twice for some weird reason // We currently support it for dual-named default theme resource if (op != null && op.Name == TrampolineName) { foundXamlLoader = true; break; } if (op != null && op.Name == "Load" && op.Parameters.Count == 1 && op.Parameters[0].ParameterType.FullName == "System.Object" && op.DeclaringType.FullName == "Avalonia.Markup.Xaml.AvaloniaXamlLoader") { if (MatchThisCall(i, c - 1)) { i[c].Operand = trampoline; foundXamlLoader = true; } } } } } if (!foundXamlLoader) { var ctors = classTypeDefinition.GetConstructors() .Where(c => !c.IsStatic).ToList(); // We can inject xaml loader into default constructor if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o => o.OpCode != OpCodes.Nop) == 3) { var i = ctors[0].Body.Instructions; var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret)); i.Insert(retIdx, Instruction.Create(OpCodes.Call, trampoline)); i.Insert(retIdx, Instruction.Create(OpCodes.Ldarg_0)); } else { throw new InvalidProgramException( $"No call to AvaloniaXamlLoader.Load(this) call found anywhere in the type {classType.FullName} and type seems to have custom constructors."); } } } if (buildName != null || classTypeDefinition != null) { var compiledBuildMethod = buildName == null ? null : typeSystem.GetTypeReference(builder).Resolve() .Methods.First(m => m.Name == buildName); var parameterlessConstructor = compiledBuildMethod != null ? null : classTypeDefinition.GetConstructors().FirstOrDefault(c => c.IsPublic && !c.IsStatic && !c.HasParameters); if (compiledBuildMethod != null || parameterlessConstructor != null) { var i = loaderDispatcherMethod.Body.Instructions; var nop = Instruction.Create(OpCodes.Nop); i.Add(Instruction.Create(OpCodes.Ldarg_0)); i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri)); i.Add(Instruction.Create(OpCodes.Call, stringEquals)); i.Add(Instruction.Create(OpCodes.Brfalse, nop)); if (parameterlessConstructor != null) { i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor)); } else { i.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod)); i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod)); } i.Add(Instruction.Create(OpCodes.Ret)); i.Add(nop); } } } catch (Exception e) { int lineNumber = 0, linePosition = 0; if (e is XamlIlParseException xe) { lineNumber = xe.LineNumber; linePosition = xe.LinePosition; } engine.LogErrorEvent(new BuildErrorEventArgs("Avalonia", "XAMLIL", res.FilePath, lineNumber, linePosition, lineNumber, linePosition, e.Message, "", "Avalonia")); return(false); } res.Remove(); } return(true); } if (emres.Resources.Count(CheckXamlName) != 0) { if (!CompileGroup(emres)) { return(new CompileResult(false)); } } if (avares.Resources.Count(CheckXamlName) != 0) { if (!CompileGroup(avares)) { return(new CompileResult(false)); } avares.Save(); } loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull)); loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); asm.Write(output, new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols }); return(new CompileResult(true, true)); }
public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, IXamlIlType contextType) : this(configuration) { _contextType = contextType; }
public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, IXamlIlTypeBuilder contextTypeBuilder) : this(configuration) { _contextType = CreateContextType(contextTypeBuilder); }