diff --git a/src/AddIns/Debugger/Debugger.Core/Value.cs b/src/AddIns/Debugger/Debugger.Core/Value.cs
index 78239033c2..5b64d2b140 100644
--- a/src/AddIns/Debugger/Debugger.Core/Value.cs
+++ b/src/AddIns/Debugger/Debugger.Core/Value.cs
@@ -577,7 +577,9 @@ namespace Debugger
if (debuggerDisplayAttribute != null) {
var formatStringParameter = debuggerDisplayAttribute.PositionalArguments.ElementAtOrDefault(0);
if ((formatStringParameter != null) && (formatStringParameter.ConstantValue is string)) {
- return FormatDebugValue(evalThread, (string) formatStringParameter.ConstantValue);
+ // Create a permanent version of this value
+ Value permanentValue = this.GetPermanentReference(evalThread);
+ return FormatDebugValue(evalThread, permanentValue, (string) formatStringParameter.ConstantValue);
}
}
}
@@ -587,41 +589,79 @@ namespace Debugger
}
///
- /// Formats current Value according to the given format, specified by
+ /// Formats current Value according to the given format, specified by .
///
/// Format to use
/// Formatted string.
- string FormatDebugValue(Thread evalThread, string debugFormat)
+ ///
+ /// Not all possible expressions are supported, but only a simple set.
+ /// Otherwise we would have to support any C# expression.
+ ///
+ static string FormatDebugValue(Thread evalThread, Value value, string debugFormat)
{
StringBuilder formattedOutput = new StringBuilder();
StringBuilder currentFieldName = new StringBuilder();
bool insideFieldName = false;
+ bool ignoringRestOfExpression = false;
+ bool insideMethodBrackets = false;
+ bool isMethodName = false;
+ bool escapeNextChar = false;
for (int i = 0; i < debugFormat.Length; i++) {
char thisChar = debugFormat[i];
- if (thisChar == '{') {
+ if (!escapeNextChar && (thisChar == '{')) {
insideFieldName = true;
- } else if (thisChar == '}') {
+ } else if (!escapeNextChar && (thisChar == '}')) {
// Insert contents of specified member, if we can find it, otherwise we display "?"
string memberValueStr = "?";
- IMember member = this.type.GetMembers(
- m => (m.Name == currentFieldName.ToString()) && ((m.SymbolKind == SymbolKind.Field) || (m.SymbolKind == SymbolKind.Property))
- ).FirstOrDefault();
+
+ // Decide if we want a method or field/property
+ Predicate isNeededMember;
+ if (isMethodName) {
+ // We only support methods without parameters here!
+ isNeededMember = m => (m.Name == currentFieldName.ToString())
+ && (m.SymbolKind == SymbolKind.Method)
+ && (((IUnresolvedMethod) m).Parameters.Count == 0);
+ } else {
+ isNeededMember = m => (m.Name == currentFieldName.ToString())
+ && ((m.SymbolKind == SymbolKind.Field) || (m.SymbolKind == SymbolKind.Property));
+ }
+
+ IMember member = value.type.GetMembers(isNeededMember).FirstOrDefault();
if (member != null) {
- Value memberValue = GetMemberValue(evalThread, member);
+ Value memberValue = value.GetMemberValue(evalThread, member);
memberValueStr = memberValue.InvokeToString(evalThread);
}
formattedOutput.Append(memberValueStr);
insideFieldName = false;
+ ignoringRestOfExpression = false;
+ insideMethodBrackets = false;
+ isMethodName = false;
currentFieldName.Clear();
+ } else if (!escapeNextChar && (thisChar == '\\')) {
+ // Next character will be escaped
+ escapeNextChar = true;
+ } else if (insideFieldName && (thisChar == '(')) {
+ insideMethodBrackets = true;
+ } else if ((thisChar == ')') && insideMethodBrackets) {
+ insideMethodBrackets = false;
+ isMethodName = true;
+
+ // Everything following the brackets will be ignored
+ ignoringRestOfExpression = true;
+ } else if (insideFieldName && !Char.IsDigit(thisChar) && !Char.IsLetter(thisChar)) {
+ // Char seems not to belong to a field name, ignore everything from now on
+ ignoringRestOfExpression = true;
} else {
if (insideFieldName) {
- currentFieldName.Append(thisChar);
+ if (!ignoringRestOfExpression)
+ currentFieldName.Append(thisChar);
} else {
formattedOutput.Append(thisChar);
}
+ escapeNextChar = false;
}
}