Changed delta api
authorAleksandr Shaurtaev <a.shaurtaev@partner.samsung.com>
Thu, 2 Jun 2022 15:46:48 +0000 (18:46 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Mon, 18 Jul 2022 13:59:06 +0000 (16:59 +0300)
test-suite/NetcoreDbgTest/Delta/GenerateDelta.cs
test-suite/NetcoreDbgTest/Delta/WatchHotReloadService.cs

index 070ef93ea948664613e52442ef79d8c2262e71b6..cb54dbbf8eb730e6140c523ad3b7733ba41d2458 100644 (file)
@@ -3,13 +3,14 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading;
-using System.Threading.Tasks;
 using System.Collections.Generic;
 using System.Collections.Immutable;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.Text;
 using Microsoft.CodeAnalysis.MSBuild;
 using Microsoft.Build.Locator;
+using System.Threading.Tasks;
+using System.Collections;
 
 namespace NetcoreDbgTest.GetDeltaApi
 {
@@ -28,7 +29,7 @@ namespace NetcoreDbgTest.GetDeltaApi
         private static Solution solution;
         private static WatchHotReloadService watchHotReloadService;
         private static Update delta;
-
+        public static List<string> diagnostics = new List<string>();
         /// <summary>
         /// Check .Net runtime version on test system
         /// </summary>
@@ -59,11 +60,13 @@ namespace NetcoreDbgTest.GetDeltaApi
                 var project = workspace.OpenProjectAsync(path, cancellationToken: CancellationToken.None).Result;
 
                 solution = project.Solution;
-                watchHotReloadService = new WatchHotReloadService(solution.Workspace.Services);
-                watchHotReloadService.StartSessionAsync(solution, CancellationToken.None).Wait();
+                watchHotReloadService = new WatchHotReloadService();
+                watchHotReloadService.InitializeService(project);
+                watchHotReloadService.StartSessionAsync(solution, CancellationToken.None);
             }
             catch(Exception exception)
             {
+                diagnostics.Add(exception.ToString());
                 return false;
             }
             return true;
@@ -135,13 +138,13 @@ namespace NetcoreDbgTest.GetDeltaApi
             solution = solution.WithDocumentText(documentId, SourceText.From(source, Encoding.UTF8));
             var (updates, hotReloadDiagnostics) = watchHotReloadService.EmitSolutionUpdate(solution, CancellationToken.None);
 
-            if (!hotReloadDiagnostics.IsDefaultOrEmpty)
+            if ((IEnumerable)hotReloadDiagnostics != null)
             {
-                foreach (var diagnostic in hotReloadDiagnostics)
+                foreach (var diagnostic in (IEnumerable)hotReloadDiagnostics)
                 {
-                    Console.WriteLine(diagnostic.ToString());
+                    diagnostics.Add(diagnostic.ToString());
                 }
-                Console.WriteLine($"Changes made in project will not be applied while the application is running,\n please change the source file #{filePath} in sources");
+                diagnostics.Add($"Changes made in project will not be applied while the application is running,\n please change the source file #{filePath} in sources");
                 return false;
             }
             delta = updates;
@@ -159,7 +162,7 @@ namespace NetcoreDbgTest.GetDeltaApi
             }
             catch(Exception ex)
             {
-                Console.WriteLine(ex.ToString());
+                diagnostics.Add(ex.ToString());
                 return false;
             }
             return true;
