/// <summary> /// Generates an assembly from a source and a minimal list of required reference assemblies. /// </summary> /// <param name="code">The source code.</param> /// <param name="assemblyPath">The full final assembly path (including the .dll extension). Can be null if skipCompilation is true.</param> /// <param name="skipCompilation">True to skip the compilation. Only the parsing and the source generation is done.</param> /// <param name="loader">Optional loader function to load the final emitted assembly.</param> /// <returns>Encapsulation of the result.</returns> public GenerateResult Generate(ICodeWorkspace code, string assemblyPath, bool skipCompilation, Func <string, Assembly>?loader = null) { if (code == null) { throw new ArgumentNullException(nameof(code)); } using (var weakLoader = WeakAssemblyNameResolver.TemporaryInstall()) { var input = GeneratorInput.Create(_workspaceFactory, code, Modules, !skipCompilation && AutoRegisterRuntimeAssembly, ParseOptions); Modules.Clear(); if (skipCompilation) { return(new GenerateResult(input.Trees)); } var collector = new HashSet <Assembly>(); foreach (var a in input.Assemblies) { if (collector.Add(a)) { Discover(a, collector); } } return(Generate(CompilationOptions, input.Trees, assemblyPath, collector.Select(a => MetadataReference.CreateFromFile(new Uri(a.Location).LocalPath)), loader) .WithLoadFailures(weakLoader.Conflicts)); } }
public void Inject(ICodeWorkspace code) { code.Global .EnsureUsing("System") .CreateType("public static class RealDBNull") .Append("public static object V = DBNull.Value;").NewLine(); }
public void BuildGenericMethods() { ICodeWorkspace workspace = CodeWorkspace.Create(); INamespaceScope global = workspace.Global; INamespaceScope b = global.FindOrCreateNamespace("CK._g"); Type t = typeof(ContainsGenericMethods <>); workspace.EnsureAssemblyReference(t); b.EnsureUsing(t.Namespace); var c = b.CreateType(header => header.Append("class Specialized<T> : ").AppendCSharpName(t, true, true, true).NewLine()); c.CreateOverride(t.GetMethod("Simple1")) .Append("if (arg.Equals(default(T))) throw new System.ArgumentException();").NewLine() .Append("return default(TResult);"); c.CreateOverride(t.GetMethod("Simple2")) .Append("=> arg2 is T1;"); Assembly a = TestHelper.CreateAssembly(workspace.GetGlobalSource(), workspace.AssemblyReferences); Type tC = a.GetTypes().Single(n => n.Name == "Specialized`1").MakeGenericType(typeof(int)); ContainsGenericMethods <int> gotIt = (ContainsGenericMethods <int>)Activator.CreateInstance(tC); gotIt.Simple1 <bool>(25).Should().BeFalse(); gotIt.Simple2(new object(), "test").Should().BeTrue(); }
public CodeProjectImpl(string projectName, ICodeWorkspace code) { Code = code; ProjectName = projectName; TargetFrameworks = new HashSet <string>(); Sdk = "Microsoft.NET.Sdk"; PackageReferences = new List <PackageReference>(); }
public void using_alias_are_a_bit_normalized_by_removing_white_spaces() { ICodeWorkspace workspace = CreateWorkspace(); INamespaceScope global = workspace.Global; INamespaceScope nAXa = global.FindOrCreateNamespace("A.X.a"); INamespaceScope nAXb = global.FindOrCreateNamespace("A.X.b"); INamespaceScope nAX = global.FindOrCreateNamespace("A.X"); INamespaceScope nA = global.FindOrCreateNamespace("A"); global.EnsureUsingAlias("INT", "System.UInt8"); nAXa.EnsureUsingAlias("INT", "System . UInt8"); ExtractNamespaces(global).Should().OnlyContain(x => x == "INT"); ExtractNamespaces(nAXa).Should().BeEmpty(); var source = workspace.GetGlobalSource(); Normalize(source).Should().Be(Normalize( @"namespace A { using INT = System.UInt8; namespace X { namespace a { } namespace b { } } }" )); global.EnsureUsingAlias("CNode", "SNode<string,bool>"); nAXa.EnsureUsingAlias("CNode", "SNode<STRING, BOOL>"); nAXa.Append("// The 2 CNode definition differ.").NewLine(); ExtractNamespaces(global).Should().HaveCount(2).And.OnlyContain(x => x == "INT" || x == "CNode"); ExtractNamespaces(nAXa).Should().OnlyContain(x => x == "CNode"); global.FindOrCreateNamespace("ToShowTheTopLevelUsingsCopy"); source = workspace.GetGlobalSource(); Normalize(source).Should().Be(Normalize( @"namespace A { using INT = System.UInt8; using CNode = SNode<string,bool>; namespace X { namespace a { using CNode = SNode<STRING, BOOL>; // The 2 CNode definition differ. } namespace b { } } } namespace ToShowTheTopLevelUsingsCopy { using INT = System.UInt8; using CNode = SNode<string,bool>; }" )); }
public void Inject(ICodeWorkspace code) { code.Global .EnsureUsing("System") .EnsureUsing("System.Reflection") .Append( @"static class CKFixDBNull { // This was the original required code (before netcoreapp2.0): // public static object Value = typeof( object ).Assembly.GetType( ""System.DBNull"" ).GetField( ""Value"" ).GetValue( null ); // Here we use a stupid value for the demo. public static object Value = ""I'm the DBNull.""; }"); }
public void MergeWith(ICodeWorkspace other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } if (other != this) { foreach (var a in other.AssemblyReferences) { _assemblies.Add(a); } Global.MergeWith((NamespaceScopeImpl)other.Global); } }
public void BaseTest() { ICodeWorkspace workspace = CodeWorkspace.Create(); INamespaceScope global = workspace.Global; INamespaceScope b = global.FindOrCreateNamespace("CK._g"); Type t = typeof(BaseToBeOverridden); workspace.EnsureAssemblyReference(t); b.EnsureUsing("System") .EnsureUsing("System.Collections.Generic") .EnsureUsing(t.Namespace); var c = b.CreateType(h => h.Append("class Specialized : ").AppendCSharpName(t, true, true, true)); c.CreatePassThroughConstructors(t); c.CreateOverride(t.GetMethod("Simple1")) .Append("=> 3712;"); c.CreateOverride(t.GetMethod("VoidMethod")); c.CreateOverride(t.GetMethod("Simple2", BindingFlags.Instance | BindingFlags.NonPublic)) .Append("=> x + '-' + g.ToString();"); c.CreateOverride(t.GetMethod("Simple3", BindingFlags.Instance | BindingFlags.NonPublic)) .Append("g = Guid.NewGuid();").NewLine() .Append(@"x = ""Hello World!"" + Simple2( ""YES"", g );").NewLine() .Append("return this;"); c.CreateOverride(t.GetMethod("VerbatimParameters", BindingFlags.Instance | BindingFlags.NonPublic)).Append(" => @this + @operator;"); Assembly a = TestHelper.CreateAssembly(workspace.GetGlobalSource(), workspace.AssemblyReferences); Type tC = a.GetTypes().Single(n => n.Name == "Specialized"); BaseToBeOverridden gotIt = (BaseToBeOverridden)Activator.CreateInstance(tC, new object[] { 3712 * 3712 }); gotIt.ValFromCtor.Should().Be(3712 * 3712); gotIt.Simple1().Should().Be(3712); string s; Guid g = Guid.Empty; gotIt.Simple3(out s, ref g, 9).Should().BeSameAs(gotIt); s.Should().Be("Hello World!YES-" + g.ToString()); g.Should().NotBeEmpty(); }
/// <summary> /// Combines code workspaces and modules into a <see cref="GeneratorInput"/>. /// </summary> /// <param name="workspaceFactory">Factory for <see cref="ICodeWorkspace"/> implementations. Must not be null.</param> /// <param name="code">Original code. Can be null or empty.</param> /// <param name="modules">Code modules. Can be null or empty.</param> /// <param name="addRuntimeAssembly">True to automatically add the typeof(object)'s assembly.</param> /// <param name="options">The optional parse options to use.</param> /// <returns>A generator input.</returns> internal static GeneratorInput Create( Func <ICodeWorkspace> workspaceFactory, ICodeWorkspace code, IEnumerable <ICodeGeneratorModule> modules, bool addRuntimeAssembly, CSharpParseOptions?options) { Debug.Assert(workspaceFactory != null); var assemblies = new HashSet <Assembly>(); if (addRuntimeAssembly) { assemblies.Add(typeof(object).Assembly); } var trees = new List <SyntaxTree>(); if (code != null) { CombineWorkspace(assemblies, trees, code, options); } if (modules != null) { foreach (var m in modules) { var transformed = m.Rewrite(trees); if (transformed != null && transformed != trees) { trees.Clear(); trees.AddRange(transformed); } var wM = workspaceFactory(); m.Inject(wM); CombineWorkspace(assemblies, trees, wM, options); } } return(new GeneratorInput(assemblies, trees)); }
public void SqlTest() { ICodeWorkspace workspace = CodeWorkspace.Create(); INamespaceScope global = workspace.Global; INamespaceScope b = global.FindOrCreateNamespace("CK._g"); workspace.EnsureAssemblyReference(typeof(SqlCommand), typeof(SimpleBase)); b.EnsureUsing("System") .EnsureUsing("System.Collections.Generic") .EnsureUsing("Microsoft.Data.SqlClient"); var type = b.CreateType(w => w.Append("public class GGGG : ").AppendCSharpName(typeof(SimpleBase), true, true, true)); type.CreateOverride(typeof(SimpleBase).GetMethod("Do")) .Append( @"if( i.HasValue ) { i *= i; } var c = new SqlCommand(""p""+i.ToString()); var p = c.Parameters.AddWithValue(""@i"", (object)i ?? DBNull.Value); return c;"); var source = workspace.GetGlobalSource(); var references = workspace.AssemblyReferences; Assembly a = TestHelper.CreateAssembly(source, references); Type t = a.GetTypes().Single(n => n.Name == "GGGG"); SimpleBase gotIt = (SimpleBase)Activator.CreateInstance(t); int? k = 67; SqlCommand cmd = gotIt.Do(ref k); k.Should().Be(67 * 67); cmd.CommandText.Should().Be("p" + k); cmd.Parameters.Cast <SqlParameter>().Single().Value.Should().Be(k); }
static void CombineWorkspace(HashSet <Assembly> assemblies, List <SyntaxTree> trees, ICodeWorkspace c, CSharpParseOptions?options) { foreach (var a in c.AssemblyReferences) { assemblies.Add(a); } var s = c.GetGlobalSource(); if (!String.IsNullOrWhiteSpace(s)) { trees.Add(SyntaxFactory.ParseSyntaxTree(s, options)); } }
/// <summary> /// Writes the current <see cref="ICodeWorkspace.Global">Global</see> source code into a <see cref="TextWriter"/>. /// </summary> /// <param name="this">This wokspace.</param> /// <param name="w">Target TextWriter.</param> public static void WriteGlobalSource(this ICodeWorkspace @this, TextWriter w) { @this.Global.Build(w.Write, true); }
/// <summary> /// Gets the current <see cref="ICodeWorkspace.Global">Global</see> source code. /// This is the same as calling ToString() on the Global namespace. /// </summary> /// <param name="this">This wokspace.</param> /// <returns>The current code source for this workspace.</returns> public static string GetGlobalSource(this ICodeWorkspace @this) { return(@this.Global.Build(new StringBuilder(), true).ToString()); }
public Tracker(ICodeWorkspace w) { w.NamespaceCreated += OnNamespaceCreated; w.TypeCreated += OnTypeCreated; w.FunctionCreated += OnFunctionCreated; }