5 using System.Collections.Generic;
8 using Mono.Collections.Generic;
12 class AssemblyLocationProvider
14 string assemblyFullPath;
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 assemblyFullPath = assemblyPath;
28 public bool TryResolveLocation (StackFrameData sfData, SeqPointInfo seqPointInfo)
30 var readerParameters = new ReaderParameters { ReadSymbols = true };
31 using (var assembly = AssemblyDefinition.ReadAssembly (assemblyFullPath, readerParameters)) {
33 if (!assembly.MainModule.HasSymbols)
36 TypeDefinition type = null;
38 if (sfData.TypeFullName.IndexOf ('/') >= 0)
39 nested = sfData.TypeFullName.Split ('/');
41 nested = sfData.TypeFullName.Split ('+');
43 var types = assembly.MainModule.Types;
44 foreach (var ntype in nested) {
46 // Use namespace first time.
47 type = types.FirstOrDefault (t => t.FullName == ntype);
49 type = types.FirstOrDefault (t => t.Name == ntype);
53 logger.LogWarning ("Could not find type: {0}", ntype);
57 types = type.NestedTypes;
60 var parensStart = sfData.MethodSignature.IndexOf ('(');
61 var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
62 var methodParameters = sfData.MethodSignature.Substring (parensStart);
63 var methods = type.Methods.Where (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters)).ToArray ();
64 if (methods.Length == 0) {
65 logger.LogWarning ("Could not find method: {0}", methodName);
68 if (methods.Length > 1) {
69 logger.LogWarning ("Ambiguous match for method: {0}", sfData.MethodSignature);
72 var method = methods [0];
75 if (sfData.IsILOffset) {
76 ilOffset = sfData.Offset;
78 if (seqPointInfo == null)
81 ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
87 if (!method.DebugInformation.HasSequencePoints)
90 SequencePoint prev = null;
91 foreach (var sp in method.DebugInformation.SequencePoints.OrderBy (l => l.Offset)) {
92 if (sp.Offset >= ilOffset) {
93 sfData.SetLocation (sp.Document.Url, sp.StartLine);
101 sfData.SetLocation (prev.Document.Url, prev.StartLine);
109 static bool CompareName (MethodDefinition candidate, string expected)
111 if (candidate.Name == expected)
114 if (!candidate.HasGenericParameters)
117 var genStart = expected.IndexOf ('[');
119 genStart = expected.IndexOf ('<');
124 if (candidate.Name != expected.Substring (0, genStart))
128 for (int pos = genStart; pos < expected.Length; ++pos) {
129 if (expected [pos] == ',')
133 return candidate.GenericParameters.Count == arity;
136 static string RemoveGenerics (string expected, char open, char close)
138 if (expected.IndexOf (open) < 0)
141 var sb = new StringBuilder ();
142 for (int i = 0; i < expected.Length;) {
143 int start = expected.IndexOf (open, i);
144 int end = expected.IndexOf (close, i);
145 if (start < 0 || end < 0) {
146 sb.Append (expected, i, expected.Length - i);
150 bool is_ginst = false;
151 for (int j = start + 1; j < end; ++j) {
152 if (expected [j] != ',')
156 if (is_ginst) //discard the the generic args
157 sb.Append (expected, i, start - i);
158 else //include array arity
159 sb.Append (expected, i, end + 1 - i);
163 return sb.ToString ();
166 static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
168 var builder = new StringBuilder ();
169 builder.Append ("(");
171 for (int i = 0; i < candidate.Count; i++) {
172 var parameter = candidate [i];
174 builder.Append (", ");
176 if (parameter.ParameterType.IsSentinel)
177 builder.Append ("...,");
179 var pt = parameter.ParameterType;
180 FormatElementType (pt, builder);
182 builder.Append (" ");
183 builder.Append (parameter.Name);
186 builder.Append (")");
188 if (builder.ToString () == RemoveGenerics (expected, '[', ']'))
191 //now try the compact runtime format.
195 builder.Append ("(");
197 for (int i = 0; i < candidate.Count; i++) {
198 var parameter = candidate [i];
200 builder.Append (",");
202 if (parameter.ParameterType.IsSentinel)
203 builder.Append ("...,");
205 var pt = parameter.ParameterType;
207 RuntimeFormatElementType (pt, builder);
210 builder.Append (")");
212 if (builder.ToString () == RemoveGenerics (expected, '<', '>'))
218 static void RuntimeFormatElementType (TypeReference tr, StringBuilder builder)
220 var ts = tr as TypeSpecification;
222 if (ts.IsByReference) {
223 RuntimeFormatElementType (ts.ElementType, builder);
224 builder.Append ("&");
229 switch (tr.MetadataType) {
230 case MetadataType.Void:
231 builder.Append ("void");
233 case MetadataType.Boolean:
234 builder.Append ("bool");
236 case MetadataType.Char:
237 builder.Append ("char");
239 case MetadataType.SByte:
240 builder.Append ("sbyte");
242 case MetadataType.Byte:
243 builder.Append ("byte");
245 case MetadataType.Int16:
246 builder.Append ("int16");
248 case MetadataType.UInt16:
249 builder.Append ("uint16");
251 case MetadataType.Int32:
252 builder.Append ("int");
254 case MetadataType.UInt32:
255 builder.Append ("uint");
257 case MetadataType.Int64:
258 builder.Append ("long");
260 case MetadataType.UInt64:
261 builder.Append ("ulong");
263 case MetadataType.Single:
264 builder.Append ("single");
266 case MetadataType.Double:
267 builder.Append ("double");
269 case MetadataType.String:
270 builder.Append ("string");
272 case MetadataType.Pointer:
273 builder.Append (((TypeSpecification)tr).ElementType);
274 builder.Append ("*");
276 case MetadataType.ValueType:
277 case MetadataType.Class:
278 case MetadataType.GenericInstance: {
279 FormatName (tr, builder, '/');
282 case MetadataType.Var:
283 case MetadataType.MVar:
284 builder.Append (tr.Name);
285 builder.Append ("_REF");
287 case MetadataType.Array: {
288 var array = (ArrayType)tr;
289 RuntimeFormatElementType (array.ElementType, builder);
290 builder.Append ("[");
292 for (int i = 0; i < array.Rank - 1; ++i)
293 builder.Append (",");
295 builder.Append ("]");
299 case MetadataType.TypedByReference:
300 builder.Append ("typedbyref");
302 case MetadataType.IntPtr:
303 builder.Append ("intptr");
305 case MetadataType.UIntPtr:
306 builder.Append ("uintptr");
308 case MetadataType.FunctionPointer:
309 builder.Append ("*()");
311 case MetadataType.Object:
312 builder.Append ("object");
315 builder.Append ("-unknown-");
320 static void FormatName (TypeReference tr, StringBuilder builder, char sep)
322 if (tr.IsNested && !(tr.MetadataType == MetadataType.Var || tr.MetadataType == MetadataType.MVar)) {
323 FormatName (tr.DeclaringType, builder, sep);
324 builder.Append (sep);
326 if (!string.IsNullOrEmpty (tr.Namespace)) {
327 builder.Append (tr.Namespace);
328 builder.Append (".");
331 builder.Append (tr.Name);
334 static void FormatElementType (TypeReference tr, StringBuilder builder)
336 var ts = tr as TypeSpecification;
338 if (ts.IsByReference) {
339 FormatElementType (ts.ElementType, builder);
340 builder.Append ("&");
344 var array = ts as ArrayType;
346 FormatElementType (ts.ElementType, builder);
347 builder.Append ("[");
349 for (int ii = 0; ii < array.Rank - 1; ++ii) {
350 builder.Append (",");
353 builder.Append ("]");
357 FormatName (tr, builder, '+');