|
// 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.
using System;
using System.Globalization;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Formats <see cref="Diagnostic"/> messages.
/// </summary>
public class DiagnosticFormatter
{
/// <summary>
/// Formats the <see cref="Diagnostic"/> message using the optional <see cref="IFormatProvider"/>.
/// </summary>
/// <param name="diagnostic">The diagnostic.</param>
/// <param name="formatter">The formatter; or null to use the default formatter.</param>
/// <returns>The formatted message.</returns>
public virtual string Format(Diagnostic diagnostic, IFormatProvider? formatter = null)
{
if (diagnostic == null)
{
throw new ArgumentNullException(nameof(diagnostic));
}
var culture = formatter as CultureInfo;
switch (diagnostic.Location.Kind)
{
case LocationKind.SourceFile:
case LocationKind.XmlFile:
case LocationKind.ExternalFile:
var span = diagnostic.Location.GetLineSpan();
var mappedSpan = diagnostic.Location.GetMappedLineSpan();
if (!span.IsValid || !mappedSpan.IsValid)
{
goto default;
}
string? path, basePath;
if (mappedSpan.HasMappedPath)
{
path = mappedSpan.Path;
basePath = span.Path;
}
else
{
path = span.Path;
basePath = null;
}
return string.Format(formatter, "{0}{1}: {2}: {3}{4}",
FormatSourcePath(path, basePath, formatter),
FormatSourceSpan(mappedSpan.Span, formatter),
GetMessagePrefix(diagnostic),
diagnostic.GetMessage(culture),
FormatHelpLinkUri(diagnostic));
default:
return string.Format(formatter, "{0}: {1}{2}",
GetMessagePrefix(diagnostic),
diagnostic.GetMessage(culture),
FormatHelpLinkUri(diagnostic));
}
}
internal virtual string FormatSourcePath(string path, string? basePath, IFormatProvider? formatter)
{
// ignore base path
return path;
}
internal virtual string FormatSourceSpan(LinePositionSpan span, IFormatProvider? formatter)
{
return string.Format("({0},{1})", span.Start.Line + 1, span.Start.Character + 1);
}
internal string GetMessagePrefix(Diagnostic diagnostic)
{
string prefix;
switch (diagnostic.Severity)
{
case DiagnosticSeverity.Hidden:
prefix = "hidden";
break;
case DiagnosticSeverity.Info:
prefix = "info";
break;
case DiagnosticSeverity.Warning:
prefix = "warning";
break;
case DiagnosticSeverity.Error:
prefix = "error";
break;
default:
throw ExceptionUtilities.UnexpectedValue(diagnostic.Severity);
}
return string.Format("{0} {1}", prefix, diagnostic.Id);
}
private string FormatHelpLinkUri(Diagnostic diagnostic)
{
var uri = diagnostic.Descriptor.HelpLinkUri;
if (string.IsNullOrEmpty(uri) || HasDefaultHelpLinkUri(diagnostic))
{
return string.Empty;
}
return $" ({uri})";
}
internal virtual bool HasDefaultHelpLinkUri(Diagnostic diagnostic) => true;
internal static readonly DiagnosticFormatter Instance = new DiagnosticFormatter();
}
}
|