From e7d334641dc30ebabcfe94c2133d5109ce3fe0d4 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 15 Dec 2015 18:13:06 -0800 Subject: [PATCH] Introduce ObjectDisplayOptions.EscapeNonPrintableStringCharacters It used to be always on in C# and implied by UseQuotes in VB. Now it can be manipulated separately. This will allow us to print unescaped strings in the C# interactive window. --- .../Portable/SymbolDisplay/ObjectDisplay.cs | 14 ++++++-- .../Portable/SymbolDisplay/SymbolDisplay.cs | 6 ++-- .../SymbolDisplay/ObjectDisplayTests.cs | 18 ++++++++-- .../SymbolDisplay/ObjectDisplayOptions.cs | 8 ++++- .../Portable/SymbolDisplay/ObjectDisplay.vb | 36 +++++++++++-------- .../Portable/SymbolDisplay/SymbolDisplay.vb | 4 +-- .../Portable/Syntax/SyntaxFactory.vb | 4 +-- .../SymbolDisplay/ObjectDisplayTests.vb | 16 +++++++-- .../ResultProvider/CSharpFormatter.Values.cs | 4 ++- .../Source/ResultProvider/CSharpFormatter.cs | 11 ++++++ .../Source/ResultProvider/Formatter.Values.cs | 6 ++-- .../Core/Source/ResultProvider/Formatter.cs | 7 ++-- .../VisualBasicFormatter.Values.vb | 6 ++++ .../ResultProvider/VisualBasicFormatter.vb | 30 ++++------------ .../ObjectFormatter/CSharpObjectFormatter.cs | 2 +- 15 files changed, 110 insertions(+), 62 deletions(-) diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs index 4fc48d546f1..afdaef2ae0d 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/ObjectDisplay.cs @@ -255,8 +255,9 @@ public static string FormatLiteral(string value, ObjectDisplayOptions options) } var useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes); + var escapeNonPrintable = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableStringCharacters); var quote = useQuotes ? '"' : '\0'; - if (!useQuotes && !ReplaceAny(value, quote)) + if (!useQuotes && !(escapeNonPrintable && ReplaceAny(value, quote))) { return value; } @@ -267,9 +268,16 @@ public static string FormatLiteral(string value, ObjectDisplayOptions options) { builder.Append(quote); } - foreach (var c in value) + if (escapeNonPrintable) { - FormatStringChar(builder, c, quote); + foreach (var c in value) + { + FormatStringChar(builder, c, quote); + } + } + else + { + builder.Append(value); } if (useQuotes) { diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs index 27d718904c6..415e37f95b2 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs @@ -145,7 +145,7 @@ public static class SymbolDisplay /// public static string FormatPrimitive(object obj, bool quoteStrings, bool useHexadecimalNumbers) { - var options = ObjectDisplayOptions.None; + var options = ObjectDisplayOptions.EscapeNonPrintableStringCharacters; if (quoteStrings) { options |= ObjectDisplayOptions.UseQuotes; @@ -168,7 +168,9 @@ public static string FormatPrimitive(object obj, bool quoteStrings, bool useHexa /// public static string FormatLiteral(string value, bool quote) { - return ObjectDisplay.FormatLiteral(value, quote ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None); + var options = ObjectDisplayOptions.EscapeNonPrintableStringCharacters | + (quote ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None); + return ObjectDisplay.FormatLiteral(value, options); } /// diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/ObjectDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/ObjectDisplayTests.cs index 72393112593..277b2e62715 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/ObjectDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/ObjectDisplayTests.cs @@ -261,21 +261,33 @@ public void TypeSuffixes() Assert.Equal("12.5M", FormatPrimitiveIncludingTypeSuffix(decimalValue, useHexadecimalNumbers: true)); } + [Fact] + public void StringEscaping() + { + const string value = "a\tb"; + + Assert.Equal("a\tb", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.None)); + Assert.Equal("\"a\tb\"", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.UseQuotes)); + Assert.Equal("a\\tb", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.EscapeNonPrintableStringCharacters)); + Assert.Equal("\"a\\tb\"", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.UseQuotes | ObjectDisplayOptions.EscapeNonPrintableStringCharacters)); + } + private string FormatPrimitive(object obj, bool quoteStrings = false) { - return ObjectDisplay.FormatPrimitive(obj, quoteStrings ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None); + var options = quoteStrings ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None; + return ObjectDisplay.FormatPrimitive(obj, options | ObjectDisplayOptions.EscapeNonPrintableStringCharacters); } private string FormatPrimitiveUsingHexadecimalNumbers(object obj, bool quoteStrings = false) { var options = quoteStrings ? ObjectDisplayOptions.UseQuotes : ObjectDisplayOptions.None; - return ObjectDisplay.FormatPrimitive(obj, options | ObjectDisplayOptions.UseHexadecimalNumbers); + return ObjectDisplay.FormatPrimitive(obj, options | ObjectDisplayOptions.UseHexadecimalNumbers | ObjectDisplayOptions.EscapeNonPrintableStringCharacters); } private string FormatPrimitiveIncludingTypeSuffix(object obj, bool useHexadecimalNumbers = false) { var options = useHexadecimalNumbers ? ObjectDisplayOptions.UseHexadecimalNumbers : ObjectDisplayOptions.None; - return ObjectDisplay.FormatPrimitive(obj, options | ObjectDisplayOptions.IncludeTypeSuffix); + return ObjectDisplay.FormatPrimitive(obj, options | ObjectDisplayOptions.IncludeTypeSuffix | ObjectDisplayOptions.EscapeNonPrintableStringCharacters); } } } diff --git a/src/Compilers/Core/Portable/SymbolDisplay/ObjectDisplayOptions.cs b/src/Compilers/Core/Portable/SymbolDisplay/ObjectDisplayOptions.cs index b18c9ed7ef1..c24e0c25342 100644 --- a/src/Compilers/Core/Portable/SymbolDisplay/ObjectDisplayOptions.cs +++ b/src/Compilers/Core/Portable/SymbolDisplay/ObjectDisplayOptions.cs @@ -31,8 +31,14 @@ internal enum ObjectDisplayOptions UseHexadecimalNumbers = 1 << 2, /// - /// Whether or not to quote character and string literals. In Visual Basic, this also enables pretty-listing of non-printable characters using ChrW function and vb* constants. + /// Whether or not to quote character and string literals. /// UseQuotes = 1 << 3, + + /// + /// In C#, replace non-printable (e.g. control) characters with dedicated (e.g. \t) or unicode (\u0001) escape sequences. + /// In Visual Basic, replace non-printable characters with calls to ChrW and vb* constants. + /// + EscapeNonPrintableStringCharacters = 1 << 4, } } diff --git a/src/Compilers/VisualBasic/Portable/SymbolDisplay/ObjectDisplay.vb b/src/Compilers/VisualBasic/Portable/SymbolDisplay/ObjectDisplay.vb index baac9097da3..ce0f4408fc7 100644 --- a/src/Compilers/VisualBasic/Portable/SymbolDisplay/ObjectDisplay.vb +++ b/src/Compilers/VisualBasic/Portable/SymbolDisplay/ObjectDisplay.vb @@ -131,10 +131,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay Dim pooledBuilder = PooledStringBuilder.GetInstance() Dim sb = pooledBuilder.Builder - Dim useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes) - Dim useHex = options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) - For Each token As Integer In TokenizeString(value, useQuotes, useHex) + For Each token As Integer In TokenizeString(value, options) sb.Append(ChrW(token And &HFFFF)) ' lower 16 bits of token contains the Unicode char value Next @@ -362,9 +360,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay End Function ' TODO: consider making "token" returned by this function a structure to abstract bit masking operations - Friend Iterator Function TokenizeString(str As String, quote As Boolean, useHexadecimalNumbers As Boolean) As IEnumerable(Of Integer) + Friend Iterator Function TokenizeString(str As String, options As ObjectDisplayOptions) As IEnumerable(Of Integer) + Dim useQuotes = options.IncludesOption(ObjectDisplayOptions.UseQuotes) + Dim useHexadecimalNumbers = options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) + Dim escapeNonPrintable = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableStringCharacters) + If str.Length = 0 Then - If quote Then + If useQuotes Then Yield Quotes() Yield Quotes() End If @@ -380,23 +382,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay Dim c = str(i) i += 1 Dim wellKnown As String - Dim isNonPrintable As Boolean + Dim shouldEscape As Boolean Dim isCrLf As Boolean - ' vbCrLf - If c = s_Cr AndAlso i < str.Length AndAlso str(i) = s_Lf Then + If Not escapeNonPrintable Then + wellKnown = Nothing + shouldEscape = False + isCrLf = False + ElseIf c = s_Cr AndAlso i < str.Length AndAlso str(i) = s_Lf Then wellKnown = "vbCrLf" - isNonPrintable = True + shouldEscape = True isCrLf = True i += 1 Else wellKnown = GetWellKnownCharacterName(c) - isNonPrintable = wellKnown IsNot Nothing OrElse Not IsPrintable(c) + shouldEscape = wellKnown IsNot Nothing OrElse Not IsPrintable(c) isCrLf = False End If - If isNonPrintable Then - If quote Then + If shouldEscape Then + If useQuotes Then If lastConcatenandWasQuoted Then Yield Quotes() lastConcatenandWasQuoted = False @@ -440,7 +445,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay Yield Character(c) End If Else - If isFirst AndAlso quote Then + If isFirst AndAlso useQuotes Then Yield Quotes() End If @@ -454,7 +459,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay End If lastConcatenandWasQuoted = True - If c = """"c AndAlso quote Then + If c = """"c AndAlso useQuotes Then Yield Quotes() Yield Quotes() Else @@ -463,7 +468,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay End If End While - If quote AndAlso lastConcatenandWasQuoted Then + If useQuotes AndAlso lastConcatenandWasQuoted Then Yield Quotes() End If End Function @@ -498,6 +503,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay Private Sub ValidateOptions(options As ObjectDisplayOptions) ' This option is not supported and has no meaning in Visual Basic...should not be passed... Debug.Assert(Not options.IncludesOption(ObjectDisplayOptions.IncludeCodePoints)) + Debug.Assert(Not options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableStringCharacters) Or options.IncludesOption(ObjectDisplayOptions.UseQuotes)) End Sub End Module diff --git a/src/Compilers/VisualBasic/Portable/SymbolDisplay/SymbolDisplay.vb b/src/Compilers/VisualBasic/Portable/SymbolDisplay/SymbolDisplay.vb index 999660c5f8b..a0b7768cad2 100644 --- a/src/Compilers/VisualBasic/Portable/SymbolDisplay/SymbolDisplay.vb +++ b/src/Compilers/VisualBasic/Portable/SymbolDisplay/SymbolDisplay.vb @@ -122,7 +122,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Function FormatPrimitive(obj As Object, quoteStrings As Boolean, useHexadecimalNumbers As Boolean) As String Dim options = ObjectDisplayOptions.None If quoteStrings Then - options = options Or ObjectDisplayOptions.UseQuotes + options = options Or ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters End If If useHexadecimalNumbers Then options = options Or ObjectDisplayOptions.UseHexadecimalNumbers @@ -135,7 +135,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim sb = pooledBuilder.Builder Dim lastKind = -1 - For Each token As Integer In ObjectDisplay.TokenizeString(str, quote:=True, useHexadecimalNumbers:=True) + For Each token As Integer In ObjectDisplay.TokenizeString(str, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.UseHexadecimalNumbers Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters) Dim kind = token >> 16 ' merge contiguous tokens of the same kind into a single part diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb index 9df9f787c9e..413d6776954 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb @@ -370,7 +370,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Creates a token with kind StringLiteralToken from a string value. ''' The string value to be represented by the returned token. Public Shared Function Literal(value As String) As SyntaxToken - Return Literal(VbObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.UseQuotes), value) + Return Literal(VbObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters), value) End Function ''' Creates a token with kind StringLiteralToken from the text and corresponding string value. @@ -393,7 +393,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Creates a token with kind CharacterLiteralToken from a character value. ''' The character value to be represented by the returned token. Public Shared Function Literal(value As Char) As SyntaxToken - Return Literal(VbObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.UseQuotes), value) + Return Literal(VbObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters), value) End Function ''' Creates a token with kind CharacterLiteralToken from the text and corresponding character value. diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/ObjectDisplayTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/ObjectDisplayTests.vb index 9922e9450a4..95f59c3c06e 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/ObjectDisplayTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/ObjectDisplayTests.vb @@ -147,7 +147,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests ' non-printable characters are unchanged if quoting is disabled Assert.Equal(s, FormatPrimitiveUsingHexadecimalNumbers(s, quoteStrings:=False)) Assert.Equal(s, ObjectDisplay.FormatLiteral(s, ObjectDisplayOptions.None)) - Assert.Equal("""a"" & ChrW(&HFFFF) & ChrW(&HFFFE) & vbCrLf & ""b""", ObjectDisplay.FormatLiteral(s, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.UseHexadecimalNumbers)) + Assert.Equal("""a"" & ChrW(&HFFFF) & ChrW(&HFFFE) & vbCrLf & ""b""", ObjectDisplay.FormatLiteral(s, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters Or ObjectDisplayOptions.UseHexadecimalNumbers)) ' "well-known" characters: Assert.Equal("""a"" & vbBack", FormatPrimitiveUsingHexadecimalNumbers("a" & vbBack, quoteStrings:=True)) @@ -225,12 +225,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Assert.Equal("12.5D", FormatPrimitiveIncludingTypeSuffix(decimalValue, useHexadecimalNumbers:=True)) End Sub + + Public Sub StringEscaping() + Const value = "a" & vbTab & "b" + + Assert.Equal("a" & vbTab & "b", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.None)) + Assert.Equal("""a" & vbTab & "b""", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.UseQuotes)) + ' Not allowed in VB: ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.EscapeNonPrintableStringCharacters) + Assert.Equal("""a"" & vbTab & ""b""", ObjectDisplay.FormatPrimitive(value, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters)) + End Sub + Private Function FormatPrimitive(obj As Object, Optional quoteStrings As Boolean = False) As String - Return ObjectDisplay.FormatPrimitive(obj, If(quoteStrings, ObjectDisplayOptions.UseQuotes, ObjectDisplayOptions.None)) + Return ObjectDisplay.FormatPrimitive(obj, If(quoteStrings, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters, ObjectDisplayOptions.None)) End Function Private Function FormatPrimitiveUsingHexadecimalNumbers(obj As Object, Optional quoteStrings As Boolean = False) As String - Dim options = If(quoteStrings, ObjectDisplayOptions.UseQuotes, ObjectDisplayOptions.None) + Dim options = If(quoteStrings, ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters, ObjectDisplayOptions.None) Return ObjectDisplay.FormatPrimitive(obj, options Or ObjectDisplayOptions.UseHexadecimalNumbers) End Function diff --git a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.Values.cs b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.Values.cs index 8431c8d7513..5cfcecd9966 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.Values.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.Values.cs @@ -205,7 +205,7 @@ internal override string FormatLiteral(char c, ObjectDisplayOptions options) internal override string FormatLiteral(int value, ObjectDisplayOptions options) { - return ObjectDisplay.FormatLiteral(value, options & ~ObjectDisplayOptions.UseQuotes); + return ObjectDisplay.FormatLiteral(value, options & ~(ObjectDisplayOptions.UseQuotes | ObjectDisplayOptions.EscapeNonPrintableStringCharacters)); } internal override string FormatPrimitiveObject(object value, ObjectDisplayOptions options) @@ -217,5 +217,7 @@ internal override string FormatString(string str, ObjectDisplayOptions options) { return ObjectDisplay.FormatString(str, useQuotes: options.IncludesOption(ObjectDisplayOptions.UseQuotes)); } + + internal override ObjectDisplayOptions QuotedStringOptions => ObjectDisplayOptions.UseQuotes; } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.cs b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.cs index 49e684fbb6b..1791fb71763 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ResultProvider/CSharpFormatter.cs @@ -42,6 +42,17 @@ internal override bool IsWhitespace(char c) return SyntaxFacts.IsWhitespace(c); } + internal override ObjectDisplayOptions GetValueStringOptions(bool useQuotes) + { + var options = ObjectDisplayOptions.EscapeNonPrintableStringCharacters; + if (useQuotes) + { + options |= ObjectDisplayOptions.UseQuotes; + } + + return options; + } + internal override string TrimAndGetFormatSpecifiers(string expression, out ReadOnlyCollection formatSpecifiers) { expression = RemoveComments(expression); diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.Values.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.Values.cs index 73af1ed2afd..54f8334db1f 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.Values.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.Values.cs @@ -61,7 +61,7 @@ internal string GetValueString(DkmClrValue value, DkmInspectionContext inspectio { return IncludeObjectId( value, - FormatPrimitive(value, options & ~ObjectDisplayOptions.UseQuotes, inspectionContext), + FormatPrimitive(value, options & ~(ObjectDisplayOptions.UseQuotes | ObjectDisplayOptions.EscapeNonPrintableStringCharacters), inspectionContext), flags); } } @@ -348,7 +348,7 @@ internal string GetEditableValue(DkmClrValue value, DkmInspectionContext inspect { if (!value.IsNull) { - return this.GetValueString(value, inspectionContext, ObjectDisplayOptions.UseQuotes, GetValueFlags.None); + return this.GetValueString(value, inspectionContext, QuotedStringOptions, GetValueFlags.None); } } else if (type.IsCharacter()) @@ -410,6 +410,8 @@ private static string IncludeObjectId(DkmClrValue value, string valueStr, GetVal internal abstract string FormatString(string str, ObjectDisplayOptions options); + internal abstract ObjectDisplayOptions QuotedStringOptions { get; } + #endregion } } diff --git a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.cs b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.cs index c99383c80cb..96c103c5189 100644 --- a/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.cs +++ b/src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Text; using System; using System.Collections.ObjectModel; using System.Diagnostics; @@ -30,9 +29,7 @@ internal Formatter(string defaultFormat, string nullString, string staticMembers string IDkmClrFormatter.GetValueString(DkmClrValue value, DkmInspectionContext inspectionContext, ReadOnlyCollection formatSpecifiers) { - var options = ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoQuotes) == 0) ? - ObjectDisplayOptions.UseQuotes : - ObjectDisplayOptions.None; + ObjectDisplayOptions options = GetValueStringOptions((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoQuotes) == 0); return GetValueString(value, inspectionContext, options, GetValueFlags.IncludeObjectId); } @@ -67,6 +64,8 @@ string IDkmClrFormatter.GetUnderlyingString(DkmClrValue value, DkmInspectionCont internal abstract bool IsWhitespace(char c); + internal abstract ObjectDisplayOptions GetValueStringOptions(bool useQuotes); + // Note: We could be less conservative (e.g. "new C()"). internal bool NeedsParentheses(string expr) { diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.Values.vb b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.Values.vb index 3c55036b395..a0ea9b0e03d 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.Values.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.Values.vb @@ -171,6 +171,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return ObjectDisplay.FormatLiteral(str, options) End Function + Friend Overrides ReadOnly Property QuotedStringOptions As ObjectDisplayOptions + Get + Return ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters + End Get + End Property + End Class End Namespace \ No newline at end of file diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.vb b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.vb index 386234c7e9d..8a920b4cdba 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicFormatter.vb @@ -2,9 +2,6 @@ Imports System.Collections.ObjectModel Imports Microsoft.CodeAnalysis.ExpressionEvaluator -Imports Microsoft.VisualStudio.Debugger.Clr -Imports Microsoft.VisualStudio.Debugger.ComponentInterfaces -Imports Microsoft.VisualStudio.Debugger.Evaluation Imports Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation Imports Microsoft.VisualStudio.Debugger.Metadata @@ -13,7 +10,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ''' ''' Computes string representations of instances. ''' - Partial Friend NotInheritable Class VisualBasicFormatter : Inherits Formatter : Implements IDkmClrFormatter + Partial Friend NotInheritable Class VisualBasicFormatter : Inherits Formatter ''' ''' Singleton instance of VisualBasicFormatter (created using default constructor). @@ -26,25 +23,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator staticMembersString:=Resources.SharedMembers) End Sub - Private Function IDkmClrFormatter_GetTypeName(inspectionContext As DkmInspectionContext, clrType As DkmClrType, clrTypeInfo As DkmClrCustomTypeInfo, formatSpecifiers As ReadOnlyCollection(Of String)) As String Implements IDkmClrFormatter.GetTypeName - Return GetTypeName(New TypeAndCustomInfo(clrType.GetLmrType(), clrTypeInfo), escapeKeywordIdentifiers:=False, sawInvalidIdentifier:=Nothing) - End Function - - Private Function IDkmClrFormatter_GetUnderlyingString(clrValue As DkmClrValue, inspectionContext As DkmInspectionContext) As String Implements IDkmClrFormatter.GetUnderlyingString - Return GetUnderlyingString(clrValue, inspectionContext) - End Function - - Private Function IDkmClrFormatter_GetValueString(clrValue As DkmClrValue, inspectionContext As DkmInspectionContext, formatSpecifiers As ReadOnlyCollection(Of String)) As String Implements IDkmClrFormatter.GetValueString - Dim options = If((inspectionContext.EvaluationFlags And DkmEvaluationFlags.NoQuotes) = 0, - ObjectDisplayOptions.UseQuotes, - ObjectDisplayOptions.None) - Return GetValueString(clrValue, inspectionContext, options, GetValueFlags.IncludeObjectId) - End Function - - Private Function IDkmClrFormatter_HasUnderlyingString(clrValue As DkmClrValue, inspectionContext As DkmInspectionContext) As Boolean Implements IDkmClrFormatter.HasUnderlyingString - Return HasUnderlyingString(clrValue, inspectionContext) - End Function - Friend Overrides Function IsValidIdentifier(name As String) As Boolean Return SyntaxFacts.IsValidIdentifier(name) End Function @@ -61,6 +39,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return SyntaxFacts.IsWhitespace(c) End Function + Friend Overrides Function GetValueStringOptions(useQuotes As Boolean) As ObjectDisplayOptions + Return If(useQuotes, + ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableStringCharacters, + ObjectDisplayOptions.None) + End Function + Friend Overrides Function TrimAndGetFormatSpecifiers(expression As String, ByRef formatSpecifiers As ReadOnlyCollection(Of String)) As String expression = RemoveComments(expression) expression = RemoveFormatSpecifiers(expression, formatSpecifiers) diff --git a/src/Scripting/CSharp/Hosting/ObjectFormatter/CSharpObjectFormatter.cs b/src/Scripting/CSharp/Hosting/ObjectFormatter/CSharpObjectFormatter.cs index 94e651e6e4e..6f9c29a6e5c 100644 --- a/src/Scripting/CSharp/Hosting/ObjectFormatter/CSharpObjectFormatter.cs +++ b/src/Scripting/CSharp/Hosting/ObjectFormatter/CSharpObjectFormatter.cs @@ -28,7 +28,7 @@ internal override string FormatLiteral(bool value) internal override string FormatLiteral(string value, bool quote, bool useHexadecimalNumbers = false) { - var options = ObjectDisplayOptions.None; + var options = ObjectDisplayOptions.EscapeNonPrintableStringCharacters; if (quote) { options |= ObjectDisplayOptions.UseQuotes; -- GitLab