Internal
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
}
}