public void TestMethodHelper(MrLoadContext loadContext, string expectedOutput)
        {
            Assert.IsTrue(loadContext.LoadedAssemblies.Count() == 1);
            var testAssembly = loadContext.LoadedAssemblies.First();

            var builder     = new StringBuilder();
            var typesString = WriteTypes(testAssembly);

            Assert.AreEqual(typesString, expectedOutput);
        }
예제 #2
0
        private void DiscoverAttachedProperties(MrLoadContext context, IEnumerable <MrType> types)
        {
            var attached = new List <MrProperty>();
            var dpType   = context.GetType($"{XamlNames.XamlNamespace}.DependencyProperty");

            foreach (var type in types)
            {
                attached.AddRange(GetAttachedDPCandidates(dpType, type));
            }
            Util.AttachedProperties = attached;
        }
예제 #3
0
        public void TestWinMD()
        {
            var loadContext = new MrLoadContext(useWinRTProjections: true);

            loadContext.LoadAssemblyFromBytes(Properties.Resources.UnitTestWinRTComponent);
            loadContext.FinishLoading();

            TestMethodHelper(loadContext, Properties.Resources.ExpectdProjectedWinRT);

            loadContext = new MrLoadContext(useWinRTProjections: false);
            loadContext.LoadAssemblyFromBytes(Properties.Resources.UnitTestWinRTComponent);
            loadContext.FinishLoading();

            TestMethodHelper(loadContext, Properties.Resources.ExpectedUnprojectedWinRT);
        }
예제 #4
0
        public void TestDotNetAssembly()
        {
            var testAssembly = typeof(UnitTestSampleAssembly.Class1 <, ,>).Assembly;

            var loadContext = new MrLoadContext();

            loadContext.AssemblyPathFromName = (string assemblyName) =>
            {
                if (testAssembly.GetName().Name == assemblyName)
                {
                    return(testAssembly.Location);
                }

                return(null);
            };

            loadContext.LoadFromAssemblyName(testAssembly.GetName().Name);
            loadContext.FinishLoading();

            TestMethodHelper(loadContext, Properties.Resources.ExpectedOutput);
        }
        MrLoadContext LoadDotNetTestAssembly()
        {
            var testAssembly = typeof(UnitTestSampleAssembly.Class1 <, ,>).Assembly;

            var loadContext = new MrLoadContext();

            loadContext.AssemblyPathFromName = (string assemblyName) =>
            {
                if (testAssembly.GetName().Name == assemblyName)
                {
                    return(testAssembly.Location);
                }

                return(null);
            };

            loadContext.LoadFromAssemblyName(testAssembly.GetName().Name);
            loadContext.FinishLoading();

            return(loadContext);
        }
