void IDkmClrResultProvider.GetResult(DkmClrValue value, DkmWorkList workList, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers, string resultName, string resultFullName, DkmCompletionRoutine<DkmEvaluationAsyncResult> completionRoutine) { if (formatSpecifiers == null) { formatSpecifiers = Formatter.NoFormatSpecifiers; } if (resultFullName != null) { ReadOnlyCollection<string> otherSpecifiers; resultFullName = FullNameProvider.GetClrExpressionAndFormatSpecifiers(inspectionContext, resultFullName, out otherSpecifiers); foreach (var formatSpecifier in otherSpecifiers) { formatSpecifiers = Formatter.AddFormatSpecifier(formatSpecifiers, formatSpecifier); } } var wl = new WorkList(workList, e => completionRoutine(DkmEvaluationAsyncResult.CreateErrorResult(e))); wl.ContinueWith( () => GetRootResultAndContinue( value, wl, declaredType, declaredTypeInfo, inspectionContext, resultName, resultFullName, formatSpecifiers, result => wl.ContinueWith(() => completionRoutine(new DkmEvaluationAsyncResult(result))))); }
private DkmEvaluationResult GetRow( ResultProvider resultProvider, DkmInspectionContext inspectionContext, DkmClrValue value, int index, EvalResultDataItem parent) { var indices = GetIndices(index); var formatter = resultProvider.Formatter; var name = formatter.GetArrayIndexExpression(indices); var elementType = value.Type.ElementType; var element = value.GetArrayElement(indices); var fullName = GetFullName(parent, name, formatter); var dataItem = resultProvider.CreateDataItem( inspectionContext, name, typeDeclaringMember: null, declaredType: elementType.GetLmrType(), value: element, parent: parent, expansionFlags: ExpansionFlags.IncludeBaseMembers, childShouldParenthesize: false, fullName: fullName, formatSpecifiers: Formatter.NoFormatSpecifiers, category: DkmEvaluationResultCategory.Other, flags: element.EvalFlags, evalFlags: inspectionContext.EvaluationFlags); return resultProvider.GetResult(dataItem, element.Type, elementType, parent); }
public EvalResultDataItem( string name, Type typeDeclaringMember, Type declaredType, DkmClrValue value, Expansion expansion, bool childShouldParenthesize, string fullName, string childFullNamePrefixOpt, ReadOnlyCollection<string> formatSpecifiers, DkmEvaluationResultCategory category, DkmEvaluationResultFlags flags, string editableValue) { Debug.Assert(formatSpecifiers != null); Debug.Assert((flags & DkmEvaluationResultFlags.Expandable) == 0); this.NameOpt = name; this.TypeDeclaringMember = typeDeclaringMember; this.DeclaredType = declaredType; this.Value = value; this.ChildShouldParenthesize = childShouldParenthesize; this.FullNameWithoutFormatSpecifiers = fullName; this.ChildFullNamePrefix = childFullNamePrefixOpt; this.FormatSpecifiers = formatSpecifiers; this.Category = category; this.EditableValue = editableValue; this.Flags = flags | GetFlags(value) | ((expansion == null) ? DkmEvaluationResultFlags.None : DkmEvaluationResultFlags.Expandable); this.Expansion = expansion; }
/// <summary> /// Generate a Results Only row if the value is a synthesized /// value declared as IEnumerable or IEnumerable<T>. /// </summary> internal static EvalResultDataItem CreateResultsOnlyRowIfSynthesizedEnumerable( DkmInspectionContext inspectionContext, string name, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmClrValue value, Formatter formatter) { if ((value.ValueFlags & DkmClrValueFlags.Synthetic) == 0) { return null; } // Must be declared as IEnumerable or IEnumerable<T>, not a derived type. var enumerableType = GetEnumerableType(value, declaredType, requireExactInterface: true); if (enumerableType == null) { return null; } var expansion = CreateExpansion(inspectionContext, value, enumerableType, formatter); if (expansion == null) { return null; } return expansion.CreateResultsViewRow( inspectionContext, name, new TypeAndCustomInfo(declaredType.GetLmrType(), declaredTypeInfo), value, includeResultsFormatSpecifier: false, formatter: formatter); }
string IDkmClrFormatter.GetValueString(DkmClrValue value, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers) { var options = ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoQuotes) == 0) ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None; return GetValueString(value, inspectionContext, options, GetValueFlags.IncludeObjectId); }
private DkmClrValue GetFunctionPointerField(DkmClrValue value, string fieldName) { var valueType = value.Type.GetLmrType(); var fieldInfo = valueType.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var fieldValue = fieldInfo.GetValue(value.RawValue); return CreateDkmClrValue(DkmClrValue.UnboxPointer(fieldValue), new DkmClrType(FunctionPointerType.Instance)); }
private EvalResult GetRow( ResultProvider resultProvider, DkmInspectionContext inspectionContext, DkmClrValue value, int index, EvalResultDataItem parent) { var indices = GetIndices(index); var fullNameProvider = resultProvider.FullNameProvider; var name = fullNameProvider.GetClrArrayIndexExpression(inspectionContext, indices); var element = value.GetArrayElement(indices, inspectionContext); var fullName = GetFullName(inspectionContext, parent, name, fullNameProvider); return resultProvider.CreateDataItem( inspectionContext, name, typeDeclaringMemberAndInfo: default(TypeAndCustomInfo), declaredTypeAndInfo: _elementTypeAndInfo, value: element, useDebuggerDisplay: parent != null, expansionFlags: ExpansionFlags.IncludeBaseMembers, childShouldParenthesize: false, fullName: fullName, formatSpecifiers: Formatter.NoFormatSpecifiers, category: DkmEvaluationResultCategory.Other, flags: element.EvalFlags, evalFlags: inspectionContext.EvaluationFlags); }
private EvalResult GetRow( DkmInspectionContext inspectionContext, DkmClrValue value, int index, EvalResultDataItem parent) { var typeParameter = _typeParameters[index]; var typeArgument = _typeArguments[index]; var typeArgumentInfo = _customTypeInfoMap.SubstituteCustomTypeInfo(typeParameter, customInfo: null); var formatSpecifiers = Formatter.NoFormatSpecifiers; return new EvalResult( ExpansionKind.TypeVariable, typeParameter.Name, typeDeclaringMemberAndInfo: default(TypeAndCustomInfo), declaredTypeAndInfo: new TypeAndCustomInfo(DkmClrType.Create(value.Type.AppDomain, typeArgument), typeArgumentInfo), useDebuggerDisplay: parent != null, value: value, displayValue: inspectionContext.GetTypeName(DkmClrType.Create(value.Type.AppDomain, typeArgument), typeArgumentInfo, formatSpecifiers), expansion: null, childShouldParenthesize: false, fullName: null, childFullNamePrefixOpt: null, formatSpecifiers: formatSpecifiers, category: DkmEvaluationResultCategory.Data, flags: DkmEvaluationResultFlags.ReadOnly, editableValue: null, inspectionContext: inspectionContext); }
private static DkmClrType GetEnumerableType(DkmClrValue value) { Debug.Assert(!value.IsError()); if (value.IsNull) { return null; } var valueType = value.Type.GetLmrType(); // Do not support Results View for strings // or arrays. (Matches legacy EE.) if (valueType.IsString() || valueType.IsArray) { return null; } var enumerableType = valueType.GetIEnumerableImplementationIfAny(); if (enumerableType == null) { return null; } return DkmClrType.Create(value.Type.AppDomain, enumerableType); }
internal static DynamicViewExpansion CreateExpansion(DkmInspectionContext inspectionContext, DkmClrValue value, ResultProvider resultProvider) { if (value.IsError() || value.IsNull || value.HasExceptionThrown()) { return null; } var type = value.Type.GetLmrType(); if (!(type.IsComObject() || type.IsIDynamicMetaObjectProvider())) { return null; } var proxyValue = value.InstantiateDynamicViewProxy(inspectionContext); Debug.Assert((proxyValue == null) || (!proxyValue.IsNull && !proxyValue.IsError() && !proxyValue.HasExceptionThrown())); // InstantiateDynamicViewProxy may return null (if required assembly is missing, for instance). if (proxyValue == null) { return null; } // Expansion is based on the 'DynamicMetaObjectProviderDebugView.Items' property. var proxyType = proxyValue.Type; var itemsMemberExpansion = RootHiddenExpansion.CreateExpansion( proxyType.GetMemberByName("Items"), DynamicFlagsMap.Create(new TypeAndCustomInfo(proxyType))); return new DynamicViewExpansion(proxyValue, itemsMemberExpansion); }
internal override void GetRows( ResultProvider resultProvider, ArrayBuilder<EvalResult> rows, DkmInspectionContext inspectionContext, EvalResultDataItem parent, DkmClrValue value, int startIndex, int count, bool visitAll, ref int index) { var fields = GetFields(); int startIndex2; int count2; GetIntersection(startIndex, count, index, fields.Count, out startIndex2, out count2); int offset = startIndex2 - index; for (int i = 0; i < count2; i++) { var row = GetMemberRow(resultProvider, inspectionContext, value, fields[i + offset], parent); rows.Add(row); } index += fields.Count; }
private DynamicViewExpansion(DkmClrValue proxyValue, Expansion proxyMembers) { Debug.Assert(proxyValue != null); Debug.Assert(proxyMembers != null); _proxyValue = proxyValue; _proxyMembers = proxyMembers; }
internal static ResultsViewExpansion CreateExpansion(DkmInspectionContext inspectionContext, DkmClrValue value, Formatter formatter) { var enumerableType = GetEnumerableType(value); if (enumerableType == null) { return null; } return CreateExpansion(inspectionContext, value, enumerableType, formatter); }
internal static TupleExpansion CreateExpansion(DkmClrValue value, TypeAndCustomInfo declaredTypeAndInfo, int cardinality) { if (value.IsNull) { // No expansion. return null; } return new TupleExpansion(new TypeAndCustomInfo(value.Type, declaredTypeAndInfo.Info), cardinality); }
string IDkmClrFormatter.GetValueString(DkmClrValue clrValue) { // TODO: IDkmClrFormatter.GetValueString should have // an explicit InspectionContext parameter that is not // inherited from the containing DkmClrValue. #1099978 var options = ((clrValue.InspectionContext.EvaluationFlags & DkmEvaluationFlags.NoQuotes) == 0) ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None; return GetValueString(clrValue, options, GetValueFlags.IncludeObjectId); }
/// <summary> /// Get the rows within the given range. 'index' is advanced /// to the end of the range, or if 'visitAll' is true, 'index' is /// advanced to the end of the expansion. /// </summary> internal abstract void GetRows( ResultProvider resultProvider, ArrayBuilder<DkmEvaluationResult> rows, DkmInspectionContext inspectionContext, EvalResultDataItem parent, DkmClrValue value, int startIndex, int count, bool visitAll, ref int index);
internal static EvalResult CreateMembersOnlyRow( DkmInspectionContext inspectionContext, string name, DkmClrValue value, ResultProvider resultProvider) { var expansion = CreateExpansion(inspectionContext, value, resultProvider); return (expansion != null) ? expansion.CreateDynamicViewRow(inspectionContext, name, parent: null, fullNameProvider: resultProvider.FullNameProvider) : new EvalResult(name, Resources.DynamicViewNotDynamic, inspectionContext); }
internal static EvalResultDataItem CreateMembersOnlyRow( DkmInspectionContext inspectionContext, string name, DkmClrValue value, Formatter formatter) { var expansion = CreateExpansion(inspectionContext, value, formatter); return (expansion != null) ? expansion.CreateDynamicViewRow(inspectionContext, name, parent: null, formatter: formatter) : new EvalResultDataItem(name, Resources.DynamicViewNotDynamic); }
internal DkmEvaluationResult GetResult(DkmClrValue value, DkmClrType declaredType, ReadOnlyCollection<string> formatSpecifiers, string resultName, string resultFullName) { // TODO: Use full name try { return GetRootResult(value, declaredType, resultName); } catch (Exception e) when (ExpressionEvaluatorFatalError.CrashIfFailFastEnabled(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// This method is called by the debug engine to populate the text representing the value /// of an expression. /// </summary> /// <param name="clrValue">The raw value to get the text for</param> /// <param name="inspectionContext">Context of the evaluation. This contains options/flags /// to be used during compilation. It also contains the InspectionSession. The inspection /// session is the object that provides lifetime management for our objects. When the user /// steps or continues the process, the debug engine will dispose of the inspection session</param> /// <param name="formatSpecifiers"></param> /// <returns>The text representing the given value</returns> string IDkmClrFormatter.GetValueString(DkmClrValue clrValue, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers) { DkmClrType clrType = clrValue.Type; if (clrType == null) { // This can be null in some error cases return string.Empty; } // Try to format the value. If we can't format the value, delegate to the C# Formatter. string value = TryFormatValue(clrValue, inspectionContext); return value ?? clrValue.GetValueString(inspectionContext, formatSpecifiers); }
private static DkmEvaluationResult GetRow( ResultProvider resultProvider, DkmInspectionContext inspectionContext, DkmClrValue pointer, Type elementType, EvalResultDataItem parent) { var value = pointer.Dereference(); var valueType = value.Type.GetLmrType(); var wasExceptionThrown = value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown); string debuggerDisplayName; string debuggerDisplayValue; string debuggerDisplayType; value.GetDebuggerDisplayStrings(out debuggerDisplayName, out debuggerDisplayValue, out debuggerDisplayType); var declaredType = elementType; var typeName = debuggerDisplayType ?? pointer.InspectionContext.GetTypeName(DkmClrType.Create(pointer.Type.AppDomain, declaredType)); var expansion = wasExceptionThrown ? null : resultProvider.GetTypeExpansion(inspectionContext, declaredType, value, ExpansionFlags.None); var fullName = string.Format("*{0}", parent.ChildFullNamePrefix); var editableValue = resultProvider.Formatter.GetEditableValue(value); // NB: Full name is based on the real (i.e. not DebuggerDisplay) name. This is a change from dev12, // which used the DebuggerDisplay name, causing surprising results in "Add Watch" scenarios. var dataItem = new EvalResultDataItem( name: null, // Okay for pointer dereferences. typeDeclaringMember: null, declaredType: declaredType, value: value, expansion: expansion, childShouldParenthesize: true, fullName: fullName, childFullNamePrefixOpt: fullName, formatSpecifiers: Formatter.NoFormatSpecifiers, category: DkmEvaluationResultCategory.Other, flags: DkmEvaluationResultFlags.None, editableValue: editableValue); var name = debuggerDisplayName ?? fullName; var display = debuggerDisplayValue ?? (wasExceptionThrown ? string.Format(Resources.InvalidPointerDereference, fullName) : value.GetValueString()); return ResultProvider.CreateEvaluationResult( value, name, typeName, display, dataItem); }
void IDkmClrResultProvider.GetResult(DkmClrValue value, DkmWorkList workList, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmInspectionContext inspectionContext, ReadOnlyCollection<string> formatSpecifiers, string resultName, string resultFullName, DkmCompletionRoutine<DkmEvaluationAsyncResult> completionRoutine) { // TODO: Use full name var wl = new WorkList(workList, e => completionRoutine(DkmEvaluationAsyncResult.CreateErrorResult(e))); GetRootResultAndContinue( value, wl, declaredType, declaredTypeInfo, inspectionContext, resultName, result => wl.ContinueWith(() => completionRoutine(new DkmEvaluationAsyncResult(result)))); wl.Execute(); }
internal static TupleExpansion CreateExpansion( DkmInspectionContext inspectionContext, TypeAndCustomInfo declaredTypeAndInfo, DkmClrValue value, int cardinality) { if (value.IsNull) { // No expansion. return null; } bool useRawView = (inspectionContext.EvaluationFlags & DkmEvaluationFlags.ShowValueRaw) != 0; return new TupleExpansion(new TypeAndCustomInfo(value.Type, declaredTypeAndInfo.Info), cardinality, useRawView); }
private static EvalResult GetMemberRow( ResultProvider resultProvider, DkmInspectionContext inspectionContext, DkmClrValue value, Field field, EvalResultDataItem parent) { var fullNameProvider = resultProvider.FullNameProvider; var parentFullName = parent.ChildFullNamePrefix; if (parentFullName != null) { if (parent.ChildShouldParenthesize) { parentFullName = parentFullName.Parenthesize(); } var parentRuntimeType = parent.Value.Type; if (!parent.DeclaredTypeAndInfo.Type.Equals(parentRuntimeType.GetLmrType())) { parentFullName = fullNameProvider.GetClrCastExpression(inspectionContext, parentFullName, parentRuntimeType, customTypeInfo: null, parenthesizeArgument: false, parenthesizeEntireExpression: true); } } // Ideally if the caller requests multiple items in a nested tuple // we should only evaluate Rest once, and should only calculate // the full name for Rest once. string fullName; var fieldValue = GetValueAndFullName( fullNameProvider, inspectionContext, value, field, parentFullName, out fullName); return resultProvider.CreateDataItem( inspectionContext, field.Name, typeDeclaringMemberAndInfo: default(TypeAndCustomInfo), declaredTypeAndInfo: field.FieldTypeAndInfo, value: fieldValue, useDebuggerDisplay: false, expansionFlags: ExpansionFlags.All, childShouldParenthesize: false, fullName: fullName, formatSpecifiers: Formatter.NoFormatSpecifiers, category: DkmEvaluationResultCategory.Other, flags: fieldValue.EvalFlags, evalFlags: DkmEvaluationFlags.None); }
internal static EvalResult CreateResultsOnlyRow( DkmInspectionContext inspectionContext, string name, string fullName, ReadOnlyCollection<string> formatSpecifiers, DkmClrType declaredType, DkmClrCustomTypeInfo declaredTypeInfo, DkmClrValue value, ResultProvider resultProvider) { string errorMessage; if (value.IsError()) { errorMessage = (string)value.HostObjectValue; } else if (value.HasExceptionThrown()) { errorMessage = value.GetExceptionMessage(inspectionContext, name); } else { var enumerableType = GetEnumerableType(value); if (enumerableType != null) { var expansion = CreateExpansion(inspectionContext, value, enumerableType, resultProvider); if (expansion != null) { return expansion.CreateResultsViewRow( inspectionContext, name, fullName, formatSpecifiers, new TypeAndCustomInfo(declaredType, declaredTypeInfo), value, includeResultsFormatSpecifier: true, fullNameProvider: resultProvider.FullNameProvider); } errorMessage = Resources.ResultsViewNoSystemCore; } else { errorMessage = Resources.ResultsViewNotEnumerable; } } Debug.Assert(errorMessage != null); return new EvalResult(name, errorMessage, inspectionContext); }
internal static DkmEvaluationResult CreateResultsOnly( string name, DkmClrType declaredType, DkmClrValue value, EvalResultDataItem parent, Formatter formatter) { string errorMessage; if (value.IsError()) { errorMessage = (string)value.HostObjectValue; } else if (value.HasExceptionThrown(parent)) { errorMessage = value.GetExceptionMessage(name, formatter); } else { var enumerableType = GetEnumerableType(value); if (enumerableType != null) { var expansion = CreateExpansion(value, enumerableType, formatter); if (expansion != null) { return expansion.CreateEvaluationResult(name, parent, formatter); } errorMessage = Resources.ResultsViewNoSystemCore; } else { errorMessage = Resources.ResultsViewNotEnumerable; } } Debug.Assert(errorMessage != null); return DkmFailedEvaluationResult.Create( InspectionContext: value.InspectionContext, StackFrame: value.StackFrame, Name: name, FullName: null, ErrorMessage: errorMessage, Flags: DkmEvaluationResultFlags.None, Type: null, DataItem: null); }
internal override void GetRows( ResultProvider resultProvider, ArrayBuilder<EvalResultDataItem> rows, DkmInspectionContext inspectionContext, EvalResultDataItem parent, DkmClrValue value, int startIndex, int count, bool visitAll, ref int index) { if (InRange(startIndex, count, index)) { rows.Add(GetRow(resultProvider, inspectionContext, value, _elementTypeAndInfo, parent: parent)); } index++; }
internal override void GetRows( ResultProvider resultProvider, ArrayBuilder<EvalResult> rows, DkmInspectionContext inspectionContext, EvalResultDataItem parent, DkmClrValue value, int startIndex, int count, bool visitAll, ref int index) { if (InRange(startIndex, count, index)) { rows.Add(CreateDynamicViewRow(inspectionContext, Resources.DynamicView, parent, resultProvider.FullNameProvider)); } index++; }
internal override void GetRows( ResultProvider resultProvider, ArrayBuilder<EvalResult> rows, DkmInspectionContext inspectionContext, EvalResultDataItem parent, DkmClrValue value, int startIndex, int count, bool visitAll, ref int index) { var memberValue = value.GetMemberValue(_member, inspectionContext); var isDynamicDebugViewEmptyException = memberValue.Type.GetLmrType().IsDynamicDebugViewEmptyException(); if (isDynamicDebugViewEmptyException || memberValue.IsError()) { if (InRange(startIndex, count, index)) { if (isDynamicDebugViewEmptyException) { var emptyMember = memberValue.Type.GetMemberByName("Empty"); memberValue = memberValue.GetMemberValue(emptyMember, inspectionContext); } var row = new EvalResult(Resources.ErrorName, (string)memberValue.HostObjectValue, inspectionContext); rows.Add(row); } index++; } else { var other = MemberExpansion.CreateMemberDataItem( resultProvider, inspectionContext, _member, memberValue, parent, _dynamicFlagsMap, ExpansionFlags.IncludeBaseMembers | ExpansionFlags.IncludeResultsView); var expansion = other.Expansion; if (expansion != null) { expansion.GetRows(resultProvider, rows, inspectionContext, other.ToDataItem(), other.Value, startIndex, count, visitAll, ref index); } } }
public EvalResultDataItem( string name, TypeAndCustomInfo declaredTypeAndInfo, DkmClrValue value, Expansion expansion, bool childShouldParenthesize, string fullNameWithoutFormatSpecifiers, string childFullNamePrefixOpt, ReadOnlyCollection<string> formatSpecifiers) { this.Name = name; this.DeclaredTypeAndInfo = declaredTypeAndInfo; this.Value = value; this.ChildShouldParenthesize = childShouldParenthesize; this.FullNameWithoutFormatSpecifiers = fullNameWithoutFormatSpecifiers; this.ChildFullNamePrefix = childFullNamePrefixOpt; this.FormatSpecifiers = formatSpecifiers; this.Expansion = expansion; }
/// <remarks> /// Very simple expression evaluation (may not support all syntax supported by Concord). /// </remarks> public string EvaluateDebuggerDisplayString(string formatString) { Debug.Assert(!this.IsNull, "Not supported by VIL"); var pooled = PooledStringBuilder.GetInstance(); var builder = pooled.Builder; int openPos = -1; int length = formatString.Length; for (int i = 0; i < length; i++) { char ch = formatString[i]; if (ch == '{') { if (openPos >= 0) { throw new ArgumentException(string.Format("Nested braces in '{0}'", formatString)); } openPos = i; } else if (ch == '}') { if (openPos < 0) { throw new ArgumentException(string.Format("Unmatched closing brace in '{0}'", formatString)); } string name = formatString.Substring(openPos + 1, i - openPos - 1); openPos = -1; // Ignore any format specifiers. int commaIndex = name.IndexOf(','); if (commaIndex >= 0) { name = name.Substring(0, commaIndex); } var type = ((TypeImpl)this.Type.GetLmrType()).Type; var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; DkmClrValue exprValue; var appDomain = this.Type.AppDomain; var field = type.GetField(name, bindingFlags); if (field != null) { var fieldValue = field.GetValue(_rawValue); exprValue = new DkmClrValue( fieldValue, fieldValue, DkmClrType.Create(appDomain, (TypeImpl)((fieldValue == null) ? field.FieldType : fieldValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(fieldValue), valueFlags: DkmClrValueFlags.None, inspectionContext: this.InspectionContext); } else { var property = type.GetProperty(name, bindingFlags); if (property != null) { var propertyValue = property.GetValue(_rawValue); exprValue = new DkmClrValue( propertyValue, propertyValue, DkmClrType.Create(appDomain, (TypeImpl)((propertyValue == null) ? property.PropertyType : propertyValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(propertyValue), valueFlags: DkmClrValueFlags.None, inspectionContext: this.InspectionContext); } else { var openParenIndex = name.IndexOf('('); if (openParenIndex >= 0) { name = name.Substring(0, openParenIndex); } var method = type.GetMethod(name, bindingFlags); // The real implementation requires parens on method invocations, so // we'll return error if there wasn't at least an open paren... if ((openParenIndex >= 0) && method != null) { var methodValue = method.Invoke(_rawValue, new object[] { }); exprValue = new DkmClrValue( methodValue, methodValue, DkmClrType.Create(appDomain, (TypeImpl)((methodValue == null) ? method.ReturnType : methodValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(methodValue), valueFlags: DkmClrValueFlags.None, inspectionContext: this.InspectionContext); } else { var stringValue = "Problem evaluating expression"; var stringType = DkmClrType.Create(appDomain, (TypeImpl)typeof(string)); exprValue = new DkmClrValue( stringValue, stringValue, stringType, alias: null, formatter: _formatter, evalFlags: DkmEvaluationResultFlags.None, valueFlags: DkmClrValueFlags.Error, inspectionContext: this.InspectionContext); } } } builder.Append(exprValue.GetValueString()); // Re-enter the formatter. } else if (openPos < 0) { builder.Append(ch); } } if (openPos >= 0) { throw new ArgumentException(string.Format("Unmatched open brace in '{0}'", formatString)); } return(pooled.ToStringAndFree()); }
/// <remarks> /// Very simple expression evaluation (may not support all syntax supported by Concord). /// </remarks> public void EvaluateDebuggerDisplayString(DkmWorkList workList, DkmInspectionContext inspectionContext, DkmClrType targetType, string formatString, DkmCompletionRoutine <DkmEvaluateDebuggerDisplayStringAsyncResult> completionRoutine) { Debug.Assert(!this.IsNull, "Not supported by VIL"); if (inspectionContext == null) { throw new ArgumentNullException(nameof(inspectionContext)); } var pooled = PooledStringBuilder.GetInstance(); var builder = pooled.Builder; int openPos = -1; int length = formatString.Length; for (int i = 0; i < length; i++) { char ch = formatString[i]; if (ch == '{') { if (openPos >= 0) { throw new ArgumentException(string.Format("Nested braces in '{0}'", formatString)); } openPos = i; } else if (ch == '}') { if (openPos < 0) { throw new ArgumentException(string.Format("Unmatched closing brace in '{0}'", formatString)); } string name = formatString.Substring(openPos + 1, i - openPos - 1); openPos = -1; var formatSpecifiers = Formatter.NoFormatSpecifiers; int commaIndex = name.IndexOf(','); if (commaIndex >= 0) { var rawFormatSpecifiers = name.Substring(commaIndex + 1).Split(','); var trimmedFormatSpecifiers = ArrayBuilder <string> .GetInstance(rawFormatSpecifiers.Length); trimmedFormatSpecifiers.AddRange(rawFormatSpecifiers.Select(fs => fs.Trim())); formatSpecifiers = trimmedFormatSpecifiers.ToImmutableAndFree(); foreach (var formatSpecifier in formatSpecifiers) { if (formatSpecifier == "nq") { inspectionContext = new DkmInspectionContext(_formatter, inspectionContext.EvaluationFlags | DkmEvaluationFlags.NoQuotes, inspectionContext.Radix, inspectionContext.RuntimeInstance); } // If we need to support additional format specifiers, add them here... } name = name.Substring(0, commaIndex); } var type = ((TypeImpl)this.Type.GetLmrType()).Type; const System.Reflection.BindingFlags bindingFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static; DkmClrValue exprValue; var appDomain = this.Type.AppDomain; var field = type.GetField(name, bindingFlags); if (field != null) { var fieldValue = field.GetValue(RawValue); exprValue = new DkmClrValue( fieldValue, fieldValue, DkmClrType.Create(appDomain, (TypeImpl)((fieldValue == null) ? field.FieldType : fieldValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(fieldValue), valueFlags: DkmClrValueFlags.None); } else { var property = type.GetProperty(name, bindingFlags); if (property != null) { var propertyValue = property.GetValue(RawValue); exprValue = new DkmClrValue( propertyValue, propertyValue, DkmClrType.Create(appDomain, (TypeImpl)((propertyValue == null) ? property.PropertyType : propertyValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(propertyValue), valueFlags: DkmClrValueFlags.None); } else { var openParenIndex = name.IndexOf('('); if (openParenIndex >= 0) { name = name.Substring(0, openParenIndex); } var method = type.GetMethod(name, bindingFlags); // The real implementation requires parens on method invocations, so // we'll return error if there wasn't at least an open paren... if ((openParenIndex >= 0) && method != null) { var methodValue = method.Invoke(RawValue, new object[] { }); exprValue = new DkmClrValue( methodValue, methodValue, DkmClrType.Create(appDomain, (TypeImpl)((methodValue == null) ? method.ReturnType : methodValue.GetType())), alias: null, formatter: _formatter, evalFlags: GetEvaluationResultFlags(methodValue), valueFlags: DkmClrValueFlags.None); } else { var stringValue = "Problem evaluating expression"; var stringType = DkmClrType.Create(appDomain, (TypeImpl)typeof(string)); exprValue = new DkmClrValue( stringValue, stringValue, stringType, alias: null, formatter: _formatter, evalFlags: DkmEvaluationResultFlags.None, valueFlags: DkmClrValueFlags.Error); } } } builder.Append(exprValue.GetValueString(inspectionContext, formatSpecifiers)); // Re-enter the formatter. } else if (openPos < 0) { builder.Append(ch); } } if (openPos >= 0) { throw new ArgumentException(string.Format("Unmatched open brace in '{0}'", formatString)); } workList.AddWork(() => completionRoutine(new DkmEvaluateDebuggerDisplayStringAsyncResult(pooled.ToStringAndFree()))); }