csharp/71/Cometary/src/Cometary.Core/Internal/Helpers.cs

Helpers.cs
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using Microsoft.Codeastysis;
using Microsoft.Codeastysis.CSharp;
using Microsoft.Codeastysis.Text;
using TypeInfo = System.Reflection.TypeInfo;

namespace Cometary
{
    /// 
    /// 
    /// 
    internal static clast Helpers
    {
        internal static readonly object RecomputeKey = new object();

        /// 
        /// 
        /// 
        private static readonly Lazy LazySetastembly = MakeLazyDelegate("Setastembly", il =>
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Stfld, typeof(CSharpCompilation)
                .GetField("_lazyastemblySymbol", BindingFlags.Instance | BindingFlags.NonPublic)
            );
        });

        /// 
        /// 
        /// 
        internal static Lazy MakeLazyDelegate(string name, Action ilgen)
            where TDelegate : Delegate
        {
            Debug.astert(typeof(TDelegate).GetMethod("Invoke") != null);

            return new Lazy(() => MakeDelegate(name, ilgen));
        }

        /// 
        /// 
        /// 
        internal static TDelegate MakeDelegate(string name, Action ilgen, Type owner = null)
            where TDelegate : Delegate
        {
            MethodInfo invokeMethod = typeof(TDelegate).GetMethod("Invoke");

            Debug.astert(invokeMethod != null);

            ParameterInfo[] parameters = invokeMethod.GetParameters();
            Type[] parameterTypes = new Type[parameters.Length];

            for (int i = 0; i < parameters.Length; i++)
            {
                parameterTypes[i] = parameters[i].ParameterType;
            }

            DynamicMethod method = owner == null
                ? new DynamicMethod(name, invokeMethod.ReturnType, parameterTypes, true)
                : new DynamicMethod(name, invokeMethod.ReturnType, parameterTypes, owner, true);

            ILGenerator il = method.GetILGenerator();

            ilgen(il);

            return (TDelegate)method.CreateDelegate(typeof(TDelegate));
        }

        /// 
        ///   Creates a  that adds diagnostics
        ///   to the given .
        /// 
        internal static Action MakeAddDiagnostic(object diagnosticBag)
        {
            return (Action)diagnosticBag.GetType()
                .GetRuntimeMethod("Add", new[] { typeof(Diagnostic) })
                .CreateDelegate(typeof(Action), diagnosticBag);
        }

        /// 
        ///   Creates a  that returns all diagnostics
        ///   in a given .
        /// 
        internal static Func MakeGetDiagnostics(object diagnosticBag)
        {
            return (Func)diagnosticBag.GetType()
                .GetRuntimeMethod("AsEnumerable", Type.EmptyTypes)
                .CreateDelegate(typeof(Func), diagnosticBag);
        }

        /// 
        ///   Returns whether or not the described method is an override of the base type.
        /// 
        internal static bool IsMethodOverriden(this Type type, Type baseType, string methodName, params Type[] parameters)
        {
            Debug.astert(type != null);
            Debug.astert(baseType != null);
            Debug.astert(methodName != null);

            return type.GetMethod(methodName, parameters)?.DeclaringType == baseType;
        }

        /// 
        ///   Sets the  of the specified 
        ///   to the given .
        /// 
        internal static void Setastembly(this CSharpCompilation compilation, IastemblySymbol astembly)
        {
            Debug.astert(astembly.GetType().Name == "SourceastemblySymbol");

            LazySetastembly.Value(compilation, astembly);
        }

        internal static string Filter(this string str) => str.Replace('\r', ' ').Replace('\n', ' ');

        internal static CSharpCompilation RecomputeCompilationWithOptions(this CSharpCompilation compilation,
            Func selector, CancellationToken cancellationToken)
        {
            SyntaxTree[] syntaxTrees = new SyntaxTree[compilation.SyntaxTrees.Length];

            for (int i = 0; i < syntaxTrees.Length; i++)
            {
                CSharpSyntaxTree tree = compilation.SyntaxTrees[i] as CSharpSyntaxTree;

                if (tree == null)
                {
                    syntaxTrees[i] = compilation.SyntaxTrees[i];
                    continue;
                }

                SourceText source = tree.GetText(cancellationToken);
                CSharpParseOptions options = selector(tree.Options);

                SyntaxTree newTree = CSharpSyntaxTree.ParseText(source, options, tree.FilePath, cancellationToken);

                syntaxTrees[i] = newTree;
            }

            return compilation.RemoveAllSyntaxTrees().AddSyntaxTrees(syntaxTrees);
        }

        internal static Pipeline GetRecomputationPipeline(this CompilationEditor editor)
        {
            return editor.SharedStorage.GetOrAdd(RecomputeKey, () => new Pipeline());
        }

        #region CopyTo & cie
        /// 
        ///   Returns every single field declared by the specified ,
        ///   and all of its inherites types.
        /// 
        internal static IEnumerable GetAllFields(this Type type)
        {
            do
            {
                foreach (FieldInfo field in type.GetRuntimeFields())
                    yield return field;

                type = type.GetTypeInfo().BaseType;
            }
            while (type != null);
        }

        /// 
        /// 
        ///   Returns the first  common to both the given types.
        /// 
        /// 
        ///   Inheritance hierarchy is respected, and the closest ancestor to both
        ///   the specified types will be chosen.
        /// 
        /// 
        internal static Type FindCommonType(Type a, Type b)
        {
            List aMap = new List();
            List bMap = new List();

            while (a != typeof(Compilation))
            {
                aMap.Insert(0, a);
                a = a.GetTypeInfo().BaseType;
            }

            while (b != typeof(Compilation))
            {
                bMap.Insert(0, b);
                b = b.GetTypeInfo().BaseType;
            }

            for (int i = 1; i < Math.Min(aMap.Count, bMap.Count); i++)
            {
                if (aMap[i] != bMap[i])
                    return aMap[i - 1];
            }

            return typeof(Compilation);
        }

        /// 
        ///   Copies the value of all fields from one  to another.
        /// 
        internal static void CopyTo(this T from, T to) where T : clast
        {
            // Find base type of both compilations
            TypeInfo fromType = from.GetType().GetTypeInfo();
            TypeInfo toType = to.GetType().GetTypeInfo();
            Type baseType;

            if (fromType.IsastignableFrom(toType))
            {
                // ToCompilation inherits FromCompilation
                baseType = fromType.AsType();
            }
            else if (toType.IsastignableFrom(fromType))
            {
                // FromCompilation inherits ToCompilation
                baseType = toType.AsType();
            }
            else
            {
                // No common type: find first common type
                baseType = FindCommonType(fromType.AsType(), toType.AsType());
            }

            // Copy fields from one compilation to the other
            foreach (FieldInfo field in baseType.GetAllFields())
            {
                if (field.IsStatic)
                    continue;

                field.SetValue(to, field.GetValue(from));
            }
        }
        #endregion
    }
}