| File: Hosting\ObjectFormatter\CommonObjectFormatter.cs | Web Access |
| Project: src\roslyn\src\Scripting\Core\Microsoft.CodeAnalysis.Scripting.csproj (Microsoft.CodeAnalysis.Scripting) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Diagnostics; using System.Globalization; using System.Reflection; using Microsoft.CodeAnalysis.PooledObjects; using static Microsoft.CodeAnalysis.Scripting.Hosting.ObjectFormatterHelpers; namespace Microsoft.CodeAnalysis.Scripting.Hosting { /// <summary> /// Object pretty printer. /// </summary> internal abstract partial class CommonObjectFormatter : ObjectFormatter { public override string FormatObject(object obj, PrintOptions options) { if (options == null) { // We could easily recover by using default options, but it makes // more sense for the host to choose the defaults so we'll require // that options be passed. throw new ArgumentNullException(nameof(options)); } var visitor = new Visitor(this, GetInternalBuilderOptions(options), GetPrimitiveOptions(options), GetTypeNameOptions(options), options.MemberDisplayFormat); return visitor.FormatObject(obj); } protected virtual MemberFilter Filter { get; } = new CommonMemberFilter(); protected abstract CommonTypeNameFormatter TypeNameFormatter { get; } protected abstract CommonPrimitiveFormatter PrimitiveFormatter { get; } protected virtual BuilderOptions GetInternalBuilderOptions(PrintOptions printOptions) => new BuilderOptions( indentation: " ", newLine: Environment.NewLine, ellipsis: printOptions.Ellipsis, maximumLineLength: int.MaxValue, maximumOutputLength: printOptions.MaximumOutputLength); protected virtual CommonPrimitiveFormatterOptions GetPrimitiveOptions(PrintOptions printOptions) => new CommonPrimitiveFormatterOptions( numberRadix: printOptions.NumberRadix, includeCodePoints: false, quoteStringsAndCharacters: true, escapeNonPrintableCharacters: printOptions.EscapeNonPrintableCharacters, cultureInfo: CultureInfo.CurrentUICulture); protected virtual CommonTypeNameFormatterOptions GetTypeNameOptions(PrintOptions printOptions) => new CommonTypeNameFormatterOptions( arrayBoundRadix: printOptions.NumberRadix, showNamespaces: false); public override string FormatException(Exception e) { if (e == null) { throw new ArgumentNullException(nameof(e)); } var pooled = PooledStringBuilder.GetInstance(); var builder = pooled.Builder; builder.Append(e.GetType()); builder.Append(": "); builder.Append(e.Message); builder.Append(Environment.NewLine); var trace = new StackTrace(e, fNeedFileInfo: true); foreach (var frame in trace.GetFrames()) { if (!Filter.Include(frame)) { continue; } var method = frame.GetMethod(); var methodDisplay = FormatMethodSignature(method); if (methodDisplay == null) { continue; } builder.Append(" + "); builder.Append(methodDisplay); var fileName = frame.GetFileName(); if (fileName != null) { builder.Append(string.Format(CultureInfo.CurrentUICulture, ScriptingResources.AtFileLine, fileName, frame.GetFileLineNumber())); } builder.AppendLine(); } return pooled.ToStringAndFree(); } /// <summary> /// Returns a method signature display string. Used to display stack frames. /// </summary> /// <returns>Null if the method is a compiler generated method that shouldn't be displayed to the user.</returns> protected internal virtual string FormatMethodSignature(MethodBase method) { var pooled = PooledStringBuilder.GetInstance(); var builder = pooled.Builder; var declaringType = method.DeclaringType; var options = new CommonTypeNameFormatterOptions(arrayBoundRadix: NumberRadixDecimal, showNamespaces: true); builder.Append(TypeNameFormatter.FormatTypeName(declaringType, options)); builder.Append('.'); builder.Append(method.Name); if (method.IsGenericMethod) { builder.Append(TypeNameFormatter.FormatTypeArguments(method.GetGenericArguments(), options)); } builder.Append('('); bool first = true; foreach (var parameter in method.GetParameters()) { if (first) { first = false; } else { builder.Append(", "); } if (parameter.ParameterType.IsByRef) { builder.Append(FormatRefKind(parameter)); builder.Append(' '); builder.Append(TypeNameFormatter.FormatTypeName(parameter.ParameterType.GetElementType(), options)); } else { builder.Append(TypeNameFormatter.FormatTypeName(parameter.ParameterType, options)); } } builder.Append(')'); return pooled.ToStringAndFree(); } protected abstract string FormatRefKind(ParameterInfo parameter); } }