Example #1
0
        public static List <string> GetPreprocessorSymbols(CSharpCompilerOptions flags)
        {
            var preprocessorSymbols = new List <string>();

            if (flags.HasFlag(CSharpCompilerOptions.UseDebug))
            {
                preprocessorSymbols.Add("DEBUG");
            }
            if (flags.HasFlag(CSharpCompilerOptions.Optimize))
            {
                preprocessorSymbols.Add("OPT");
            }
            if (flags.HasFlag(CSharpCompilerOptions.UseRoslyn))
            {
                preprocessorSymbols.Add("ROSLYN");
                preprocessorSymbols.Add("CS60");
                preprocessorSymbols.Add("CS70");
                preprocessorSymbols.Add("CS71");
                preprocessorSymbols.Add("CS72");
            }
            else if (flags.HasFlag(CSharpCompilerOptions.UseMcs))
            {
                preprocessorSymbols.Add("MCS");
            }
            else
            {
                preprocessorSymbols.Add("LEGACY_CSC");
            }
            return(preprocessorSymbols);
        }
Example #2
0
        void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CSharpCompilerOptions cscOptions = CSharpCompilerOptions.None, DecompilerSettings decompilerSettings = null)
        {
            var ilFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".il";
            var csFile = Path.Combine(TestCasePath, testName + ".cs");

            if (!File.Exists(ilFile))
            {
                // re-create .il file if necessary
                CompilerResults output = null;
                try {
                    string outputFile = Path.ChangeExtension(ilFile,
                                                             cscOptions.HasFlag(CSharpCompilerOptions.Library) ? ".dll" : ".exe");
                    output = Tester.CompileCSharp(csFile, cscOptions, outputFile);
                    Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions);
                } finally {
                    if (output != null)
                    {
                        output.TempFiles.Delete();
                    }
                }
            }

            var executable = Tester.AssembleIL(ilFile, asmOptions);
            var decompiled = Tester.DecompileCSharp(executable, decompilerSettings ?? Tester.GetSettings(cscOptions));

            CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray());
        }
Example #3
0
 public void MiniJSON([ValueSource("defaultOptions")] CSharpCompilerOptions options)
 {
     if (options.HasFlag(CSharpCompilerOptions.UseMcs))
     {
         Assert.Ignore("Decompiler bug with mono!");
     }
     RunCS(options: options);
 }
Example #4
0
 internal static DecompilerSettings GetSettings(CSharpCompilerOptions cscOptions)
 {
     if (cscOptions.HasFlag(CSharpCompilerOptions.UseRoslyn))
     {
         return(new DecompilerSettings(CSharp.LanguageVersion.Latest));
     }
     else
     {
         return(new DecompilerSettings(CSharp.LanguageVersion.CSharp5));
     }
 }
Example #5
0
        void RunCS([CallerMemberName] string testName = null, CSharpCompilerOptions options = CSharpCompilerOptions.UseDebug)
        {
            string          testFileName = testName + ".cs";
            string          testOutputFileName = testName + Tester.GetSuffix(options) + ".exe";
            CompilerResults outputFile = null, decompiledOutputFile = null;

            try {
                outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options,
                                                  outputFileName: Path.Combine(TestCasePath, testOutputFileName));
                string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options));
                if (options.HasFlag(CSharpCompilerOptions.UseMcs))
                {
                    // For second pass, use roslyn instead of mcs.
                    // mcs has some compiler bugs that cause it to not accept ILSpy-generated code,
                    // for example when there's unreachable code due to other compiler bugs in the first mcs run.
                    options &= ~CSharpCompilerOptions.UseMcs;
                    options |= CSharpCompilerOptions.UseRoslyn;
                    // Also, add an .exe.config so that we consistently use the .NET 4.x runtime.
                    File.WriteAllText(outputFile.PathToAssembly + ".config", @"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
	<startup>
		<supportedRuntime version=""v4.0"" sku="".NETFramework,Version=v4.0,Profile=Client"" />
	</startup>
</configuration>");
                }
                decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options);

                Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile);

                File.Delete(decompiledCodeFile);
                File.Delete(decompiledOutputFile.PathToAssembly);
            } finally {
                if (outputFile != null)
                {
                    outputFile.TempFiles.Delete();
                }
                if (decompiledOutputFile != null)
                {
                    decompiledOutputFile.TempFiles.Delete();
                }
            }
        }
