From 5e37f44535e0753ff3e4dbdef4ef148ca8bb09e0 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 23 Jul 2020 15:01:43 -0700 Subject: Automatically update local variable debug info (#676) * Automatically update local variable debug info When manipulating the local variables collection on a method body, automatically update the debug info for all affected local variables. When removing a local variable, also remove the debug info for that local variable from the scopes. When removing or inserting update the indeces of local variable debug infos which are afected by the action. Note the local variable debug info either holds just a backpointer to the local variable in which case it doesn't store the index at all (and thus nothing to do), or it stores the index explicitly in which case it needs to be updated. Added tests for both insert and remove cases. * Add internal properties on `VariableOffset` to make it easier to manipulate it. Reworked the `UpdateVariableIndeces` to only loop over variables once and also to handle removal of resolved variable debug infos. * Simplify the code a little and add comments * PR feedback --- Test/Mono.Cecil.Tests/VariableTests.cs | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'Test/Mono.Cecil.Tests') diff --git a/Test/Mono.Cecil.Tests/VariableTests.cs b/Test/Mono.Cecil.Tests/VariableTests.cs index 577e56f..5454b93 100644 --- a/Test/Mono.Cecil.Tests/VariableTests.cs +++ b/Test/Mono.Cecil.Tests/VariableTests.cs @@ -80,6 +80,45 @@ namespace Mono.Cecil.Tests { Assert.AreEqual (1, z.Index); } + [Test] + public void RemoveVariableWithDebugInfo () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ret); + + var x = new VariableDefinition (object_ref); + var y = new VariableDefinition (object_ref); + var z = new VariableDefinition (object_ref); + var z2 = new VariableDefinition (object_ref); + + body.Variables.Add (x); + body.Variables.Add (y); + body.Variables.Add (z); + body.Variables.Add (z2); + + var scope = new ScopeDebugInformation (body.Instructions [0], body.Instructions [0]); + method.DebugInformation = new MethodDebugInformation (method) { + Scope = scope + }; + scope.Variables.Add (new VariableDebugInformation (x.index, nameof (x))); + scope.Variables.Add (new VariableDebugInformation (y.index, nameof (y))); + scope.Variables.Add (new VariableDebugInformation (z.index, nameof (z))); + scope.Variables.Add (new VariableDebugInformation (z2, nameof (z2))); + + body.Variables.Remove (y); + + Assert.AreEqual (3, scope.Variables.Count); + Assert.AreEqual (x.Index, scope.Variables [0].Index); + Assert.AreEqual (nameof (x), scope.Variables [0].Name); + Assert.AreEqual (z.Index, scope.Variables [1].Index); + Assert.AreEqual (nameof (z), scope.Variables [1].Name); + Assert.AreEqual (z2.Index, scope.Variables [2].Index); + Assert.AreEqual (nameof (z2), scope.Variables [2].Name); + } + [Test] public void InsertVariableIndex () { @@ -104,5 +143,43 @@ namespace Mono.Cecil.Tests { Assert.AreEqual (1, y.Index); Assert.AreEqual (2, z.Index); } + + [Test] + public void InsertVariableWithDebugInfo () + { + var object_ref = new TypeReference ("System", "Object", null, null, false); + var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); + var body = new MethodBody (method); + var il = body.GetILProcessor (); + il.Emit (OpCodes.Ret); + + var x = new VariableDefinition (object_ref); + var y = new VariableDefinition (object_ref); + var z = new VariableDefinition (object_ref); + var z2 = new VariableDefinition (object_ref); + + body.Variables.Add (x); + body.Variables.Add (z); + body.Variables.Add (z2); + + var scope = new ScopeDebugInformation (body.Instructions [0], body.Instructions [0]); + method.DebugInformation = new MethodDebugInformation (method) { + Scope = scope + }; + scope.Variables.Add (new VariableDebugInformation (x.index, nameof (x))); + scope.Variables.Add (new VariableDebugInformation (z.index, nameof (z))); + scope.Variables.Add (new VariableDebugInformation (z2, nameof (z2))); + + body.Variables.Insert (1, y); + + // Adding local variable doesn't add debug info for it (since there's no way to deduce the name of the variable) + Assert.AreEqual (3, scope.Variables.Count); + Assert.AreEqual (x.Index, scope.Variables [0].Index); + Assert.AreEqual (nameof (x), scope.Variables [0].Name); + Assert.AreEqual (z.Index, scope.Variables [1].Index); + Assert.AreEqual (nameof (z), scope.Variables [1].Name); + Assert.AreEqual (z2.Index, scope.Variables [2].Index); + Assert.AreEqual (nameof (z2), scope.Variables [2].Name); + } } } -- cgit v1.2.3