1 // CollectionAdaptor.cs
4 // Lluis Sanchez Gual <lluis@novell.com>
6 // Copyright (c) 2008 Novell, Inc (http://www.novell.com)
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
29 using System
.Collections
.Generic
;
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
> ();
51 public TargetPropertyInfo IndexerProp
;
55 string currentObjType
;
57 public CollectionAdaptor (EvaluationContext ctx
, TargetStructObject obj
, TargetPropertyInfo indexerProp
)
60 this.indexerProp
= indexerProp
;
64 public static CollectionAdaptor
CreateAdaptor (EvaluationContext ctx
, TargetStructObject obj
)
66 // Disabled for now since it is not stable
68 /* if (obj is TargetGenericInstanceObject)
70 if (!ctx.Frame.Language.IsManaged)
74 if (colTypes.TryGetValue (obj.Type.Name, out colInfo)) {
79 if (!ObjectUtil.IsInstanceOfType (ctx, "System.Collections.ICollection", obj)) {
80 colTypes [obj.Type.Name] = 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)
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)
97 if (colInfo.IndexerProp != null) {
98 colTypes [obj.Type.Name] = colInfo;
99 return new CollectionAdaptor (ctx, obj, colInfo.IndexerProp);
102 colTypes [obj.Type.Name] = 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
;
118 count
= Convert
.ToInt32 (fob
.GetObject (ctx
.Thread
));
119 bounds
= TargetArrayBounds
.MakeSimpleArray (count
);
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
) {
137 TargetObject eob
= ObjectUtil
.GetRealObject (ctx
, ObjectUtil
.CallMethod (ctx
, "MoveNext", enumerator
));
138 TargetFundamentalObject res
= eob
as TargetFundamentalObject
;
141 } else if ((bool) res
.GetObject (ctx
.Thread
)) {
143 TargetObject current
= ObjectUtil
.GetPropertyValue (ctx
, "Current", enumerator
);
148 if (idx
< items
.Count
)
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
;
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
);
186 return ObjectValue
.CreateObject (null, new ObjectPath (sidx
), elem
.Type
.Name
, val
, ObjectValueFlags
.ReadOnly
, new ObjectValue
[] { vkey, vvalue }
);
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
;
198 TargetObject newInd
= TargetObjectConvert
.ExplicitFundamentalConversion (ctx
, ind
, ft
);
201 ObjectUtil
.SetPropertyValue (ctx
, null, obj
, val
, newInd
);
205 public TargetType ElementType
{
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
;
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
);
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")
236 TargetObject key
= ObjectUtil
.GetPropertyValue (ctx
, "Key", elem
);
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
);
246 val
= TargetObjectConvert
.Cast (ctx
, val
, elemType
);
247 ObjectUtil
.SetPropertyValue (ctx
, null, obj
, val
, key
);
248 } catch (Exception ex
) {
249 Server
.Instance
.WriteDebuggerError (ex
);
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
);