MyRoslynHost.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using FastReport.Design.PageDesigners.Code;
  2. using Microsoft.CodeAnalysis;
  3. using Microsoft.CodeAnalysis.CSharp;
  4. using RoslynPad.Roslyn;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Collections.Immutable;
  8. using System.IO;
  9. using System.Reflection;
  10. namespace FastReport.WPF.RoslynPad
  11. {
  12. internal class MyRoslynHost : RoslynHost
  13. {
  14. private ProjectId projectId;
  15. private DocumentId additionalDocumentId;
  16. private RoslynWorkspace workspace;
  17. private string languageName;
  18. private string FindLocalAssembly(string name)
  19. {
  20. if (name == null || name.Trim() == "")
  21. return null;
  22. // old report version
  23. if (string.Compare(name, "System.Windows.Forms.DataVisualization.dll", true) == 0)
  24. name = "FastReport.DataVisualization.dll";
  25. // WPF versions of FastReport assemblies
  26. if (string.Compare(name, "System.Windows.Forms.dll", true) == 0)
  27. name = "FastReport.Forms.WPF.dll";
  28. // See if the required assembly is present locally
  29. string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, name);
  30. if (File.Exists(path))
  31. return path;
  32. return null;
  33. }
  34. private string GetRefAssemblyPath(Type type)
  35. {
  36. // dlls located here (example paths, dependent on arch & fw version):
  37. //"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.14\" or "C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.14\"
  38. // ref dlls with associated xml files located here:
  39. //"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.14\ref\net6.0\"
  40. string dllPath = Path.GetDirectoryName(type.Assembly.Location);
  41. string refPath = "";
  42. if (dllPath.Contains(@"shared\Microsoft.NETCore.App", StringComparison.OrdinalIgnoreCase))
  43. {
  44. refPath = dllPath.Replace(@"shared\Microsoft.NETCore.App", @"packs\Microsoft.NETCore.App.Ref", StringComparison.OrdinalIgnoreCase);
  45. }
  46. else if (dllPath.Contains(@"shared\Microsoft.WindowsDesktop.App", StringComparison.OrdinalIgnoreCase))
  47. {
  48. refPath = dllPath.Replace(@"shared\Microsoft.WindowsDesktop.App", @"packs\Microsoft.WindowsDesktop.App.Ref", StringComparison.OrdinalIgnoreCase);
  49. }
  50. else
  51. {
  52. // no ref dlls installed? Return default dll path (no xml comments though)
  53. return dllPath;
  54. }
  55. refPath = Path.Combine(refPath, "ref", "net") + type.Assembly.GetName().Version.ToString(2);
  56. if (Directory.Exists(refPath))
  57. return refPath;
  58. return dllPath;
  59. }
  60. private string GetRefAssemblyFileName(Type type)
  61. {
  62. return Path.Combine(GetRefAssemblyPath(type), Path.GetFileName(type.Assembly.Location));
  63. }
  64. private MetadataReference[] GetRefAssemblies(string[] assemblies)
  65. {
  66. List<MetadataReference> refAssemblies = new List<MetadataReference>();
  67. // system assemblies. Add them all
  68. string refPath = GetRefAssemblyPath(typeof(Object));
  69. foreach (var fileName in Directory.GetFiles(refPath, "*.dll"))
  70. refAssemblies.Add(CreateMetadataReference(fileName));
  71. // System.Drawing.Common (xml doc: missing for some types such as Bitmap. VS has the same issue)
  72. string sysDrawingDll = GetRefAssemblyFileName(typeof(System.Drawing.Image));
  73. if (File.Exists(sysDrawingDll))
  74. refAssemblies.Add(CreateMetadataReference(sysDrawingDll));
  75. // assemblies from Report.ReferencedAssemblies. Search in the exe folder. Note that system assemblies in this list will be ignored
  76. foreach (string name in assemblies)
  77. {
  78. var asm = FindLocalAssembly(name);
  79. if (asm != null)
  80. refAssemblies.Add(CreateMetadataReference(asm));
  81. }
  82. // FastReport main assembly
  83. refAssemblies.Add(CreateMetadataReference(typeof(Report).Assembly.Location));
  84. return refAssemblies.ToArray();
  85. }
  86. protected override ParseOptions CreateDefaultParseOptions()
  87. {
  88. return new CSharpParseOptions(kind: SourceCodeKind.Regular, languageVersion: LanguageVersion.Default);
  89. }
  90. public override RoslynWorkspace CreateWorkspace()
  91. {
  92. workspace = new MyRoslynWorkspace(HostServices, roslynHost: this);
  93. return workspace;
  94. }
  95. private string HiddenClassName
  96. {
  97. get { return languageName == LanguageNames.CSharp ? "hiddenClass.cs" : "hiddenClass.vb"; }
  98. }
  99. private ParseOptions GetParseOptions()
  100. {
  101. if (languageName == LanguageNames.CSharp)
  102. return new CSharpParseOptions(kind: SourceCodeKind.Regular, languageVersion: LanguageVersion.Default);
  103. return new Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions(kind: SourceCodeKind.Regular);
  104. }
  105. protected override CompilationOptions CreateCompilationOptions(DocumentCreationArgs args, bool addDefaultImports)
  106. {
  107. if (languageName == LanguageNames.CSharp)
  108. return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
  109. usings: addDefaultImports ? DefaultImports : ImmutableArray<string>.Empty,
  110. allowUnsafe: true,
  111. sourceReferenceResolver: new SourceFileResolver(ImmutableArray<string>.Empty, args.WorkingDirectory),
  112. // all #r references are resolved by the editor/msbuild
  113. metadataReferenceResolver: DummyScriptMetadataResolver.Instance,
  114. nullableContextOptions: NullableContextOptions.Disable);
  115. return new Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
  116. sourceReferenceResolver: new SourceFileResolver(ImmutableArray<string>.Empty, args.WorkingDirectory),
  117. metadataReferenceResolver: DummyScriptMetadataResolver.Instance);
  118. }
  119. protected override Project CreateProject(Solution solution, DocumentCreationArgs args, CompilationOptions compilationOptions, Project previousProject = null)
  120. {
  121. var name = args.Name ?? "Program";
  122. projectId = ProjectId.CreateNewId(name);
  123. solution = solution.AddProject(ProjectInfo.Create(
  124. projectId,
  125. VersionStamp.Create(),
  126. name,
  127. name,
  128. languageName,
  129. isSubmission: false,
  130. parseOptions: GetParseOptions(),
  131. compilationOptions: compilationOptions,
  132. metadataReferences: previousProject != null ? ImmutableArray<MetadataReference>.Empty : DefaultReferences,
  133. projectReferences: previousProject != null ? new[] { new ProjectReference(previousProject.Id) } : null)
  134. );
  135. additionalDocumentId = DocumentId.CreateNewId(projectId);
  136. solution = solution.AddDocument(additionalDocumentId, HiddenClassName, " ");
  137. var project = solution.GetProject(projectId);
  138. return project;
  139. }
  140. public void SetAdditionalInfo(string hiddenClassText, string[] assemblies)
  141. {
  142. var solution = workspace.CurrentSolution;
  143. var project = solution.GetProject(projectId);
  144. project = project.WithMetadataReferences(GetRefAssemblies(assemblies));
  145. solution = project.Solution;
  146. solution = solution.RemoveDocument(additionalDocumentId);
  147. additionalDocumentId = DocumentId.CreateNewId(projectId);
  148. solution = solution.AddDocument(additionalDocumentId, HiddenClassName, hiddenClassText);
  149. workspace.TryApplyChanges(solution);
  150. }
  151. public MyRoslynHost(SyntaxType syntaxType) :
  152. base(syntaxType == SyntaxType.Cs ?
  153. new[] {
  154. Assembly.Load("RoslynPad.Roslyn.Windows"),
  155. Assembly.Load("RoslynPad.Editor.Windows"),
  156. } :
  157. new[] {
  158. Assembly.Load("RoslynPad.Roslyn.Windows"),
  159. Assembly.Load("RoslynPad.Editor.Windows"),
  160. Assembly.Load("Microsoft.CodeAnalysis.VisualBasic.Features"),
  161. Assembly.Load("Microsoft.CodeAnalysis.VisualBasic.Workspaces"),
  162. }, null)
  163. {
  164. this.languageName = syntaxType == SyntaxType.Cs ? LanguageNames.CSharp : LanguageNames.VisualBasic;
  165. }
  166. }
  167. }