private static bool ContainsVariable(this ScopeDebugInformation debugInfo, VariableDefinition variable) { // Note: just checking for index might not be sufficient var hasVariable = debugInfo.Variables.Any(x => x.Index == variable.Index); if (hasVariable) { return(true); } // Important: check nested scopes for (var i = 0; i < debugInfo.Scopes.Count; i++) { if (ContainsVariable(debugInfo.Scopes[i], variable)) { return(true); } } return(false); }
static ScopeDebugInformation ReadScopeAndLocals(PdbScope scope, MethodDebugInformation info) { var parent = new ScopeDebugInformation(); parent.Start = new InstructionOffset((int)scope.offset); parent.End = new InstructionOffset((int)(scope.offset + scope.length)); if (!scope.slots.IsNullOrEmpty()) { parent.variables = new Collection <VariableDebugInformation> (scope.slots.Length); foreach (PdbSlot slot in scope.slots) { var index = (int)slot.slot; var variable = new VariableDebugInformation(index, slot.name); if (slot.flags == 4) { variable.IsDebuggerHidden = true; } parent.variables.Add(variable); } } if (!scope.constants.IsNullOrEmpty()) { parent.constants = new Collection <ConstantDebugInformation> (scope.constants.Length); foreach (var constant in scope.constants) { parent.constants.Add(new ConstantDebugInformation( constant.name, (TypeReference)info.method.Module.LookupToken((int)constant.token), constant.value)); } } parent.scopes = ReadScopeAndLocals(scope.scopes, info); return(parent); }
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); }
ScopeDebugInformation ReadScopeAndLocals(PdbScope scope, MethodDebugInformation info) { var parent = new ScopeDebugInformation(); parent.Start = new InstructionOffset((int)scope.offset); parent.End = new InstructionOffset((int)(scope.offset + scope.length)); if (!scope.slots.IsNullOrEmpty()) { parent.variables = new Collection <VariableDebugInformation> (scope.slots.Length); foreach (PdbSlot slot in scope.slots) { if ((slot.flags & 1) != 0) // parameter names { continue; } var index = (int)slot.slot; var variable = new VariableDebugInformation(index, slot.name); if ((slot.flags & 4) != 0) { variable.IsDebuggerHidden = true; } parent.variables.Add(variable); } } if (!scope.constants.IsNullOrEmpty()) { parent.constants = new Collection <ConstantDebugInformation> (scope.constants.Length); foreach (var constant in scope.constants) { var type = info.Method.Module.Read(constant, (c, r) => r.ReadConstantSignature(new MetadataToken(c.token))); var value = constant.value; // Object "null" is encoded as integer if (type != null && !type.IsValueType && value is int && (int)value == 0) { value = null; } parent.constants.Add(new ConstantDebugInformation(constant.name, type, value)); } } if (!scope.usedNamespaces.IsNullOrEmpty()) { ImportDebugInformation import; if (imports.TryGetValue(scope, out import)) { parent.import = import; } else { import = GetImport(scope, info.Method.Module); imports.Add(scope, import); parent.import = import; } } parent.scopes = ReadScopeAndLocals(scope.scopes, info); return(parent); }
void DefineScope(ScopeDebugInformation scope, MethodDebugInformation info, out MetadataToken import_parent) { var start_offset = scope.Start.Offset; var end_offset = scope.End.IsEndOfMethod ? info.code_size : scope.End.Offset; import_parent = new MetadataToken(0u); writer.OpenScope(start_offset); if (scope.Import != null && scope.Import.HasTargets && !import_info_to_parent.TryGetValue(info.scope.Import, out import_parent)) { foreach (var target in scope.Import.Targets) { switch (target.Kind) { case ImportTargetKind.ImportNamespace: writer.UsingNamespace("U" + target.@namespace); break; case ImportTargetKind.ImportType: writer.UsingNamespace("T" + TypeParser.ToParseable(target.type)); break; case ImportTargetKind.DefineNamespaceAlias: writer.UsingNamespace("A" + target.Alias + " U" + target.@namespace); break; case ImportTargetKind.DefineTypeAlias: writer.UsingNamespace("A" + target.Alias + " T" + TypeParser.ToParseable(target.type)); break; } } import_info_to_parent.Add(info.scope.Import, info.method.MetadataToken); } var sym_token = info.local_var_token.ToInt32(); if (!scope.variables.IsNullOrEmpty()) { for (int i = 0; i < scope.variables.Count; i++) { var variable = scope.variables [i]; DefineLocalVariable(variable, sym_token, start_offset, end_offset); } } if (!scope.constants.IsNullOrEmpty()) { for (int i = 0; i < scope.constants.Count; i++) { var constant = scope.constants [i]; DefineConstant(constant); } } if (!scope.scopes.IsNullOrEmpty()) { for (int i = 0; i < scope.scopes.Count; i++) { MetadataToken _; DefineScope(scope.scopes [i], info, out _); } } writer.CloseScope(end_offset); }