@@ -171,11 +174,45 @@ namespace NetcoreDbgTest.GetDeltaApi
         /// <param name="fileName">Filename</param>
         public bool WriteDeltas(string fileName) 
         {
-            WriteDeltaToFile(delta.MetadataDelta.ToArray(), $"{fileName}.metadata");
-            WriteDeltaToFile(delta.ILDelta.ToArray(), $"{fileName}.il");
-            WriteDeltaToFile(delta.PdbDelta.ToArray(), $"{fileName}.pdb");
+            try
+            {
+                WriteDeltaToFile(delta.MetadataDelta.ToArray(), $"{fileName}.metadata");
+                WriteDeltaToFile(delta.ILDelta.ToArray(), $"{fileName}.il");
+                WriteDeltaToFile(delta.PdbDelta.ToArray(), $"{fileName}.pdb");
+                WriteLineUpdates(delta, $"{fileName}.bin");
+            }
+            catch(Exception ex)
+            {
+                diagnostics.Add(ex.ToString());
+                return false;
+            }
+            return true;
+        }
 
-            return File.Exists($"{fileName}.il") ? true : false;
+        private static void WriteLineUpdates(Update delta, string basename)
+        {
+            using (BinaryWriter bw = new BinaryWriter(File.Open(basename, FileMode.Create))) 
+            {
+                var sequencePointsCount = (uint)(delta.SequencePoints as ICollection).Count;
+                bw.Write(sequencePointsCount);
+                foreach (var sp in delta.SequencePoints) 
+                {
+                    var filenameLength = Convert.ToUInt32(Encoding.UTF8.GetBytes(((object)sp).GetType().GetProperty("FileName").GetValue(sp)).Length);
+                    bw.Write(filenameLength);
+                    var filename = Encoding.UTF8.GetBytes(((object)sp).GetType().GetProperty("FileName").GetValue(sp));
+                    bw.Write(filename);
+                    var lineUpdates = (object)(sp).GetType().GetProperty("LineUpdates").GetValue(sp);
+                    var lineUpdatesLength = Convert.ToUInt32(lineUpdates.GetType().GetProperty("Length").GetValue(lineUpdates));
+                    bw.Write(lineUpdatesLength);
+                    foreach (var lu in (IEnumerable)lineUpdates) 
+                    {
+                        var newline = Convert.ToUInt32((object)lu.GetType().GetProperty("NewLine").GetValue(lu));
+                        bw.Write(newline);
+                        var oldline = Convert.ToUInt32((object)lu.GetType().GetProperty("OldLine").GetValue(lu));
+                        bw.Write(oldline);
+                    }
+                }
+            }
         }
 
         /// <summary>d
@@ -191,4 +228,4 @@ namespace NetcoreDbgTest.GetDeltaApi
             }
         }
     }
