5 using System.Collections.Generic;
8 using Mono.Collections.Generic;
12 class AssemblyLocationProvider
14 AssemblyDefinition assembly;
17 public AssemblyLocationProvider (string assemblyPath, Logger logger)
19 assemblyPath = Path.GetFullPath (assemblyPath);
22 if (!File.Exists (assemblyPath))
23 throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
25 var readerParameters = new ReaderParameters { ReadSymbols = true };
26 assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParameters);
29 public bool TryResolveLocation (StackFrameData sfData, SeqPointInfo seqPointInfo)
31 if (!assembly.MainModule.HasSymbols)
34 TypeDefinition type = null;
35 var nested = sfData.TypeFullName.Split ('+');
36 var types = assembly.MainModule.Types;
37 foreach (var ntype in nested) {
39 // Use namespace first time.
40 type = types.FirstOrDefault (t => t.FullName == ntype);
42 type = types.FirstOrDefault (t => t.Name == ntype);
46 logger.LogWarning ("Could not find type: {0}", ntype);
50 types = type.NestedTypes;
53 var parensStart = sfData.MethodSignature.IndexOf ('(');
54 var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
55 var methodParameters = sfData.MethodSignature.Substring (parensStart);
56 var method = type.Methods.FirstOrDefault (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters));
58 logger.LogWarning ("Could not find method: {0}", methodName);
63 if (sfData.IsILOffset) {
64 ilOffset = sfData.Offset;
66 if (seqPointInfo == null)
69 ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
75 if (!method.DebugInformation.HasSequencePoints)
78 SequencePoint prev = null;
79 foreach (var sp in method.DebugInformation.SequencePoints.OrderBy (l => l.Offset)) {
80 if (sp.Offset >= ilOffset) {
81 sfData.SetLocation (sp.Document.Url, sp.StartLine);
89 sfData.SetLocation (prev.Document.Url, prev.StartLine);
96 static bool CompareName (MethodDefinition candidate, string expected)
98 if (candidate.Name == expected)
101 if (!candidate.HasGenericParameters)
104 var genStart = expected.IndexOf ('[');
108 if (candidate.Name != expected.Substring (0, genStart))
112 for (int pos = genStart; pos < expected.Length; ++pos) {
113 if (expected [pos] == ',')
117 return candidate.GenericParameters.Count == arity;
120 static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
122 var builder = new StringBuilder ();
123 builder.Append ("(");
125 for (int i = 0; i < candidate.Count; i++) {
126 var parameter = candidate [i];
128 builder.Append (", ");
130 if (parameter.ParameterType.IsSentinel)
131 builder.Append ("...,");
133 var pt = parameter.ParameterType;
134 if (!string.IsNullOrEmpty (pt.Namespace)) {
135 builder.Append (pt.Namespace);
136 builder.Append (".");
139 FormatElementType (pt, builder);
141 builder.Append (" ");
142 builder.Append (parameter.Name);
145 builder.Append (")");
147 return builder.ToString () == expected;
150 static void FormatElementType (TypeReference tr, StringBuilder builder)
152 var ts = tr as TypeSpecification;
154 if (ts.IsByReference) {
155 FormatElementType (ts.ElementType, builder);
156 builder.Append ("&");
160 var array = ts as ArrayType;
162 FormatElementType (ts.ElementType, builder);
163 builder.Append ("[");
165 for (int ii = 0; ii < array.Rank - 1; ++ii) {
166 builder.Append (",");
169 builder.Append ("]");
174 builder.Append (tr.Name);