Example #6
0
        public static CompilerResults CompileCSharp(string sourceFileName, CSharpCompilerOptions flags = CSharpCompilerOptions.UseDebug, string outputFileName = null)
        {
            List <string> sourceFileNames = new List <string> {
                sourceFileName
            };

            foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)"""))
            {
                sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value)));
            }

            var preprocessorSymbols = GetPreprocessorSymbols(flags);

            if (flags.HasFlag(CSharpCompilerOptions.UseRoslyn))
            {
                var parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols.ToArray(), languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest);
                var syntaxTrees  = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f));
                var compilation  = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(sourceFileName),
                                                            syntaxTrees, defaultReferences.Value,
                                                            new CSharpCompilationOptions(
                                                                flags.HasFlag(CSharpCompilerOptions.Library) ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication,
                                                                platform: flags.HasFlag(CSharpCompilerOptions.Force32Bit) ? Platform.X86 : Platform.AnyCpu,
                                                                optimizationLevel: flags.HasFlag(CSharpCompilerOptions.Optimize) ? OptimizationLevel.Release : OptimizationLevel.Debug,
                                                                allowUnsafe: true,
                                                                deterministic: true
                                                                ));
                CompilerResults results = new CompilerResults(new TempFileCollection());
                results.PathToAssembly = outputFileName ?? Path.GetTempFileName();
                var emitResult = compilation.Emit(results.PathToAssembly);
                if (!emitResult.Success)
                {
                    StringBuilder b = new StringBuilder("Compiler error:");
                    foreach (var diag in emitResult.Diagnostics)
                    {
                        b.AppendLine(diag.ToString());
                    }
                    throw new Exception(b.ToString());
                }
                return(results);
            }
            else if (flags.HasFlag(CSharpCompilerOptions.UseMcs))
            {
                CompilerResults results = new CompilerResults(new TempFileCollection());
                results.PathToAssembly = outputFileName ?? Path.GetTempFileName();
                string testBasePath = RoundtripAssembly.TestDir;
                if (!Directory.Exists(testBasePath))
                {
                    Assert.Ignore($"Compilation with mcs ignored: test directory '{testBasePath}' needs to be checked out separately." + Environment.NewLine +
                                  $"git clone https://github.com/icsharpcode/ILSpy-tests \"{testBasePath}\"");
                }
                string mcsPath      = Path.Combine(testBasePath, @"mcs\2.6.4\bin\gmcs.bat");
                string otherOptions = " -unsafe -o" + (flags.HasFlag(CSharpCompilerOptions.Optimize) ? "+ " : "- ");

                if (flags.HasFlag(CSharpCompilerOptions.Library))
                {
                    otherOptions += "-t:library ";
                }
                else
                {
                    otherOptions += "-t:exe ";
                }

                if (flags.HasFlag(CSharpCompilerOptions.UseDebug))
                {
                    otherOptions += "-g ";
                }

                if (flags.HasFlag(CSharpCompilerOptions.Force32Bit))
                {
                    otherOptions += "-platform:x86 ";
                }
                else
                {
                    otherOptions += "-platform:anycpu ";
                }
                if (preprocessorSymbols.Count > 0)
                {
                    otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" ";
                }

                ProcessStartInfo info = new ProcessStartInfo(mcsPath);
                info.Arguments              = $"{otherOptions}-out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}";
                info.RedirectStandardError  = true;
                info.RedirectStandardOutput = true;
                info.UseShellExecute        = false;

                Console.WriteLine($"\"{info.FileName}\" {info.Arguments}");

                Process process = Process.Start(info);

                var outputTask = process.StandardOutput.ReadToEndAsync();
                var errorTask  = process.StandardError.ReadToEndAsync();

                Task.WaitAll(outputTask, errorTask);
                process.WaitForExit();

                Console.WriteLine("output: " + outputTask.Result);
                Console.WriteLine("errors: " + errorTask.Result);
                Assert.AreEqual(0, process.ExitCode, "mcs failed");
                return(results);
            }
            else
            {
                var provider = new CSharpCodeProvider(new Dictionary <string, string> {
                    { "CompilerVersion", "v4.0" }
                });
                CompilerParameters options = new CompilerParameters();
                options.GenerateExecutable = !flags.HasFlag(CSharpCompilerOptions.Library);
                options.CompilerOptions    = "/unsafe /o" + (flags.HasFlag(CSharpCompilerOptions.Optimize) ? "+" : "-");
                options.CompilerOptions   += (flags.HasFlag(CSharpCompilerOptions.UseDebug) ? " /debug" : "");
                options.CompilerOptions   += (flags.HasFlag(CSharpCompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : "");
                if (preprocessorSymbols.Count > 0)
                {
                    options.CompilerOptions += " /d:" + string.Join(";", preprocessorSymbols);
                }
                if (outputFileName != null)
                {
                    options.OutputAssembly = outputFileName;
                }

                options.ReferencedAssemblies.Add("System.dll");
                options.ReferencedAssemblies.Add("System.Core.dll");
                options.ReferencedAssemblies.Add("System.Xml.dll");
                options.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
                CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFileNames.ToArray());
                if (results.Errors.Cast <CompilerError>().Any(e => !e.IsWarning))
                {
                    StringBuilder b = new StringBuilder("Compiler error:");
                    foreach (var error in results.Errors)
                    {
                        b.AppendLine(error.ToString());
                    }
                    throw new Exception(b.ToString());
                }
                return(results);
            }
        }