Ejemplo n.º 1
0
        /// <summary>
        /// Generates source code for the provided assembly.
        /// </summary>
        /// <param name="input">
        /// The assembly to generate source for.
        /// </param>
        /// <returns>
        /// The generated source.
        /// </returns>
        public string GenerateSourceForAssembly(Assembly input)
        {
            if (input.GetCustomAttribute <GeneratedCodeAttribute>() != null ||
                input.GetCustomAttribute <SkipCodeGenerationAttribute>() != null)
            {
                return(string.Empty);
            }

            var generated = this.GenerateCode(input, new[] { input }.ToList());

            if (generated.Syntax == null)
            {
                return(string.Empty);
            }

            return(CodeGeneratorCommon.GenerateSourceCode(CodeGeneratorCommon.AddGeneratedCodeAttribute(generated)));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Generates source code for the provided assembly.
        /// </summary>
        /// <param name="input">
        /// The assembly to generate source for.
        /// </param>
        /// <returns>
        /// The generated source.
        /// </returns>
        public string GenerateSourceForAssembly(Assembly input)
        {
            if (!ShouldGenerateCodeForAssembly(input))
            {
                return(string.Empty);
            }

            var generated = GenerateForAssemblies(new List <Assembly> {
                input
            }, false);

            if (generated.Syntax == null)
            {
                return(string.Empty);
            }

            return(CodeGeneratorCommon.GenerateSourceCode(CodeGeneratorCommon.AddGeneratedCodeAttribute(generated)));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generates source code for the provided assembly.
        /// </summary>
        /// <param name="input">
        /// The assembly to generate source for.
        /// </param>
        /// <returns>
        /// The generated source.
        /// </returns>
        public string GenerateSourceForAssembly(Assembly input)
        {
            RegisterGeneratedCodeTargets(input);

            if (input.GetCustomAttribute <GeneratedCodeAttribute>() != null ||
                input.GetCustomAttribute <SkipCodeGenerationAttribute>() != null)
            {
                return(string.Empty);
            }

            var generated = GenerateForAssemblies(new List <Assembly> {
                input
            }, false);

            if (generated.Syntax == null)
            {
                return(string.Empty);
            }

            return(CodeGeneratorCommon.GenerateSourceCode(CodeGeneratorCommon.AddGeneratedCodeAttribute(generated)));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Generates and compiles an assembly for the provided syntax.
        /// </summary>
        /// <param name="generatedSyntax">
        /// The generated code.
        /// </param>
        /// <param name="assemblyName">
        /// The name for the generated assembly.
        /// </param>
        /// <param name="emitDebugSymbols">
        /// Whether or not to emit debug symbols for the generated assembly.
        /// </param>
        /// <returns>
        /// The raw assembly.
        /// </returns>
        /// <exception cref="CodeGenerationException">
        /// An error occurred generating code.
        /// </exception>
        private Assembly CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName, bool emitDebugSymbols)
        {
            // Add the generated code attribute.
            var code = CodeGeneratorCommon.AddGeneratedCodeAttribute(generatedSyntax);

            // Reference everything which can be referenced.
            var assemblies =
                AppDomain.CurrentDomain.GetAssemblies()
                .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location))
                .Select(asm => MetadataReference.CreateFromFile(asm.Location))
                .Cast <MetadataReference>()
                .ToArray();

            // Generate the code.
            var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

#if NETSTANDARD2_0
            // CoreFX bug https://github.com/dotnet/corefx/issues/5540
            // to workaround it, we are calling internal WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes)
            // TODO: this API will be public in the future releases of Roslyn.
            // This work is tracked in https://github.com/dotnet/roslyn/issues/5855
            // Once it's public, we should replace the internal reflection API call by the public one.
            var method = typeof(CSharpCompilationOptions).GetMethod("WithTopLevelBinderFlags", BindingFlags.NonPublic | BindingFlags.Instance);
            // we need to pass BinderFlags.IgnoreCorLibraryDuplicatedTypes, but it's an internal class
            // http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Binder/BinderFlags.cs,00f268571bb66b73
            options = (CSharpCompilationOptions)method.Invoke(options, new object[] { 1u << 26 });
#endif

            string source = null;
            if (this.logger.IsEnabled(LogLevel.Debug))
            {
                source = CodeGeneratorCommon.GenerateSourceCode(code);

                // Compile the code and load the generated assembly.
                this.logger.Debug(
                    ErrorCode.CodeGenSourceGenerated,
                    "Generating assembly {0} with source:\n{1}",
                    assemblyName,
                    source);
            }

            var compilation =
                CSharpCompilation.Create(assemblyName)
                .AddSyntaxTrees(code.SyntaxTree)
                .AddReferences(assemblies)
                .WithOptions(options);

            using (var outputStream = new MemoryStream())
            {
                var emitOptions = new EmitOptions()
                                  .WithEmitMetadataOnly(false)
                                  .WithIncludePrivateMembers(true);

                if (emitDebugSymbols)
                {
                    emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.Embedded);
                }

                var compilationResult = compilation.Emit(outputStream, options: emitOptions);
                if (!compilationResult.Success)
                {
                    source = source ?? CodeGeneratorCommon.GenerateSourceCode(code);
                    var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString()));
                    this.logger.Warn(
                        ErrorCode.CodeGenCompilationFailed,
                        "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}",
                        assemblyName,
                        errors,
                        source);
                    throw new CodeGenerationException(errors);
                }

                this.logger.Debug(
                    ErrorCode.CodeGenCompilationSucceeded,
                    "Compilation of assembly {0} succeeded.",
                    assemblyName);
                return(Assembly.Load(outputStream.ToArray()));
            }
        }