PageRenderTime 65ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/TestBoilen/CodeGeneration/Compile.cs

#
C# | 151 lines | 121 code | 30 blank | 0 comment | 15 complexity | ba9aefc4177bfa7ce3371a1f80070f52 MD5 | raw file
  1. using Boilen.Guards;
  2. using Microsoft.CSharp;
  3. using System;
  4. using System.CodeDom.Compiler;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reflection;
  10. using Xunit;
  11. namespace Boilen.Primitives.CodeGeneration {
  12. public static class Compile {
  13. public static MemberInfo[] PartialType( PartialType pt ) {
  14. var caller = GetCaller( );
  15. Type compiledType;
  16. return Compile.PartialType( caller, pt, out compiledType );
  17. }
  18. public static MemberInfo[] PartialType( PartialType pt, out Type compiledType ) {
  19. var caller = GetCaller( );
  20. return Compile.PartialType( caller, pt, out compiledType );
  21. }
  22. public static bool PartialType( PartialType pt, bool swallowRunErrors, out CompilerResults compileResults ) {
  23. var caller = GetCaller( );
  24. bool silverlight;
  25. return Compile.PartialType( caller, pt, swallowRunErrors, out silverlight, out compileResults );
  26. }
  27. private static MemberInfo[] PartialType( MethodBase caller, PartialType pt, out Type compiledType ) {
  28. bool silverlight;
  29. CompilerResults results;
  30. Compile.PartialType( caller, pt, false, out silverlight, out results );
  31. var errors = results.Errors.Cast<CompilerError>( );
  32. if( errors.Any( ) ) {
  33. string errorMessage = errors.Aggregate(
  34. new System.Text.StringBuilder( ).AppendLine( silverlight ? "SL" : "WPF" ),
  35. ( sb, e ) => sb.AppendLine( e.ToString( ) ),
  36. ( sb ) => sb.ToString( )
  37. );
  38. Assert.True( false, errorMessage );
  39. }
  40. Type[] types = results.CompiledAssembly.GetExportedTypes( );
  41. compiledType = Assert.Single( types );
  42. Assert.Equal( compiledType.FullName, pt.Type.FullName );
  43. var compiledTypeLocal = compiledType;
  44. var newMembers = compiledType.GetMembers( )
  45. .Where( m => m.DeclaringType == compiledTypeLocal )
  46. .ToArray( );
  47. return newMembers;
  48. }
  49. private static bool PartialType( MethodBase caller, PartialType pt, bool swallowRunErrors, out bool silverlight, out CompilerResults compileResults ) {
  50. var writer = new CodeFileWriter( caller, pt.Type );
  51. bool runResult = true;
  52. using( writer ) {
  53. if( swallowRunErrors ) {
  54. try { pt.Run( writer ); }
  55. catch { runResult = false; }
  56. }
  57. else
  58. pt.Run( writer );
  59. }
  60. string generatedFile = writer.FilePath;
  61. string sourceFile = Path.Combine( CodeFileWriter.CodeDirectory, writer.TypeName + ".cs" );
  62. silverlight = true;
  63. compileResults = GetCompileResults( silverlight, generatedFile, sourceFile );
  64. if( compileResults.Errors.Count == 0 ) {
  65. silverlight = false;
  66. compileResults = GetCompileResults( silverlight, generatedFile, sourceFile );
  67. }
  68. return runResult;
  69. }
  70. private static CompilerResults GetCompileResults( bool silverlight, params string[] files ) {
  71. string[] referenceAssemblies = (silverlight ? GetSilverlightReferences( ) : GetWpfReferences( )).ToArray( );
  72. var providerOptions = new Dictionary<string, string>( ) { { "CompilerVersion", "v4.0" } };
  73. var provider = new CSharpCodeProvider( providerOptions );
  74. var options = new CompilerParameters( ) { GenerateInMemory = true, TreatWarningsAsErrors = true, WarningLevel = 4 };
  75. options.TempFiles.KeepFiles = false;
  76. options.ReferencedAssemblies.AddRange( referenceAssemblies );
  77. if( silverlight ) { options.CompilerOptions = "/nostdlib+ /define:" + CompilationSymbol.Silverlight.Symbol; }
  78. return provider.CompileAssemblyFromFile( options, files );
  79. }
  80. private static readonly string[] excludedAssemblies = new string[] {
  81. typeof( int ).Assembly.FullName,
  82. typeof( Compile ).Assembly.FullName,
  83. typeof( PartialType ).Assembly.FullName,
  84. typeof( Xunit.Assert ).Assembly.FullName,
  85. typeof( Xunit.Extensions.TheoryAttribute ).Assembly.FullName,
  86. };
  87. private static IEnumerable<string> GetWpfReferences( ) {
  88. return AppDomain.CurrentDomain.GetAssemblies( )
  89. .Where( a => !string.IsNullOrEmpty( a.Location )
  90. && !a.FullName.StartsWith( "Microsoft." )
  91. && !excludedAssemblies.Contains( a.FullName ) )
  92. .Select( a => a.Location );
  93. }
  94. private static IEnumerable<string> GetSilverlightReferences( ) {
  95. string wpfSourceDependenciesFile = new Uri( typeof( TestGuards ).Assembly.CodeBase, UriKind.Absolute ).AbsolutePath;
  96. string sourceDependenciesName = Path.GetFileNameWithoutExtension( wpfSourceDependenciesFile );
  97. var sourceDependenciesDirectory = Directory.GetParent( wpfSourceDependenciesFile );
  98. while( sourceDependenciesDirectory.GetDirectories( sourceDependenciesName ).Length == 0 )
  99. sourceDependenciesDirectory = sourceDependenciesDirectory.Parent;
  100. string slSourceDependenciesFile = new[] {
  101. sourceDependenciesDirectory.FullName,
  102. sourceDependenciesName, "bin", "Debug", sourceDependenciesName + ".SL.dll"
  103. }.Aggregate( Path.Combine );
  104. string slReferencesDirectory = new[] {
  105. Environment.GetFolderPath( Environment.SpecialFolder.ProgramFiles ),
  106. "Reference Assemblies", "Microsoft", "Framework", "Silverlight", "v4.0"
  107. }.Aggregate( Path.Combine );
  108. string[] slReferences = Directory.GetFiles( slReferencesDirectory, "*.dll", SearchOption.TopDirectoryOnly );
  109. return slReferences
  110. .Where( path => {
  111. string fileName = Path.GetFileNameWithoutExtension( path );
  112. bool include = fileName.Any( char.IsUpper ) && fileName != "Silverlight.ConfigurationUI";
  113. return fileName == "system" || fileName == "mscorlib" || include;
  114. } )
  115. .Concat( new[] { slSourceDependenciesFile } );
  116. }
  117. private static MethodBase GetCaller( ) {
  118. return new StackTrace( ).GetFrame( 2 ).GetMethod( );
  119. }
  120. }
  121. }