예제 #6
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
        void DumpTypes(string path)
        {
            var output = Path.ChangeExtension(path, "xml");

            writer = XmlWriter.Create(output, new XmlWriterSettings()
            {
                Indent = true
            });
            writer.WriteStartDocument();
            var context = new MrLoadContext(true);

            context.FakeTypeRequired += (sender, e) => {
                var ctx = sender as MrLoadContext;
                if (e.AssemblyName == "Windows.Foundation.FoundationContract")
                {
                    e.ReplacementType = ctx.GetTypeFromAssembly(e.TypeName, "Windows");
                }
            };
            var windows_winmd = context.LoadAssemblyFromPath(@"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd"); //, "Windows.winmd");
            var assembly      = context.LoadAssemblyFromPath(path);                                                                               // @"C:\rnw\vnext\target\x86\Debug\Microsoft.ReactNative\Microsoft.ReactNative.winmd");

            context.FinishLoading();
            var types = assembly.GetAllTypes().Skip(1);

            var namespaces = assembly.GetAllTypes().Skip(1).Select(x => x.GetNamespace()).Distinct();

            writer.WriteStartElement("assembly");
            writer.WriteAttributeString("namespace", namespaces.FirstOrDefault());

            foreach (var t in types)
            {
                if (IsExclusiveInterface(t) || IsAttribute(t))
                {
                    continue;
                }
                writer.WriteStartElement(GetTypeKind(t));
                writer.WriteAttributeString("name", t.GetName());
                if (!t.IsInterface && t.IsAbstract)
                {
                    writer.WriteAttributeString("abstract", "true");
                }
                var attrs = GetCustomAttrs(t);
                WriteAttrs(attrs);

                Debug.WriteLine($"{GetTypeKind(t)} {t.GetName()} {attrs.GetValueOrDefault("docstring")} {attrs.GetValueOrDefault("docdefault")}");
                var kind = GetTypeKind(t);

                var baseTypesToSkip = new string[]
                {
                    typeof(MulticastDelegate).FullName,
                    typeof(ValueType).FullName,
                    typeof(Enum).FullName,
                    typeof(object).FullName,
                    typeof(Attribute).FullName,
                };

                if (t.GetBaseType() != null && !baseTypesToSkip.Contains(t.GetBaseType().GetFullName()))
                {
                    writer.WriteStartElement("extends");
                    WriteType(t.GetBaseType());
                    writer.WriteEndElement();
                }
                var ifaces = t.GetInterfaces().Where(x => !IsExclusiveInterface(x));
                if (ifaces.Count() > 0)
                {
                    writer.WriteStartElement(t.IsClass ? "implements" : "extends");
                    foreach (var i in ifaces)
                    {
                        WriteType(i);
                    }
                    writer.WriteEndElement();
                }


                foreach (var m in t.GetProperties())
                {
                    var mattrs       = GetCustomAttrs(m);
                    var mattrsGetter = GetCustomAttrs(m.Getter);
                    foreach (var kv in mattrsGetter)
                    {
                        mattrs[kv.Key] = kv.Value;
                    }
                    writer.WriteStartElement("property");
                    writer.WriteAttributeString("name", m.GetName());
                    bool isStatic = (m.Getter.MethodDefinition.Attributes & System.Reflection.MethodAttributes.Static) == System.Reflection.MethodAttributes.Static;
                    if (isStatic)
                    {
                        writer.WriteAttributeString("static", isStatic.ToString().ToLower());
                    }
                    bool isReadonly = m.Setter == null || !m.Setter.GetParsedMethodAttributes().IsPublic;
                    if (isReadonly)
                    {
                        writer.WriteAttributeString("isReadonly", isReadonly.ToString().ToLower());
                    }
                    WriteAttrs(mattrs);
                    WriteType(m.GetPropertyType());

                    writer.WriteEndElement();
                    Debug.WriteLine($"  prop {m.GetPropertyType().GetPrettyFullName()} {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}");
                }

                t.GetMethodsAndConstructors(out var methods, out var ctors);
                if (GetTypeKind(t) != "delegate")
                {
                    foreach (var m in methods)
                    {
                        var mattrs = GetCustomAttrs(m);
                        writer.WriteStartElement("method");
                        writer.WriteAttributeString("name", m.GetName());
                        bool isStatic = m.MethodDefinition.Attributes.HasFlag(System.Reflection.MethodAttributes.Static);
                        if (isStatic)
                        {
                            writer.WriteAttributeString("static", isStatic.ToString().ToLower());
                        }
                        bool isAbstract = !t.IsInterface && m.MethodDefinition.Attributes.HasFlag(System.Reflection.MethodAttributes.Abstract);
                        if (isAbstract)
                        {
                            writer.WriteAttributeString("abstract", isAbstract.ToString().ToLower());
                        }

                        WriteAttrs(mattrs);
                        WriteMethodSignature(m);
                        writer.WriteEndElement();
                        Debug.WriteLine($"  method {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}");
                    }

                    foreach (var m in ctors)
                    {
                        var mattrs = GetCustomAttrs(m);
                        writer.WriteStartElement("ctor");
                        writer.WriteAttributeString("name", m.DeclaringType.GetName());

                        WriteAttrs(mattrs);
                        WriteMethodSignature(m, false);
                        writer.WriteEndElement();
                        Debug.WriteLine($"  ctor {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}");
                    }
                }
                else
                {
                    var m      = t.GetInvokeMethod();
                    var mattrs = GetCustomAttrs(m);

                    WriteAttrs(mattrs);
                    WriteMethodSignature(m);
                }

                foreach (var m in t.GetFields().Where(x => !x.IsSpecialName))
                {
                    var mattrs = GetCustomAttrs(m);
                    writer.WriteStartElement("field");
                    writer.WriteAttributeString("name", m.GetName());
                    var constant = m.GetConstantValue(out var type);
                    if (constant != null)
                    {
                        writer.WriteAttributeString("value", constant.ToString());
                    }
                    WriteAttrs(mattrs);
                    writer.WriteEndElement();
                    Debug.WriteLine($"  field {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}");
                }

                foreach (var m in t.GetEvents())
                {
                    var mattrs = GetCustomAttrs(m);
                    writer.WriteStartElement("event");
                    writer.WriteAttributeString("name", m.GetName());

                    WriteAttrs(mattrs);
                    writer.WriteEndElement();
                    Debug.WriteLine($"  event {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}");
                }

                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();
        }
예제 #7
0
        private void DumpTypes(Version version)
        {
            var start = DateTime.Now;

            Config = JsonDocument.Parse(File.ReadAllText(ConfigFileName), new JsonDocumentOptions()
            {
                AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip
            });

            var context = new MrLoadContext(true);

            context.FakeTypeRequired += (sender, e) =>
            {
                var ctx = sender as MrLoadContext;
                if (e.AssemblyName == "Windows.Foundation.FoundationContract" || e.AssemblyName == "Windows.Foundation.UniversalApiContract")
                {
                    e.ReplacementType = ctx.GetTypeFromAssembly(e.TypeName, "Windows");
                }
            };

            var windows_winmd = context.LoadAssemblyFromPath(Windows_winmd);
            var winmds        = winmdPaths.Select(winmdPath => context.LoadAssemblyFromPath(winmdPath)).ToList();

            // ToList realizes the list which is needs to happen before FinishLoading is called

            context.FinishLoading();

            var typesPerAssembly   = winmds.Select(winmd => winmd.GetAllTypes().Skip(1));
            var types              = typesPerAssembly.Count() != 0 ? typesPerAssembly.Aggregate((l1, l2) => l1.Union(l2)) : new MrType[] { };
            var windows_winmdTypes = windows_winmd.GetAllTypes().Skip(1);

            if (winmdPaths.Count != 0)
            {
                types = types.Union(windows_winmdTypes);
            }
            else
            {
                types = windows_winmdTypes;
            }
            Util.LoadContext = context;

            foreach (var entry in Config.RootElement.GetProperty("commands").EnumerateObject())
            {
                var commands = new List <Command>();
                foreach (var c in entry.Value.EnumerateArray())
                {
                    var command = new Command {
                        Name = c.GetProperty("name").GetString()
                    };
                    if (c.TryGetProperty("args", out var value))
                    {
                        command.TSArgTypes = ConvertJSONToTSType(value);
                    }
                    commands.Add(command);
                }
                Util.commands[GetTypeNameFromJsonProperty(entry)] = commands;
            }

            var fakeProps = new List <MrProperty>();

            foreach (var entry in Config.RootElement.GetProperty("propNameMapping").EnumerateObject())
            {
                Util.propNameMap[GetTypeNameFromJsonProperty(entry)] = entry.Value.GetString();
            }

            foreach (var entry in Config.RootElement.GetProperty("fakeProps").EnumerateArray())
            {
                var value    = GetTypeNameFromJson(entry);
                var typeName = value.Substring(0, value.LastIndexOf('.'));
                var propName = value.Substring(value.LastIndexOf('.') + 1);
                fakeProps.Add(GetProperty(context, typeName, propName));
            }
            ;

            var syntheticProps = new List <SyntheticProperty>();

            foreach (var entry in Config.RootElement.GetProperty("syntheticProps").EnumerateArray())
            {
                var    declaringTypes = entry.GetProperty("declaringType");
                string name           = entry.GetProperty("name").GetString();

                MrType propertyType = entry.TryGetProperty("propertyType", out var propTypeJson) ? context.GetType(GetTypeNameFromJson(propTypeJson)) : null;

                if (name.IndexOf('.') != -1)
                {
                    var propTypeName = name.Substring(0, name.LastIndexOf('.'));
                    var propName     = name.Substring(name.LastIndexOf('.') + 1);
                    var propType     = context.GetType(propTypeName);
                    var prop         = propType.GetProperties().First(p => p.GetName() == propName);
                    if (prop.GetPropertyType() != propertyType)
                    {
                        throw new ArgumentException($"The property type for {name} was expected to be {prop.GetPropertyType()}, but was specified as {propertyType}");
                    }
                }
                string fakePropertyType = entry.TryGetProperty("fakePropertyType", out var fakePropType) ? fakePropType.GetString() : null;
                string comment          = entry.TryGetProperty("comment", out var commentElement) ? commentElement.GetString() : "";
                if (declaringTypes.ValueKind == JsonValueKind.Array)
                {
                    foreach (var declaringType in declaringTypes.EnumerateArray())
                    {
                        var sp = new SyntheticProperty
                        {
                            Name             = name,
                            DeclaringType    = context.GetType(GetTypeNameFromJson(declaringType)),
                            PropertyType     = propertyType,
                            FakePropertyType = fakePropertyType,
                            Comment          = comment,
                        };
                        syntheticProps.Add(sp);
                    }
                }
                else
                {
                    var sp = new SyntheticProperty
                    {
                        Name             = name,
                        DeclaringType    = context.GetType(GetTypeNameFromJson(declaringTypes)),
                        PropertyType     = propertyType,
                        FakePropertyType = fakePropertyType,
                        Comment          = comment,
                    };
                    syntheticProps.Add(sp);
                }
            }

            Console.WriteLine("Generating projections for the following WinMD files:");
            Console.WriteLine($"- {Windows_winmd}");
            foreach (var path in winmdPaths)
            {
                Console.WriteLine($"- {Path.GetFullPath(path)}");
            }
            Console.WriteLine();

            var properties = new List <SyntheticProperty>();

            PrintVerbose("Enumerating attached properties");
            DiscoverAttachedProperties(context, types);

            PrintVerbose($"Parsing configuration from {ConfigFileName}");

            foreach (var entry in Config.RootElement.GetProperty("attachedProps").EnumerateObject())
            {
                var propName    = GetTypeNameFromJsonProperty(entry);
                var attachedDPs = Util.AttachedProperties.Where(p => Util.MinusPropertySuffix(Util.GetPropFullName(p)).StartsWith(propName));

                foreach (var attachedDP in attachedDPs)
                {
                    var type       = attachedDP.DeclaringType;
                    var simpleName = attachedDP.GetName().Substring(0, attachedDP.GetName().LastIndexOf("Property"));
                    type.GetMethodsAndConstructors(out var methods, out var ctors);
                    var propType = methods.First(m => m.GetName() == $"Get{simpleName}").ReturnType;

                    if (entry.Value.ValueKind == JsonValueKind.Array)
                    {
                        foreach (var onTypeEntry in entry.Value.EnumerateArray())
                        {
                            var sp = new SyntheticProperty
                            {
                                Name          = simpleName,
                                DeclaringType = context.GetType(GetTypeNameFromJson(onTypeEntry)),
                                PropertyType  = propType,
                                Property      = attachedDP,
                                Comment       = $"Attached property: ${propName}",
                            };
                            properties.Add(sp);
                        }
                    }
                    else
                    {
                        var onType = GetTypeNameFromJson(entry.Value);

                        var sp = new SyntheticProperty
                        {
                            Name          = simpleName,
                            DeclaringType = context.GetType(onType),
                            PropertyType  = propType,
                            Property      = attachedDP,
                            Comment       = $"Attached property: {propName}",
                        };
                        properties.Add(sp);
                    }
                }
            }

            foreach (var entry in Config.RootElement.GetProperty("typeMapping").EnumerateArray())
            {
                Util.TypeMapping[GetTypeNameFromJson(entry)] = new TypeMapping()
                {
                    VM = Enum.Parse <ViewManagerPropertyType>(entry.GetProperty("VM").GetString()),
                    TS = entry.GetProperty("TS").GetString(),
                };
            }

            var baseClassesToProject = new List <string>();

            foreach (var entry in Config.RootElement.GetProperty("baseClasses").EnumerateArray())
            {
                var name = GetTypeNameFromJson(entry);
                baseClassesToProject.Add(name);
            }
            ;

            var syntheticEvents = new List <SyntheticProperty>();

            foreach (var entry in Config.RootElement.GetProperty("syntheticEvents").EnumerateObject())
            {
                var val       = GetTypeNameFromJsonProperty(entry);
                var typeName  = val.Substring(0, val.LastIndexOf('.'));
                var eventName = val.Substring(val.LastIndexOf('.') + 1);

                syntheticEvents.Add(new SyntheticProperty()
                {
                    Name             = eventName,
                    DeclaringType    = context.GetType(typeName),
                    FakePropertyType = entry.Value.GetString(),
                });
            }


            var xamlTypes = types.Where(type => baseClassesToProject.Any(b =>
                                                                         Util.DerivesFrom(type, b)) || type.GetFullName() == XamlNames.TopLevelProjectedType).ToList();

            var generatedDirPath = Path.GetFullPath(cppOutPath ?? Path.Join(PackageRoot, @"windows\ReactNativeXaml\Codegen"));
            var packageSrcPath   = Path.GetFullPath(tsOutPath ?? Path.Join(PackageRoot, @"src"));


            PrintVerbose("Filtering types");
            var creatableTypes = xamlTypes.Where(x => Util.HasCtor(x)).ToList();

            PrintVerbose("Sorting types");
            creatableTypes.Sort((a, b) => a.GetFullName().CompareTo(b.GetFullName()));

            foreach (var entry in Config.RootElement.GetProperty("eventArgsMethods").EnumerateObject())
            {
                Util.eventArgsMethods.Add(GetTypeNameFromJsonProperty(entry), entry.Value.EnumerateArray().Select(x => x.GetString()));
            }

            var events = new List <MrEvent>();

            var eventArgProps = new List <SyntheticProperty>();

            PrintVerbose("Enumerating properties and events");
            foreach (var type in xamlTypes)
            {
                var props      = type.GetProperties();
                var propsToAdd = props.Where(p => Util.ShouldEmitPropertyMetadata(p));
                foreach (var p in propsToAdd)
                {
                    properties.Add(new SyntheticProperty()
                    {
                        Name          = Util.GetPropFullName(p),
                        DeclaringType = p.DeclaringType,
                        Property      = p,
                    });
                }

                var eventsToAdd = type.GetEvents().Where(e => Util.ShouldEmitEventMetadata(e));
                foreach (var e in eventsToAdd)
                {
                    var handlerDelegate = e.GetEventType();
                    var invoke          = handlerDelegate.GetInvokeMethod();
                    if (invoke != null)
                    {
                        var parameters = invoke.GetParameters();
                        if (parameters.Length == 2 && (parameters[1].GetParameterName().EndsWith("args") || parameters[1].GetParameterType().GetName().EndsWith("Args")))
                        {
                            Util.FoundEventArgsType(parameters[1].GetParameterType());
                        }
                        else if (parameters.Length == 1 && parameters[0].GetParameterType().GetName().EndsWith("Args"))
                        {
                            Util.FoundEventArgsType(parameters[0].GetParameterType());
                        }
                        else
                        {
                            throw new ArgumentException($"Couldn't infer event arg type for event {e.GetName()}");
                        }
                    }
                    else if (handlerDelegate.GetFullName() == "System.EventHandler`1")
                    {
                        var paramType = handlerDelegate.GetGenericTypeParameters();
                        if (paramType.Length != 1)
                        {
                            throw new ArgumentException($"Couldn't infer EventHandler generic type for event {e.GetName()}");
                        }
                        Util.FoundEventArgsType(paramType[0]);
                    }
                }
                events.AddRange(eventsToAdd);
            }



            foreach (var type in Util.eventArgsTypes)
            {
                var props      = type.GetProperties();
                var propsToAdd = props
                                 .Where(p => Util.IsInstanceProperty(p))
                                 .Select(p => new SyntheticProperty()
                {
                    Name          = p.GetName(),
                    DeclaringType = p.DeclaringType,
                    Property      = p,
                });
                eventArgProps.AddRange(propsToAdd);
                foreach (var p in propsToAdd.Where(p => p.Property.GetPropertyType().IsEnum).Select(p => p.Property.GetPropertyType()))
                {
                    Util.VisitEnum(p);
                }
            }

            properties.Sort(CompareProps);
            eventArgProps.Sort(CompareProps);

            PrintVerbose("Generating projection");


            foreach (var entry in Config.RootElement.GetProperty("fakeEnums").EnumerateArray())
            {
                var      typeName = GetTypeNameFromJson(entry.GetProperty("name"));
                FakeEnum fe;
                if (typeName.IndexOf('.') != -1)
                {
                    var type = context.GetType(typeName);
                    if (type.IsEnum)
                    {
                        var values = type.GetFields().Skip(1);
                        fe = new FakeEnum()
                        {
                            Name   = typeName.Substring(typeName.LastIndexOf('.') + 1),
                            Values = values.ToDictionary <MrField, string, int>(f => f.GetName(), f => (int)f.GetConstantValue(out var _)),
                        };
                    }
                    else
                    {
                        throw new ArgumentException($"Type {typeName} is not an enum");
                    }
                }
                else
                {
                    fe = new FakeEnum()
                    {
                        Name   = typeName,
                        Values = ToDictionary(entry.GetProperty("values").EnumerateObject()),
                    };
                }
                Util.fakeEnums.Add(fe);
            }

            var propsGen       = new TSProps(xamlTypes, properties, fakeProps, syntheticProps, syntheticEvents).TransformText();
            var typesGen       = new TSTypes(xamlTypes).TransformText();
            var typeCreatorGen = new TypeCreator(creatableTypes).TransformText();
            var propertiesGen  = new TypeProperties(properties, fakeProps, syntheticProps).TransformText();
            var enumsGen       = new TypeEnums().TransformText();

            var tsEnumsGen    = new TSEnums().TransformText();
            var eventsGen     = new TypeEvents(events, syntheticEvents).TransformText();
            var eventPropsGen = new EventArgsTypeProperties(eventArgProps).TransformText();
            var versionGen    = new VersionHeader()
            {
                Version = version
            }.TransformText();

            PrintVerbose("Updating files");
            if (!Directory.Exists(generatedDirPath))
            {
                Directory.CreateDirectory(generatedDirPath);
            }

            var changes = false;

            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeCreator.g.cpp"), typeCreatorGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeProperties.g.h"), propertiesGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeEvents.g.h"), eventsGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "EventArgsTypeProperties.g.h"), eventPropsGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeEnums.g.h"), enumsGen);

            changes |= UpdateFile(Path.Join(generatedDirPath, "Version.g.h"), versionGen);

            changes |= UpdateFile(Path.Join(packageSrcPath, "Enums.ts"), tsEnumsGen.Replace("\r\n", "\n"));
            changes |= UpdateFile(Path.Join(packageSrcPath, "Props.ts"), propsGen.Replace("\r\n", "\n"));
            changes |= UpdateFile(Path.Join(packageSrcPath, "Types.tsx"), typesGen.Replace("\r\n", "\n"));

            if (!changes)
            {
                PrintVerbose("\nNo changes were required.");
            }
            PrintVerbose($"Done in {(DateTime.Now - start).TotalSeconds}s.");
        }
예제 #8
0
 private static MrProperty GetProperty(MrLoadContext context, string type, string prop)
 {
     return(context.GetType(type).GetProperties().First(x => x.GetName() == prop));
 }