-}
+}
\ No newline at end of file
index 6db1017bf7b434f6d18e79a01f694d5d431028aa..fdf54494520017e7446203d4038046759c9fd8ef 100644 (file)
@@ -1,11 +1,16 @@
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Threading.Tasks;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.MSBuild;
 
 namespace NetcoreDbgTest.GetDeltaApi
 {
@@ -55,56 +60,66 @@ namespace NetcoreDbgTest.GetDeltaApi
         public readonly ImmutableArray<byte> ILDelta;
         public readonly ImmutableArray<byte> MetadataDelta;
         public readonly ImmutableArray<byte> PdbDelta;
+        public readonly dynamic SequencePoints;
 
-        public Update(Guid moduleId, ImmutableArray<byte> ilDelta, ImmutableArray<byte> metadataDelta, ImmutableArray<byte> pdbDelta)
+        public Update(Guid moduleId, ImmutableArray<byte> ilDelta, ImmutableArray<byte> metadataDelta, ImmutableArray<byte> pdbDelta, dynamic sequencePoints)
         {
             ModuleId = moduleId;
             ILDelta = ilDelta;
             MetadataDelta = metadataDelta;
             PdbDelta = pdbDelta;
+            SequencePoints = sequencePoints;
         }
     }
 
     public class WatchHotReloadService
     {
-        private readonly Func<Solution, CancellationToken, Task> startSession;
-        private readonly Func<Solution, CancellationToken, ITuple> emitSolutionUpdateAsync;
-        private readonly Action endSession;
-
-        private static ImmutableArray<string> Net5RuntimeCapabilities = ImmutableArray.Create(EditAndContinueCapabilities.Baseline, EditAndContinueCapabilities.AddInstanceFieldToExistingType,
+        public object current_project = null;
+        public object editAndContinueWorkspaceServiceInstance = null;
+        private static ImmutableArray<string> s_net5RuntimeCapabilities = ImmutableArray.Create(EditAndContinueCapabilities.Baseline, EditAndContinueCapabilities.AddInstanceFieldToExistingType,
                                                                                         EditAndContinueCapabilities.AddStaticFieldToExistingType, EditAndContinueCapabilities.AddMethodToExistingType,
                                                                                         EditAndContinueCapabilities.NewTypeDefinition);
 
-        private static ImmutableArray<string> Net6RuntimeCapabilities = Net5RuntimeCapabilities.AddRange(new[] { EditAndContinueCapabilities.ChangeCustomAttributes, EditAndContinueCapabilities.UpdateParameters });
-
+        private static ImmutableArray<string> s_net6RuntimeCapabilities = s_net5RuntimeCapabilities.AddRange(new[] { EditAndContinueCapabilities.ChangeCustomAttributes, EditAndContinueCapabilities.UpdateParameters });
 
-        public WatchHotReloadService(HostWorkspaceServices services)
+        /// <summary>
+        /// Initialize WatchHotReloadService
+        /// </summary>
+        /// <param name="project">Current project</param>
+        public void InitializeService(Project project)
         {
             try
             {
-                var watchType = Type.GetType("Microsoft.CodeAnalysis.ExternalAccess.Watch.Api.WatchHotReloadService, Microsoft.CodeAnalysis.Features");
-                //We use the full set of capabilities for the latest version since it also works correctly on lower runtime versions to get deltas
-                var watchHotReloadServiceInstance = Activator.CreateInstance(watchType, services, Net6RuntimeCapabilities);
-                startSession = watchType.GetMethod("StartSessionAsync").CreateDelegate(typeof(Func<Solution, CancellationToken, Task>), watchHotReloadServiceInstance) as Func<Solution, CancellationToken, Task>;
-
-                emitSolutionUpdateAsync = (solution, token) =>
-                {
-                    var emitSolutionResult = watchType.GetMethod("EmitSolutionUpdateAsync").Invoke(watchHotReloadServiceInstance, new object[] { solution, token });
-                    var results = emitSolutionResult.GetType().GetProperty("Result").GetValue(emitSolutionResult, null) as ITuple;
-                    return results;
-                };
-
-                endSession = watchType.GetMethod("EndSession").CreateDelegate(typeof(Action), watchHotReloadServiceInstance) as Action;
+                current_project = project;
+                var encWorkspaceServiceType = Type.GetType("Microsoft.CodeAnalysis.EditAndContinue.EditAndContinueWorkspaceService, Microsoft.CodeAnalysis.Features");
+                editAndContinueWorkspaceServiceInstance = encWorkspaceServiceType.GetConstructor(Array.Empty<Type>()).Invoke(parameters: Array.Empty<object>());
             }
-            catch (Exception ex) 
+            catch (Exception ex)
             {
                 throw new Exception(ex.Message);
             }
         }
 
-        public Task StartSessionAsync(Solution currentSolution, CancellationToken cancellationToken)
+        /// <summary>
+        /// Start debugging session
+        /// </summary>
+        /// <param name="solution">Current solution</param>
+        /// <param name="cancellationToken">cancellation token</param>
+        public void StartSessionAsync(Solution solution, CancellationToken cancellationToken)
         {
-            return startSession(currentSolution, cancellationToken);
+
+            var defaultDocumentTrackingServiceType = Type.GetType("Microsoft.CodeAnalysis.SolutionCrawler.DefaultDocumentTrackingService, Microsoft.CodeAnalysis.Features");
+            var defaultDocumentTrackingServiceConstructor = defaultDocumentTrackingServiceType.GetConstructor(Array.Empty<Type>()).Invoke(parameters: Array.Empty<object>());
+            var emptyImmutableArrayofDocumentId = defaultDocumentTrackingServiceConstructor.GetType().GetMethod("GetVisibleDocuments").Invoke(obj: defaultDocumentTrackingServiceConstructor, parameters: Array.Empty<object>());
+            var debuggerService = Type.GetType("Microsoft.CodeAnalysis.ExternalAccess.Watch.Api.WatchHotReloadService, Microsoft.CodeAnalysis.Features")
+                                      .GetNestedType(name: "DebuggerService", bindingAttr: BindingFlags.NonPublic)
+                                      .GetConstructor(types: new Type[] { s_net6RuntimeCapabilities.GetType() })
+                                      .Invoke(parameters: new object[] { s_net6RuntimeCapabilities });
+            
+            var startDebuggingSessionAsync = editAndContinueWorkspaceServiceInstance.GetType()
+                                                        .GetMethod("StartDebuggingSessionAsync")
+                                                        .Invoke(obj: editAndContinueWorkspaceServiceInstance,
+                                                                parameters: new object[] { solution, debuggerService, ImmutableArray<DocumentId>.Empty, false, true, CancellationToken.None });
         }
 
         /// <summary>
@@ -116,27 +131,63 @@ namespace NetcoreDbgTest.GetDeltaApi
         /// <returns>
         /// Updates and Rude Edit diagnostics. Does not include syntax or semantic diagnostics.
         /// </returns>
-        public (Update deltas, ImmutableArray<Diagnostic> diagnostics) EmitSolutionUpdate(Solution solution, CancellationToken cancellationToken)
+        public (Update deltas, object diagnostics) EmitSolutionUpdate(Solution solution, CancellationToken cancellationToken)
         {
-            var values = emitSolutionUpdateAsync(solution, cancellationToken);
-            var moduleUpdates = (IList)values[0];
-            var diagnostics = (ImmutableArray<Diagnostic>)values[1];
             var deltas = new Update();
+            object diagnostics = default;
+            var activeStatementSpanProvider = Type.GetType("Microsoft.CodeAnalysis.ExternalAccess.Watch.Api.WatchHotReloadService, Microsoft.CodeAnalysis.Features").GetField(name: "s_solutionActiveStatementSpanProvider",
+                                                                                                                                                                              bindingAttr: BindingFlags.NonPublic | BindingFlags.Static).GetValue(default);
+            var id = editAndContinueWorkspaceServiceInstance.GetType().GetField(name: "s_debuggingSessionId", bindingAttr: BindingFlags.NonPublic | BindingFlags.Static).GetValue(editAndContinueWorkspaceServiceInstance);
+            var debuggingSessionId = Type.GetType("Microsoft.CodeAnalysis.EditAndContinue.DebuggingSessionId, Microsoft.CodeAnalysis.Features").GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { id });
+            var emitSolutionUpdateAsync = editAndContinueWorkspaceServiceInstance.GetType().GetMethod("EmitSolutionUpdateAsync").Invoke(obj: editAndContinueWorkspaceServiceInstance,
+                                                                                                                                        parameters: new object[] { debuggingSessionId, solution, activeStatementSpanProvider, CancellationToken.None });
+            var get_results = emitSolutionUpdateAsync.GetType().GetMethod("get_Result").Invoke(obj: emitSolutionUpdateAsync,
+                                                                                               parameters: Array.Empty<object>());
+            var newModuleUpdates = get_results.GetType().GetField("ModuleUpdates").GetValue(get_results);
+            var getAllDiagnostics = get_results.GetType().GetMethod("GetAllDiagnosticsAsync").Invoke(get_results, new object[] { solution, cancellationToken });
+            var updates = newModuleUpdates.GetType().GetProperty("Updates").GetValue(newModuleUpdates);
+            var defaultDocumentTrackingServiceType = Type.GetType("Microsoft.CodeAnalysis.SolutionCrawler.DefaultDocumentTrackingService, Microsoft.CodeAnalysis.Features");
+            var defaultDocumentTrackingServiceConstructor = defaultDocumentTrackingServiceType.GetConstructor(Array.Empty<Type>()).Invoke(parameters: Array.Empty<object>());
+            var emptyImmutableArrayofDocumentId = defaultDocumentTrackingServiceConstructor.GetType().GetMethod("GetVisibleDocuments").Invoke(obj: defaultDocumentTrackingServiceConstructor,
+                                                                                                                                              parameters: Array.Empty<object>());
+            var managedModuleUpdateStatusReady = Type.GetType("Microsoft.CodeAnalysis.EditAndContinue.Contracts.ManagedModuleUpdateStatus, Microsoft.CodeAnalysis.Features").GetField("Ready").GetValue(newModuleUpdates);
+
+            if (newModuleUpdates.GetType().GetProperty("Status").GetValue(newModuleUpdates).Equals(managedModuleUpdateStatusReady))
+            {
+                editAndContinueWorkspaceServiceInstance.GetType().GetMethod("CommitSolutionUpdate").Invoke(obj: editAndContinueWorkspaceServiceInstance,
+                                                                                               parameters: new object[] { debuggingSessionId, emptyImmutableArrayofDocumentId });
+            }
+            else
+            {
+                diagnostics = getAllDiagnostics.GetType().GetProperty("Result").GetValue(getAllDiagnostics);
+            }
+
+            var moduleUpdates = (IList)updates;
 
             for (int i = 0; i < moduleUpdates.Count; i++)
             {
                 object moduleUpdate = moduleUpdates[i];
                 var updateType = moduleUpdate.GetType();
 
-                deltas = new Update((Guid)updateType.GetField("ModuleId").GetValue(moduleUpdate),
-                                        (ImmutableArray<byte>)updateType.GetField("ILDelta").GetValue(moduleUpdate),
-                                        (ImmutableArray<byte>)updateType.GetField("MetadataDelta").GetValue(moduleUpdate),
-                                        (ImmutableArray<byte>)updateType.GetField("PdbDelta").GetValue(moduleUpdate));
-
+                deltas = new Update((Guid)updateType.GetProperty("Module").GetValue(moduleUpdate),
+                        (ImmutableArray<byte>)updateType.GetProperty("ILDelta").GetValue(moduleUpdate),
+                        (ImmutableArray<byte>)updateType.GetProperty("MetadataDelta").GetValue(moduleUpdate),
+                        (ImmutableArray<byte>)updateType.GetProperty("PdbDelta").GetValue(moduleUpdate),
+                        (dynamic)(updateType.GetProperty("SequencePoints").GetValue(moduleUpdate)));
             }
             return (deltas, diagnostics);
         }
 
-        public void EndSession() => endSession();
+        /// <summary>
+        /// End Debugging session
+        /// </summary>
+        public void EndSession()
+        {
+            object docs = null;
+            var id = editAndContinueWorkspaceServiceInstance.GetType().GetField(name: "s_debuggingSessionId", bindingAttr: BindingFlags.NonPublic | BindingFlags.Static).GetValue(editAndContinueWorkspaceServiceInstance);
+            var debuggingSessionId = Type.GetType("Microsoft.CodeAnalysis.EditAndContinue.DebuggingSessionId, Microsoft.CodeAnalysis.Features").GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { id });
+            var endDebuggingSession = editAndContinueWorkspaceServiceInstance.GetType().GetMethod("EndDebuggingSession").Invoke(obj: editAndContinueWorkspaceServiceInstance,
+                                                                                                                            parameters: new object[] { debuggingSessionId, docs });           
+        }
     }
-}
+}
\ No newline at end of file