diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
index 79cb5dbb8..513e3e0ec 100644
--- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
+++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
@@ -287,21 +287,22 @@ namespace ILSpy.Debugger.Services
// Stepping:
- SourceCodeMapping GetCurrentCodeMapping()
+ SourceCodeMapping GetCurrentCodeMapping(out bool isMatch)
{
+ isMatch = false;
if (CurrentLineBookmark.Instance == null)
return null;
+ var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
// get the mapped instruction from the current line marker or the next one
- uint token;
return CodeMappingsStorage.GetInstructionByTypeAndLine(
- CurrentLineBookmark.Instance.Type.FullName,
- CurrentLineBookmark.Instance.LineNumber, out token);
+ CurrentLineBookmark.Instance.Type.FullName, (uint)frame.MethodInfo.MetadataToken, frame.IP, out isMatch);
}
StackFrame GetStackFrame()
{
- var map = GetCurrentCodeMapping();
+ bool isMatch;
+ var map = GetCurrentCodeMapping(out isMatch);
if (map == null) {
CurrentLineBookmark.Remove();
Continue();
@@ -309,7 +310,7 @@ namespace ILSpy.Debugger.Services
} else {
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
frame.SourceCodeLine = map.SourceCodeLine;
- frame.ILRanges = map.ToArray();
+ frame.ILRanges = map.ToArray(isMatch);
return frame;
}
}
diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs
index f2c961489..cb27c520f 100644
--- a/ICSharpCode.Decompiler/CodeMappings.cs
+++ b/ICSharpCode.Decompiler/CodeMappings.cs
@@ -42,17 +42,26 @@ namespace ICSharpCode.Decompiler
///
/// Retrieves the array that contains the IL range and the missing gaps between ranges.
///
- ///
- public int[] ToArray()
+ /// The array representation of the step aranges.
+ public int[] ToArray(bool isMatch)
{
+ var currentList = new List();
+
// add list for the current source code line
- var currentList = MemberMapping.MemberCodeMappings
- .FindAll(m => m.SourceCodeLine == this.SourceCodeLine)
- .ConvertAll(m => m.ILInstructionOffset);
+ currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings
+ .FindAll(m => m.SourceCodeLine == this.SourceCodeLine)
+ .ConvertAll(m => m.ILInstructionOffset)));
- // add inverted
- currentList.AddRange(MemberMapping.InvertedList);
+ if (!isMatch) {
+ // add inverted
+ currentList.AddRange(MemberMapping.InvertedList);
+ } else {
+ // if the current list contains the last mapping, add also the last gap
+ if (currentList.Count == 1)
+ currentList.Add(MemberMapping.InvertedList.LastOrDefault());
+ }
+ // set the output
var resultList = new List();
foreach (var element in ILRange.OrderAndJoint(currentList)) {
resultList.Add(element.From);
@@ -101,7 +110,7 @@ namespace ICSharpCode.Decompiler
if (invertedList == null) {
var list = MemberCodeMappings.ConvertAll(
s => new ILRange { From = s.ILInstructionOffset.From, To = s.ILInstructionOffset.To });
- invertedList = ILRange.Invert(list, CodeSize);
+ invertedList = ILRange.OrderAndJoint(ILRange.Invert(list, CodeSize));
}
return invertedList;
}
@@ -201,6 +210,40 @@ namespace ICSharpCode.Decompiler
return null;
}
+ public static SourceCodeMapping GetInstructionByTypeAndLine(
+ this ConcurrentDictionary> codeMappings,
+ string typeName,
+ uint token,
+ int ilOffset, out bool isMatch)
+ {
+ isMatch = false;
+
+ if (codeMappings == null)
+ throw new ArgumentNullException("CodeMappings storage must be valid!");
+
+ if (!codeMappings.ContainsKey(typeName)) {
+ return null;
+ }
+
+ var methodMappings = codeMappings[typeName];
+ var maping = methodMappings.Find(m => m.MetadataToken == token);
+ // try find an exact match
+ var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
+
+ if (map == null) {
+ // get the immediate next one
+ map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From >= ilOffset);
+ isMatch = false;
+ if (map == null)
+ map = maping.MemberCodeMappings.LastOrDefault(); // get the last
+
+ return map;
+ }
+
+ isMatch = true;
+ return map;
+ }
+
///
/// Gets the source code and type name from metadata token and offset.
///
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
index 5fbd2e385..3608cacc1 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -224,7 +224,10 @@ namespace ICSharpCode.Decompiler.ILAst
public static List OrderAndJoint(IEnumerable input)
{
- List ranges = input.OrderBy(r => r.From).ToList();
+ if (input == null)
+ throw new ArgumentNullException("Input is null!");
+
+ List ranges = input.Where(r => r != null).OrderBy(r => r.From).ToList();
for (int i = 0; i < ranges.Count - 1;) {
ILRange curr = ranges[i];
ILRange next = ranges[i + 1];
@@ -241,6 +244,12 @@ namespace ICSharpCode.Decompiler.ILAst
public static IEnumerable Invert(IEnumerable input, int codeSize)
{
+ if (input == null)
+ throw new ArgumentNullException("Input is null!");
+
+ if (codeSize <= 0)
+ throw new ArgumentException("Code size must be grater than 0");
+
var ordered = OrderAndJoint(input);
if (ordered.Count == 0) {
yield return new ILRange() { From = 0, To = codeSize };