// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Microsoft.ClearScript.Util
{
internal static partial class AssemblyHelpers
{
public static string GetFullAssemblyName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return name;
}
if (MiscHelpers.Try(out var assembly, () => Assembly.Load(name)))
{
return assembly.FullName;
}
var fileName = name;
if (!string.Equals(Path.GetExtension(fileName), ".dll", StringComparison.OrdinalIgnoreCase))
{
fileName = Path.ChangeExtension(fileName + '.', "dll");
}
if (MiscHelpers.Try(out var assemblyName, () => AssemblyName.GetAssemblyName(fileName)))
{
return assemblyName.FullName;
}
var dirPath = Path.GetDirectoryName(typeof(string).Assembly.Location);
if (!string.IsNullOrWhiteSpace(dirPath))
{
// ReSharper disable AccessToModifiedClosure
var path = Path.Combine(dirPath, fileName);
if (File.Exists(path) && MiscHelpers.Try(out assemblyName, () => AssemblyName.GetAssemblyName(path)))
{
return assemblyName.FullName;
}
if (MiscHelpers.Try(out var subDirPaths, () => Directory.EnumerateDirectories(dirPath, "*", SearchOption.AllDirectories)))
{
foreach (var subDirPath in subDirPaths)
{
path = Path.Combine(subDirPath, fileName);
if (File.Exists(path) && MiscHelpers.Try(out assemblyName, () => AssemblyName.GetAssemblyName(path)))
{
return assemblyName.FullName;
}
}
}
// ReSharper restore AccessToModifiedClosure
}
return name;
}
public static Assembly TryLoad(AssemblyName name)
{
if (MiscHelpers.Try(out var assembly, () => Assembly.Load(name)))
{
return assembly;
}
return null;
}
public static T GetAttribute(this Assembly assembly, bool inherit) where T : Attribute
{
return Attribute.GetCustomAttributes(assembly, typeof(T), inherit).SingleOrDefault() as T;
}
public static IEnumerable GetAttributes(this Assembly assembly, bool inherit) where T : Attribute
{
return Attribute.GetCustomAttributes(assembly, typeof(T), inherit).OfType();
}
public static bool IsFriendOf(this Assembly thisAssembly, Assembly thatAssembly)
{
if (thatAssembly == thisAssembly)
{
return true;
}
var thisName = thisAssembly.GetName();
foreach (var attribute in thatAssembly.GetAttributes(false))
{
var thatName = new AssemblyName(attribute.AssemblyName);
if (AssemblyName.ReferenceMatchesDefinition(thatName, thisName))
{
return true;
}
}
return false;
}
public static IEnumerable GetReferencedEnums(this Assembly assembly)
{
var processedTypes = new HashSet();
return assembly.GetAllTypes().SelectMany(type => GetReferencedEnums(assembly, type, processedTypes));
}
private static IEnumerable GetReferencedEnums(Assembly assembly, Type type, HashSet processedTypes)
{
if ((type == null) || !type.IsVisible || type.ContainsGenericParameters || processedTypes.Contains(type))
{
yield break;
}
processedTypes.Add(type);
if (type.IsEnum)
{
yield return type;
yield break;
}
foreach (var enumType in GetReferencedEnums(assembly, type.GetElementType(), processedTypes))
{
yield return enumType;
}
foreach (var enumType in type.GetGenericArguments().SelectMany(argType => GetReferencedEnums(assembly, argType, processedTypes)))
{
yield return enumType;
}
foreach (var enumType in GetReferencedEnums(assembly, type.BaseType, processedTypes))
{
yield return enumType;
}
foreach (var enumType in type.GetInterfaces().SelectMany(interfaceType => GetReferencedEnums(assembly, interfaceType, processedTypes)))
{
yield return enumType;
}
if (type.Assembly == assembly)
{
foreach (var enumType in type.GetMembers().SelectMany(member => GetReferencedEnums(assembly, member, processedTypes)))
{
yield return enumType;
}
}
}
private static IEnumerable GetReferencedEnums(Assembly assembly, MemberInfo member, HashSet processedTypes)
{
if (member == null)
{
return Enumerable.Empty();
}
if (member.MemberType == MemberTypes.Field)
{
return GetReferencedEnums(assembly, (FieldInfo)member, processedTypes);
}
if (member.MemberType == MemberTypes.Property)
{
return GetReferencedEnums(assembly, (PropertyInfo)member, processedTypes);
}
if (member.MemberType == MemberTypes.Method)
{
return GetReferencedEnums(assembly, (MethodInfo)member, processedTypes);
}
if (member.MemberType == MemberTypes.NestedType)
{
return GetReferencedEnums(assembly, (Type)member, processedTypes);
}
return Enumerable.Empty();
}
private static IEnumerable GetReferencedEnums(Assembly assembly, FieldInfo field, HashSet processedTypes)
{
if (field == null)
{
return Enumerable.Empty();
}
return GetReferencedEnums(assembly, field.FieldType, processedTypes);
}
private static IEnumerable GetReferencedEnums(Assembly assembly, PropertyInfo property, HashSet processedTypes)
{
if (property == null)
{
yield break;
}
foreach (var enumType in GetReferencedEnums(assembly, property.PropertyType, processedTypes))
{
yield return enumType;
}
foreach (var enumType in GetReferencedEnums(assembly, property.GetMethod, processedTypes))
{
yield return enumType;
}
foreach (var enumType in GetReferencedEnums(assembly, property.SetMethod, processedTypes))
{
yield return enumType;
}
}
private static IEnumerable GetReferencedEnums(Assembly assembly, MethodInfo method, HashSet processedTypes)
{
if (method == null)
{
yield break;
}
foreach (var enumType in GetReferencedEnums(assembly, method.ReturnParameter, processedTypes))
{
yield return enumType;
}
foreach (var enumType in method.GetParameters().SelectMany(param => GetReferencedEnums(assembly, param, processedTypes)))
{
yield return enumType;
}
}
private static IEnumerable GetReferencedEnums(Assembly assembly, ParameterInfo param, HashSet processedTypes)
{
if (param == null)
{
return Enumerable.Empty();
}
return GetReferencedEnums(assembly, param.ParameterType, processedTypes);
}
}
}