* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Debugger.Mdb / Mono.Debugging.Server.Mdb / CollectionAdaptor.cs
blob1d620e9ecd4a3706da60c50f66c680ea077a011b
1 // CollectionAdaptor.cs
2 //
3 // Author:
4 // Lluis Sanchez Gual <lluis@novell.com>
5 //
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 // THE SOFTWARE.
28 using System;
29 using System.Collections.Generic;
30 using Mono.Debugger;
31 using Mono.Debugger.Languages;
32 using Mono.Debugging.Client;
33 using Mono.Debugging.Backend;
35 namespace DebuggerServer
37 public class CollectionAdaptor: RemoteFrameObject, ICollectionAdaptor, IObjectValueSource
39 EvaluationContext ctx;
40 TargetStructObject obj;
42 TargetPropertyInfo indexerProp;
44 TargetArrayBounds bounds;
45 TargetObject enumerator;
46 List<TargetObject> items = new List<TargetObject> ();
48 static Dictionary<string,ColInfo> colTypes = new Dictionary<string,ColInfo> ();
50 class ColInfo {
51 public TargetPropertyInfo IndexerProp;
54 bool done;
55 string currentObjType;
57 public CollectionAdaptor (EvaluationContext ctx, TargetStructObject obj, TargetPropertyInfo indexerProp)
59 this.ctx = ctx;
60 this.indexerProp = indexerProp;
61 this.obj = obj;
64 public static CollectionAdaptor CreateAdaptor (EvaluationContext ctx, TargetStructObject obj)
66 // Disabled for now since it is not stable
67 return null;
68 /* if (obj is TargetGenericInstanceObject)
69 return null;
70 if (!ctx.Frame.Language.IsManaged)
71 return null;
73 ColInfo colInfo;
74 if (colTypes.TryGetValue (obj.Type.Name, out colInfo)) {
75 if (colInfo == null)
76 return null;
78 else {
79 if (!ObjectUtil.IsInstanceOfType (ctx, "System.Collections.ICollection", obj)) {
80 colTypes [obj.Type.Name] = null;
81 return null;
83 colInfo = new ColInfo ();
84 foreach (MemberReference mem in ObjectUtil.GetTypeMembers (ctx, obj.Type, false, false, true, true, ReqMemberAccess.All)) {
85 if (mem.Member.IsStatic)
86 continue;
87 if (mem.Member is TargetPropertyInfo) {
88 TargetPropertyInfo prop = (TargetPropertyInfo) mem.Member;
89 if (prop.CanRead && prop.Getter.ParameterTypes.Length == 1)
90 colInfo.IndexerProp = prop;
92 if (colInfo.IndexerProp != null)
93 break;
97 if (colInfo.IndexerProp != null) {
98 colTypes [obj.Type.Name] = colInfo;
99 return new CollectionAdaptor (ctx, obj, colInfo.IndexerProp);
101 else {
102 colTypes [obj.Type.Name] = null;
103 return null;
108 public TargetArrayBounds GetBounds ()
110 if (bounds == null) {
111 TargetObject ob = ObjectUtil.GetPropertyValue (ctx, "Count", obj);
112 ob = ObjectUtil.GetRealObject (ctx, ob);
113 TargetFundamentalObject fob = ob as TargetFundamentalObject;
114 int count;
115 if (fob == null)
116 count = 0;
117 else
118 count = Convert.ToInt32 (fob.GetObject (ctx.Thread));
119 bounds = TargetArrayBounds.MakeSimpleArray (count);
121 return bounds;
124 public TargetObject GetElement (int[] indices)
126 int idx = indices [0];
128 if (idx >= items.Count) {
129 if (enumerator == null) {
130 // call GetEnumerator
131 enumerator = ObjectUtil.CallMethod (ctx, "GetEnumerator", obj);
135 while (bounds.Length > items.Count && !done) {
136 // call MoveNext
137 TargetObject eob = ObjectUtil.GetRealObject (ctx, ObjectUtil.CallMethod (ctx, "MoveNext", enumerator));
138 TargetFundamentalObject res = eob as TargetFundamentalObject;
139 if (res == null) {
140 done = true;
141 } else if ((bool) res.GetObject (ctx.Thread)) {
142 // call Current
143 TargetObject current = ObjectUtil.GetPropertyValue (ctx, "Current", enumerator);
144 items.Add (current);
148 if (idx < items.Count)
149 return items [idx];
150 else
151 return null;
154 bool CheckDictionary (TargetObject currentObj)
156 currentObj = ObjectUtil.GetRealObject (ctx, currentObj);
158 if (currentObj.Type.Name == "System.Collections.DictionaryEntry" || currentObj.Type.Name.StartsWith ("KeyValuePair")) {
159 // If the object type changes, we can handle it as a dictionary entry
160 if (currentObjType != null)
161 return currentObjType == currentObj.Type.Name;
163 currentObjType = currentObj.Type.Name;
164 return true;
166 return false;
169 public ObjectValue CreateElementValue (ArrayElementGroup grp, ObjectPath path, int[] indices)
171 TargetObject elem = GetElement (indices);
172 TargetStructObject telem = elem as TargetStructObject;
174 if (telem != null && CheckDictionary (telem)) {
175 string sidx = indices[0].ToString ();
176 TargetObject key = ObjectUtil.GetPropertyValue (ctx, "Key", telem);
177 TargetObject value = ObjectUtil.GetPropertyValue (ctx, "Value", telem);
178 key = ObjectUtil.GetRealObject (ctx, key);
179 value = ObjectUtil.GetRealObject (ctx, value);
180 string val = "{[" + Server.Instance.Evaluator.TargetObjectToExpression (ctx, key) + ", " + Server.Instance.Evaluator.TargetObjectToExpression (ctx, value) + "]}";
181 ObjectValueFlags setFlags = indexerProp.CanWrite ? ObjectValueFlags.None : ObjectValueFlags.ReadOnly;
182 ObjectValue vkey = Util.CreateObjectValue (ctx, this, new ObjectPath (sidx).Append ("key"), key, ObjectValueFlags.ReadOnly | ObjectValueFlags.Property);
183 ObjectValue vvalue = Util.CreateObjectValue (ctx, this, new ObjectPath (sidx).Append ("val"), value, setFlags | ObjectValueFlags.Property);
185 Connect ();
186 return ObjectValue.CreateObject (null, new ObjectPath (sidx), elem.Type.Name, val, ObjectValueFlags.ReadOnly, new ObjectValue [] { vkey, vvalue });
188 else
189 return Util.CreateObjectValue (ctx, grp, path, elem, ObjectValueFlags.ArrayElement);
192 public void SetElement (int[] indices, TargetObject val)
194 TargetFundamentalObject ind = ctx.Frame.Language.CreateInstance (ctx.Thread, indices [0]);
195 TargetFundamentalType ft = indexerProp.Setter.ParameterTypes [0] as TargetFundamentalType;
196 if (ft == null)
197 return;
198 TargetObject newInd = TargetObjectConvert.ExplicitFundamentalConversion (ctx, ind, ft);
199 if (newInd == null)
200 return;
201 ObjectUtil.SetPropertyValue (ctx, null, obj, val, newInd);
205 public TargetType ElementType {
206 get {
207 return indexerProp.Getter.ReturnType;
211 #region IObjectValueSource implementation
213 public ObjectValue[] GetChildren (ObjectPath path, int index, int count)
215 int idx = int.Parse (path [0]);
216 TargetStructObject elem = GetElement (new int [] { idx }) as TargetStructObject;
217 if (elem == null)
218 return new ObjectValue [0];
220 if (path[1] == "key") {
221 TargetObject key = ObjectUtil.GetPropertyValue (ctx, "Key", elem);
222 return Util.GetObjectValueChildren (ctx, key, index, count);
223 } else {
224 TargetObject value = ObjectUtil.GetPropertyValue (ctx, "Value", elem);
225 return Util.GetObjectValueChildren (ctx, value, index, count);
229 public string SetValue (ObjectPath path, string value)
231 int idx = int.Parse (path [0]);
232 TargetStructObject elem = GetElement (new int [] { idx }) as TargetStructObject;
233 if (elem == null || path [1] != "value")
234 return value;
236 TargetObject key = ObjectUtil.GetPropertyValue (ctx, "Key", elem);
238 TargetObject val;
239 try {
240 TargetType elemType = indexerProp.Setter.ParameterTypes [1];
241 EvaluationOptions ops = new EvaluationOptions ();
242 ops.ExpectedType = elemType;
243 ops.CanEvaluateMethods = true;
244 ValueReference var = Server.Instance.Evaluator.Evaluate (ctx, value, ops);
245 val = var.Value;
246 val = TargetObjectConvert.Cast (ctx, val, elemType);
247 ObjectUtil.SetPropertyValue (ctx, null, obj, val, key);
248 } catch (Exception ex) {
249 Server.Instance.WriteDebuggerError (ex);
250 return value;
253 try {
254 val = ObjectUtil.GetPropertyValue (ctx, null, obj, key);
255 return Server.Instance.Evaluator.TargetObjectToExpression (ctx, val);
256 } catch (Exception ex) {
257 Server.Instance.WriteDebuggerError (ex);
258 return value;
262 #endregion