| File: GenPartialFacadeSourceGenerator.cs | Web Access |
| Project: src\arcade\src\Microsoft.DotNet.GenFacades\Microsoft.DotNet.GenFacades.csproj (Microsoft.DotNet.GenFacades) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.DotNet.Build.Tasks; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; namespace Microsoft.DotNet.GenFacades { public class GenPartialFacadeSourceGenerator { public static bool Execute( string[] seeds, string contractAssembly, string[] compileFiles, string defineConstants, string langVersion, string outputSourcePath, ILog logger, bool ignoreMissingTypes = false, string[] ignoreMissingTypesList = null, string[] OmitTypes = null, ITaskItem[] seedTypePreferencesList = null) { Dictionary<string, string> seedTypePreferences = ParseSeedTypePreferences(seedTypePreferencesList, logger); IEnumerable<string> referenceTypes = GetPublicVisibleTypes(contractAssembly, includeTypeForwards: true); // Normalizing and Removing Relative Segments from the seed paths. string[] distinctSeeds = seeds.Select(seed => Path.GetFullPath(seed)).Distinct().ToArray(); string[] seedNames = distinctSeeds.Select(seed => Path.GetFileName(seed)).ToArray(); if (distinctSeeds.Count() != seedNames.Distinct(StringComparer.InvariantCultureIgnoreCase).Count()) { IEnumerable<string> duplicates = seedNames.GroupBy(x => x) .Where(g => g.Count() > 1) .Select(y => y.Key); logger.LogError("There are multiple versions of these assemblies: {0}. Please provide a single version.", string.Join(", ", duplicates)); return false; } IReadOnlyDictionary<string, IList<string>> seedTypes = GenerateTypeTable(distinctSeeds); if (OmitTypes != null) referenceTypes = referenceTypes.Where(type => !OmitTypes.Contains(type)); var sourceGenerator = new SourceGenerator(referenceTypes, seedTypes, seedTypePreferences, outputSourcePath, ignoreMissingTypesList, logger); return sourceGenerator.GenerateSource(compileFiles, ParseDefineConstants(defineConstants), langVersion, ignoreMissingTypes); } private static IEnumerable<string> ParseDefineConstants(string defineConstants) { return defineConstants?.Split(';', ',').Where(t => !string.IsNullOrEmpty(t)).ToArray(); } private static Dictionary<string, string> ParseSeedTypePreferences(ITaskItem[] preferences, ILog logger) { var dictionary = new Dictionary<string, string>(StringComparer.Ordinal); if (preferences != null) { foreach (var item in preferences) { string key = item.ItemSpec; string value = item.GetMetadata("Aliases"); if (value != null) { string existingValue; if (dictionary.TryGetValue(key, out existingValue)) { logger.LogWarning($"Overriding SeedType{existingValue} for type {key} with {value}"); } dictionary[key] = value; } else { logger.LogWarning($"No Alias has been provided for type {key}"); } } } return dictionary; } private static IEnumerable<string> GetPublicVisibleTypes(string assembly, bool includeTypeForwards = false) { using (var peReader = new PEReader(new FileStream(assembly, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read))) { if (peReader.HasMetadata) { MetadataReader reader = peReader.GetMetadataReader(); // Enumerating typeDefinatons foreach (var typeDefinationHandle in reader.TypeDefinitions) { TypeDefinition typeDefination = reader.GetTypeDefinition(typeDefinationHandle); // Ignoring Nested types if (!typeDefination.IsNested && IsPublic(typeDefination)) { yield return GetTypeName(typeDefination.Namespace, typeDefination.Name, reader); } } if (includeTypeForwards) { // Enumerating typeforwards foreach (var exportedTypeHandle in reader.ExportedTypes) { ExportedType exportedType = reader.GetExportedType(exportedTypeHandle); if (exportedType.IsForwarder) { yield return GetTypeName(exportedType.Namespace, exportedType.Name, reader); } } } } } } private static string GetTypeName(StringHandle namespaceHandle, StringHandle typeHandle, MetadataReader reader) { return namespaceHandle.IsNil ? reader.GetString(typeHandle) : reader.GetString(namespaceHandle) + "." + reader.GetString(typeHandle); } // This acts as a filter for public types. private static bool IsPublic(TypeDefinition typeDefination) { return (typeDefination.Attributes & TypeAttributes.Public) != 0; } private static IReadOnlyDictionary<string, IList<string>> GenerateTypeTable(IEnumerable<string> seedAssemblies) { var typeTable = new Dictionary<string, IList<string>>(); foreach(string assembly in seedAssemblies) { IEnumerable<string> types = GetPublicVisibleTypes(assembly); foreach (string type in types) { AddTypeToTable(typeTable, type, Path.GetFileName(assembly)); } } return typeTable; } private static void AddTypeToTable(Dictionary<string, IList<string>> typeTable, string type, string assemblyName) { if (type != null) { IList<string> assemblyListForTypes; if (!typeTable.TryGetValue(type, out assemblyListForTypes)) { assemblyListForTypes = new List<string>(1); typeTable.Add(type, assemblyListForTypes); } assemblyListForTypes.Add(assemblyName); } } } }