pascalabcnet/VisualPascalABCNETLinux/MonoDebugging/Soft/FieldValueReference.cs

214 lines
6.7 KiB
C#
Raw Normal View History

2023-04-10 22:04:27 +03:00
//
// FieldValueReference.cs
//
// Authors: Lluis Sanchez Gual <lluis@novell.com>
// Jeffrey Stedfast <jeff@xamarin.com>
//
// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Reflection;
using Mono.Debugging.Evaluation;
using Mono.Debugger.Soft;
using Mono.Debugging.Client;
using System.Collections.Generic;
using System.Linq;
namespace Mono.Debugging.Soft
{
public class FieldValueReference: SoftValueReference
{
FieldInfoMirror field;
object obj;
TypeMirror declaringType;
ObjectValueFlags flags;
string vname;
FieldReferenceBatch batch;
public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, FieldReferenceBatch batch = null)
: this (ctx, field, obj, declaringType, null, ObjectValueFlags.Field, batch)
{
}
public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, string vname, ObjectValueFlags vflags, FieldReferenceBatch batch = null): base (ctx)
{
this.field = field;
this.obj = obj;
this.declaringType = declaringType;
this.vname = vname;
this.batch = batch;
if (field.IsStatic)
this.obj = null;
var objectMirror = obj as ObjectMirror;
if (objectMirror != null)
EnsureContextHasDomain (objectMirror.Domain);
flags = GetFlags (field);
// if `vflags` already has an origin specified, we need to unset the `Field` flag which is always returned by GetFlags().
if ((vflags & ObjectValueFlags.OriginMask) != 0)
flags &= ~ObjectValueFlags.Field;
flags |= vflags;
if (obj is PrimitiveValue)
flags |= ObjectValueFlags.ReadOnly;
}
internal static ObjectValueFlags GetFlags (FieldInfoMirror field)
{
var flags = ObjectValueFlags.Field;
if (field.IsStatic)
flags |= ObjectValueFlags.Global;
if (field.IsPublic)
flags |= ObjectValueFlags.Public;
else if (field.IsPrivate)
flags |= ObjectValueFlags.Private;
else if (field.IsFamily)
flags |= ObjectValueFlags.Protected;
else if (field.IsFamilyAndAssembly)
flags |= ObjectValueFlags.Internal;
else if (field.IsFamilyOrAssembly)
flags |= ObjectValueFlags.InternalProtected;
return flags;
}
public override ObjectValueFlags Flags {
get {
return flags;
}
}
public override string Name {
get {
return vname ?? field.Name;
}
}
public override object Type {
get {
return field.FieldType;
}
}
public override object DeclaringType {
get {
return field.DeclaringType;
}
}
public override object Value {
get {
if (obj == null) {
// If the type hasn't already been loaded, invoke the .cctor() for types w/ the BeforeFieldInit attribute.
Context.Adapter.ForceLoadType (Context, declaringType);
return declaringType.GetValue (field, ((SoftEvaluationContext)Context).Thread);
} else if (obj is ObjectMirror) {
if (batch != null)
return batch.GetValue (field);
return ((ObjectMirror)obj).GetValue (field);
} else if (obj is StructMirror) {
StructMirror sm = (StructMirror)obj;
int idx = 0;
foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
if (f.IsStatic) continue;
if (f == field)
break;
idx++;
}
return sm.Fields [idx];
} else if (obj is StringMirror) {
SoftEvaluationContext cx = (SoftEvaluationContext) Context;
StringMirror val = (StringMirror) obj;
FieldInfo rfield = typeof(string).GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
} else {
SoftEvaluationContext cx = (SoftEvaluationContext) Context;
PrimitiveValue val = (PrimitiveValue) obj;
if (val.Value == null)
return null;
FieldInfo rfield = val.Value.GetType ().GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
}
}
set {
if (obj == null)
declaringType.SetValue (field, (Value)value);
else if (obj is ObjectMirror) {
if (batch != null)
batch.Invalidate ();
((ObjectMirror)obj).SetValue (field, (Value)value);
}
else if (obj is StructMirror) {
StructMirror sm = (StructMirror)obj;
int idx = 0;
foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
if (f.IsStatic) continue;
if (f == field)
break;
idx++;
}
if (idx != -1) {
sm.Fields [idx] = (Value)value;
// Structs are handled by-value in the debugger, so the source of the object has to be updated
if (ParentSource != null && obj != null)
ParentSource.Value = obj;
}
}
else
throw new NotSupportedException ();
}
}
internal string [] GetTupleElementNames ()
{
return GetTupleElementNames (field.GetCustomAttributes (true));
}
internal static string [] GetTupleElementNames (CustomAttributeDataMirror [] attrs)
{
var attr = attrs.FirstOrDefault (at => at.Constructor.DeclaringType.Name == "TupleElementNamesAttribute");
if (attr == null)
return null;
var attributeValue = attr.ConstructorArguments.Single ().Value;
var array = attributeValue as ArrayMirror;
if (array == null)
return null;
var values = array.GetValues (0, array.Length);
if (!values.Any ())
return null;
var result = new string [values.Count];
for (int i = 0; i < result.Length; i++) {
if (values [i] is StringMirror s)//other than string is null
result [i] = s.Value;
}
return result;
}
}
}