/// <summary> /// Generates the assembly from the specified importing options. /// </summary> /// <param name="options">The importing options.</param> internal ImportUserTypeAssembly GenerateAssembly(ImportUserTypeOptions options) { // Generate CodeGen configuration string assemblyPath = Path.Combine(Path.GetTempPath(), "CsDebugScript.CodeGen.Assemblies", Guid.NewGuid().ToString() + ".dll"); XmlConfig codeGenConfig = ConvertOptionsToCodeGenConfig(options); codeGenConfig.GeneratedAssemblyName = assemblyPath; // Execute code generation IModuleProvider moduleProvider = new EngineSymbolProviderModuleProvider(Process.Current); Generator generator = new Generator(moduleProvider); byte[] assemblyBytes = generator.GenerateAssembly(codeGenConfig); Directory.CreateDirectory(Path.GetDirectoryName(assemblyPath)); File.WriteAllBytes(assemblyPath, assemblyBytes); // Add generated file to be loaded after execution return(new ImportUserTypeAssembly() { AssemblyBytes = assemblyBytes, AssemblyPath = assemblyPath, Options = options, }); }
/// <summary> /// Converts the importing options to CodeGen configuration. /// </summary> /// <param name="options">The importing options.</param> /// <returns>CodeGen configuration</returns> private static XmlConfig ConvertOptionsToCodeGenConfig(ImportUserTypeOptions options) { // User types List <XmlType> types = new List <XmlType>(); foreach (string userTypeName in options.UserTypes) { types.Add(new XmlType() { Name = userTypeName, ExportDependentTypes = options.ImportDependentTypes, }); } // Modules List <XmlModule> modules = new List <XmlModule>(); foreach (string moduleName in options.Modules) { Module module = Module.All.First(m => m.Name == moduleName); string symbolsPath = Context.SymbolProvider.GetModuleSymbolsPath(module); if (!File.Exists(symbolsPath)) { continue; } modules.Add(new XmlModule() { Name = moduleName, SymbolsPath = symbolsPath, }); } // Check if we are using direct class access. bool useDirectClassAccess = !(Context.SymbolProvider is DbgEngSymbolProvider); // Create configuration return(new XmlConfig() { Types = types.ToArray(), Modules = modules.ToArray(), UseDirectClassAccess = useDirectClassAccess, CompressedOutput = true, ForceUserTypesToNewInsteadOfCasting = true, GeneratePhysicalMappingOfUserTypes = useDirectClassAccess, MultiFileExport = false, Transformations = DefaultTransformations, GenerateAssemblyWithILWriter = options.UseILCodeWriter, }); }
/// <summary> /// Normalizes specified source path with respect to base file path. /// </summary> /// <param name="path">The source path to normalize. May be absolute or relative.</param> /// <param name="baseFilePath">Path of the source file that contains the <paramref name="path" /> (may also be relative), or null if not available.</param> /// <returns> /// Normalized path, or null if <paramref name="path" /> can't be normalized. The resulting path doesn't need to exist. /// </returns> public override string NormalizePath(string path, string baseFilePath) { // Try to see if it is import user type options ImportUserTypeOptions options = ImportUserTypeOptions.ParseString(path); if (options != null) { return(options.Serialize()); } // Normalize path string result = originalSourceResolver.NormalizePath(path, baseFilePath); return(result); }
/// <summary> /// Imports user types from modules using the specified importing options. /// </summary> /// <param name="options">The importing options.</param> /// <param name="asAssembly">If set to <c>true</c> user types will be imported as assembly. If set to <c>false</c> user types will be imported as script code.</param> public void ImportUserTypes(ImportUserTypeOptions options, bool asAssembly = false) { if (asAssembly) { ImportUserTypeAssembly assembly = _AssemblyResolver_.GenerateAssembly(options); _CodeGenAssemblies_.Add(assembly); } else { ImportUserTypeCode code = _CodeResolver_.GenerateCode(options); _CodeGenCode_.Add(code); } }
/// <summary> /// Generates the code from the specified importing options. /// </summary> /// <param name="options">The importing options.</param> internal ImportUserTypeCode GenerateCode(ImportUserTypeOptions options) { XmlConfig codeGenConfig = ConvertOptionsToCodeGenConfig(options); codeGenConfig.GenerateNamespaceAsStaticClass = true; // Execute code generation IModuleProvider moduleProvider = new EngineSymbolProviderModuleProvider(Process.Current); Generator generator = new Generator(moduleProvider); string code = generator.GenerateScriptCode(codeGenConfig); // Add generated code to be loaded after execution return(new ImportUserTypeCode() { Code = code, Options = options, }); }
/// <summary> /// Converts the importing options to CodeGen configuration. /// </summary> /// <param name="options">The importing options.</param> /// <returns>CodeGen configuration</returns> private static XmlConfig ConvertOptionsToCodeGenConfig(ImportUserTypeOptions options) { // User types List <XmlType> types = new List <XmlType>(); foreach (string userTypeName in options.UserTypes) { types.Add(new XmlType() { Name = userTypeName, ExportDependentTypes = options.ImportDependentTypes, }); } // Modules List <XmlModule> modules = new List <XmlModule>(); foreach (string moduleName in options.Modules) { modules.Add(new XmlModule() { Name = moduleName, PdbPath = Module.All.First(m => m.Name == moduleName).SymbolFileName, }); } // Check if we are using DIA as symbol provider bool useDia = Context.SymbolProvider is DiaSymbolProvider; // Create configuration return(new XmlConfig() { Types = types.ToArray(), Modules = modules.ToArray(), UseDiaSymbolProvider = useDia, CompressedOutput = true, ForceUserTypesToNewInsteadOfCasting = true, GeneratePhysicalMappingOfUserTypes = useDia, MultiFileExport = false, Transformations = DefaultTransformations, }); }
/// <summary> /// Opens a <see cref="T:System.IO.Stream" /> that allows reading the content of the specified file. /// </summary> /// <param name="resolvedPath">Path returned by <see cref="M:Microsoft.CodeAnalysis.SourceReferenceResolver.ResolveReference(System.String,System.String)" />.</param> /// <returns></returns> public override Stream OpenRead(string resolvedPath) { ImportUserTypeCode code; if (codeGenCode.TryGetValue(resolvedPath, out code)) { return(new MemoryStream(Encoding.UTF8.GetBytes(code.Code))); } ImportUserTypeOptions options = ImportUserTypeOptions.ParseString(resolvedPath); if (options != null) { code = GenerateCode(options); AddCode(code); return(new MemoryStream(Encoding.UTF8.GetBytes(code.Code))); } return(originalSourceResolver.OpenRead(resolvedPath)); }
/// <summary> /// Resolves specified path with respect to base file path. /// </summary> /// <param name="path">The path to resolve. May be absolute or relative.</param> /// <param name="baseFilePath">Path of the source file that contains the <paramref name="path" /> (may also be relative), or null if not available.</param> /// <returns> /// Normalized path, or null if the file can't be resolved. /// </returns> public override string ResolveReference(string path, string baseFilePath) { // Try to see if it is import user type options ImportUserTypeOptions options = ImportUserTypeOptions.ParseString(path); if (options != null) { return(options.Serialize()); } // Do resolve reference string result = originalSourceResolver.ResolveReference(path, baseFilePath); if (string.IsNullOrEmpty(result)) { result = ResolvePath(path, baseFilePath); } return(result); }
/// <summary> /// Resolves the reference. /// </summary> /// <param name="reference">The reference.</param> /// <param name="baseFilePath">The base file path.</param> /// <param name="properties">The properties.</param> /// <returns></returns> public override ImmutableArray <PortableExecutableReference> ResolveReference(string reference, string baseFilePath, MetadataReferenceProperties properties) { // Check if we are referencing CodeGen assembly ImportUserTypeAssembly codeGenAssembly; if (codeGenAssemblies.TryGetValue(reference, out codeGenAssembly)) { using (MemoryStream stream = new MemoryStream(codeGenAssembly.AssemblyBytes)) { return(ImmutableArray.Create(MetadataReference.CreateFromStream(stream, properties, null, codeGenAssembly.AssemblyPath))); } } // Check the previous resolver var result = previousResolver.ResolveReference(reference, baseFilePath, properties); if (result.Length > 0) { return(result); } // Try to use file resolver try { string path = ResolvePath(reference, baseFilePath); if (!string.IsNullOrEmpty(path)) { return(ImmutableArray.Create(MetadataReference.CreateFromFile(path, properties))); } } catch { } // Check if reference holds xml for CodeGen ImportUserTypeOptions options = ImportUserTypeOptions.ParseString(reference); if (options != null) { foreach (ImportUserTypeAssembly assembly in codeGenAssemblies.Values) { if (assembly.Options.Equals(options)) { // TODO: Compare that used PDBs have same GUID. codeGenAssembly = assembly; break; } } if (codeGenAssembly == null) { codeGenAssembly = GenerateAssembly(options); AddAssembly(codeGenAssembly); } using (MemoryStream stream = new MemoryStream(codeGenAssembly.AssemblyBytes)) { return(ImmutableArray.Create(MetadataReference.CreateFromStream(stream, properties, null, codeGenAssembly.AssemblyPath))); } } return(ImmutableArray <PortableExecutableReference> .Empty); }