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;
36 if (sfData.TypeFullName.IndexOf ('/') >= 0)
37 nested = sfData.TypeFullName.Split ('/');
39 nested = sfData.TypeFullName.Split ('+');
41 var types = assembly.MainModule.Types;
42 foreach (var ntype in nested) {
44 // Use namespace first time.
45 type = types.FirstOrDefault (t => t.FullName == ntype);
47 type = types.FirstOrDefault (t => t.Name == ntype);
51 logger.LogWarning ("Could not find type: {0}", ntype);
55 types = type.NestedTypes;
58 var parensStart = sfData.MethodSignature.IndexOf ('(');
59 var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
60 var methodParameters = sfData.MethodSignature.Substring (parensStart);
61 var methods = type.Methods.Where (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters)).ToArray ();
62 if (methods.Length == 0) {
63 logger.LogWarning ("Could not find method: {0}", methodName);
66 if (methods.Length > 1) {
67 logger.LogWarning ("Ambiguous match for method: {0}", sfData.MethodSignature);
70 var method = methods [0];
73 if (sfData.IsILOffset) {
74 ilOffset = sfData.Offset;
76 if (seqPointInfo == null)
79 ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
85 if (!method.DebugInformation.HasSequencePoints)
88 SequencePoint prev = null;
89 foreach (var sp in method.DebugInformation.SequencePoints.OrderBy (l => l.Offset)) {
90 if (sp.Offset >= ilOffset) {
91 sfData.SetLocation (sp.Document.Url, sp.StartLine);
99 sfData.SetLocation (prev.Document.Url, prev.StartLine);
106 static bool CompareName (MethodDefinition candidate, string expected)
108 if (candidate.Name == expected)
111 if (!candidate.HasGenericParameters)
114 var genStart = expected.IndexOf ('[');
116 genStart = expected.IndexOf ('<');
121 if (candidate.Name != expected.Substring (0, genStart))
125 for (int pos = genStart; pos < expected.Length; ++pos) {
126 if (expected [pos] == ',')
130 return candidate.GenericParameters.Count == arity;
133 static string RemoveGenerics (string expected, char open, char close)
135 if (expected.IndexOf (open) < 0)
138 var sb = new StringBuilder ();
139 for (int i = 0; i < expected.Length;) {
140 int start = expected.IndexOf (open, i);
141 int end = expected.IndexOf (close, i);
142 if (start < 0 || end < 0) {
143 sb.Append (expected, i, expected.Length - i);
147 bool is_ginst = false;
148 for (int j = start + 1; j < end; ++j) {
149 if (expected [j] != ',')
153 if (is_ginst) //discard the the generic args
154 sb.Append (expected, i, start - i);
155 else //include array arity
156 sb.Append (expected, i, end + 1 - i);
160 return sb.ToString ();
163 static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
165 var builder = new StringBuilder ();
166 builder.Append ("(");
168 for (int i = 0; i < candidate.Count; i++) {
169 var parameter = candidate [i];
171 builder.Append (", ");
173 if (parameter.ParameterType.IsSentinel)
174 builder.Append ("...,");
176 var pt = parameter.ParameterType;
177 FormatElementType (pt, builder);
179 builder.Append (" ");
180 builder.Append (parameter.Name);
183 builder.Append (")");
185 if (builder.ToString () == RemoveGenerics (expected, '[', ']'))
188 //now try the compact runtime format.
192 builder.Append ("(");
194 for (int i = 0; i < candidate.Count; i++) {
195 var parameter = candidate [i];
197 builder.Append (",");
199 if (parameter.ParameterType.IsSentinel)
200 builder.Append ("...,");
202 var pt = parameter.ParameterType;
204 RuntimeFormatElementType (pt, builder);
207 builder.Append (")");
209 if (builder.ToString () == RemoveGenerics (expected, '<', '>'))
215 static void RuntimeFormatElementType (TypeReference tr, StringBuilder builder)
217 var ts = tr as TypeSpecification;
219 if (ts.IsByReference) {
220 RuntimeFormatElementType (ts.ElementType, builder);
221 builder.Append ("&");
226 switch (tr.MetadataType) {
227 case MetadataType.Void:
228 builder.Append ("void");
230 case MetadataType.Boolean:
231 builder.Append ("bool");
233 case MetadataType.Char:
234 builder.Append ("char");
236 case MetadataType.SByte:
237 builder.Append ("sbyte");
239 case MetadataType.Byte:
240 builder.Append ("byte");
242 case MetadataType.Int16:
243 builder.Append ("int16");
245 case MetadataType.UInt16:
246 builder.Append ("uint16");
248 case MetadataType.Int32:
249 builder.Append ("int");
251 case MetadataType.UInt32:
252 builder.Append ("uint");
254 case MetadataType.Int64:
255 builder.Append ("long");
257 case MetadataType.UInt64:
258 builder.Append ("ulong");
260 case MetadataType.Single:
261 builder.Append ("single");
263 case MetadataType.Double:
264 builder.Append ("double");
266 case MetadataType.String:
267 builder.Append ("string");
269 case MetadataType.Pointer:
270 builder.Append (((TypeSpecification)tr).ElementType);
271 builder.Append ("*");
273 case MetadataType.ValueType:
274 case MetadataType.Class:
275 case MetadataType.GenericInstance: {
276 FormatName (tr, builder, '/');
279 case MetadataType.Var:
280 case MetadataType.MVar:
281 builder.Append (tr.Name);
282 builder.Append ("_REF");
284 case MetadataType.Array: {
285 var array = (ArrayType)tr;
286 RuntimeFormatElementType (array.ElementType, builder);
287 builder.Append ("[");
289 for (int i = 0; i < array.Rank - 1; ++i)
290 builder.Append (",");
292 builder.Append ("]");
296 case MetadataType.TypedByReference:
297 builder.Append ("typedbyref");
299 case MetadataType.IntPtr:
300 builder.Append ("intptr");
302 case MetadataType.UIntPtr:
303 builder.Append ("uintptr");
305 case MetadataType.FunctionPointer:
306 builder.Append ("*()");
308 case MetadataType.Object:
309 builder.Append ("object");
312 builder.Append ("-unknown-");
317 static void FormatName (TypeReference tr, StringBuilder builder, char sep)
319 if (tr.IsNested && !(tr.MetadataType == MetadataType.Var || tr.MetadataType == MetadataType.MVar)) {
320 FormatName (tr.DeclaringType, builder, sep);
321 builder.Append (sep);
323 if (!string.IsNullOrEmpty (tr.Namespace)) {
324 builder.Append (tr.Namespace);
325 builder.Append (".");
328 builder.Append (tr.Name);
331 static void FormatElementType (TypeReference tr, StringBuilder builder)
333 var ts = tr as TypeSpecification;
335 if (ts.IsByReference) {
336 FormatElementType (ts.ElementType, builder);
337 builder.Append ("&");
341 var array = ts as ArrayType;
343 FormatElementType (ts.ElementType, builder);
344 builder.Append ("[");
346 for (int ii = 0; ii < array.Rank - 1; ++ii) {
347 builder.Append (",");
350 builder.Append ("]");
354 FormatName (tr, builder, '+');