|
// 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.Collections.Concurrent;
using System.Globalization;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Abstracts the ability to classify and load messages for error codes. Allows the error
/// infrastructure to be reused between C# and VB.
/// </summary>
internal abstract class CommonMessageProvider
{
/// <summary>
/// Caches the return values for <see cref="GetIdForErrorCode(int)"/>.
/// </summary>
private static readonly ConcurrentDictionary<(string prefix, int code), string> s_errorIdCache = new ConcurrentDictionary<(string prefix, int code), string>();
/// <summary>
/// Given an error code, get the severity (warning or error) of the code.
/// </summary>
public abstract DiagnosticSeverity GetSeverity(int code);
/// <summary>
/// Load the message for the given error code. If the message contains
/// "fill-in" placeholders, those should be expressed in standard string.Format notation
/// and be in the string.
/// </summary>
public abstract string LoadMessage(int code, CultureInfo? language);
/// <summary>
/// Get an optional localizable title for the given diagnostic code.
/// </summary>
public abstract LocalizableString GetTitle(int code);
/// <summary>
/// Get an optional localizable description for the given diagnostic code.
/// </summary>
public abstract LocalizableString GetDescription(int code);
/// <summary>
/// Get a localizable message format string for the given diagnostic code.
/// </summary>
public abstract LocalizableString GetMessageFormat(int code);
/// <summary>
/// Get an optional help link for the given diagnostic code.
/// </summary>
public abstract string GetHelpLink(int code);
/// <summary>
/// Get the diagnostic category for the given diagnostic code.
/// Default category is <see cref="Diagnostic.CompilerDiagnosticCategory"/>.
/// </summary>
public abstract string GetCategory(int code);
/// <summary>
/// Get the text prefix (e.g., "CS" for C#) used on error messages.
/// </summary>
public abstract string CodePrefix { get; }
/// <summary>
/// Get the warning level for warnings (e.g., 1 or greater for C#). VB does not have warning
/// levels and always uses 1. Errors should return 0.
/// </summary>
public abstract int GetWarningLevel(int code);
/// <summary>
/// Type that defines error codes. For testing purposes only.
/// </summary>
public abstract Type ErrorCodeType { get; }
/// <summary>
/// Create a simple language specific diagnostic for given error code.
/// </summary>
public Diagnostic CreateDiagnostic(int code, Location location)
{
return CreateDiagnostic(code, location, Array.Empty<object>());
}
/// <summary>
/// Create a simple language specific diagnostic with no location for given info.
/// </summary>
public abstract Diagnostic CreateDiagnostic(DiagnosticInfo info);
/// <summary>
/// Create a simple language specific diagnostic for given error code.
/// </summary>
public abstract Diagnostic CreateDiagnostic(int code, Location location, params object[] args);
/// <summary>
/// Given a message identifier (e.g., CS0219), severity, warning as error and a culture,
/// get the entire prefix (e.g., "error CS0219: Warning as Error:" for C# or "error BC42024:" for VB) used on error messages.
/// </summary>
public abstract string GetMessagePrefix(string id, DiagnosticSeverity severity, bool isWarningAsError, CultureInfo? culture);
/// <summary>
/// Convert given symbol to string representation.
/// </summary>
public abstract string GetErrorDisplayString(ISymbol symbol);
public abstract bool GetIsEnabledByDefault(int code);
/// <summary>
/// Given an error code (like 1234) return the identifier (CS1234 or BC1234).
/// </summary>
[PerformanceSensitive(
"https://github.com/dotnet/roslyn/issues/31964",
AllowCaptures = false,
Constraint = "Frequently called by error list filtering; avoid allocations")]
public string GetIdForErrorCode(int errorCode)
{
return s_errorIdCache.GetOrAdd((CodePrefix, errorCode), key => key.prefix + key.code.ToString("0000"));
}
/// <summary>
/// Produces the filtering action for the diagnostic based on the options passed in.
/// </summary>
/// <returns>
/// A new <see cref="DiagnosticInfo"/> with new effective severity based on the options or null if the
/// diagnostic has been suppressed.
/// </returns>
public abstract ReportDiagnostic GetDiagnosticReport(DiagnosticInfo diagnosticInfo, CompilationOptions options);
/// <summary>
/// Filter a <see cref="DiagnosticInfo"/> based on the compilation options so that /nowarn and /warnaserror etc. take effect.options
/// </summary>
/// <returns>A <see cref="DiagnosticInfo"/> with effective severity based on option or null if suppressed.</returns>
public DiagnosticInfo? FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, CompilationOptions options)
{
var report = this.GetDiagnosticReport(diagnosticInfo, options);
switch (report)
{
case ReportDiagnostic.Error:
return diagnosticInfo.GetInstanceWithSeverity(DiagnosticSeverity.Error);
case ReportDiagnostic.Warn:
return diagnosticInfo.GetInstanceWithSeverity(DiagnosticSeverity.Warning);
case ReportDiagnostic.Info:
return diagnosticInfo.GetInstanceWithSeverity(DiagnosticSeverity.Info);
case ReportDiagnostic.Hidden:
return diagnosticInfo.GetInstanceWithSeverity(DiagnosticSeverity.Hidden);
case ReportDiagnostic.Suppress:
return null;
default:
return diagnosticInfo;
}
}
#if DEBUG
internal abstract bool ShouldAssertExpectedMessageArgumentsLength(int errorCode);
#endif
// Common error messages
public abstract int ERR_FailedToCreateTempFile { get; }
public abstract int ERR_MultipleAnalyzerConfigsInSameDir { get; }
// command line:
public abstract int ERR_ExpectedSingleScript { get; }
public abstract int ERR_OpenResponseFile { get; }
public abstract int ERR_InvalidPathMap { get; }
public abstract int FTL_InvalidInputFileName { get; }
public abstract int ERR_FileNotFound { get; }
public abstract int ERR_NoSourceFile { get; }
public abstract int ERR_CantOpenFileWrite { get; }
public abstract int ERR_OutputWriteFailed { get; }
public abstract int WRN_NoConfigNotOnCommandLine { get; }
public abstract int ERR_BinaryFile { get; }
public abstract int WRN_UnableToLoadAnalyzer { get; }
public abstract int INF_UnableToLoadSomeTypesInAnalyzer { get; }
public abstract int WRN_AnalyzerCannotBeCreated { get; }
public abstract int WRN_NoAnalyzerInAssembly { get; }
public abstract int WRN_AnalyzerReferencesFramework { get; }
public abstract int WRN_AnalyzerReferencesNewerCompiler { get; }
public abstract int WRN_DuplicateAnalyzerReference { get; }
public abstract int ERR_CantReadRulesetFile { get; }
public abstract int ERR_CompileCancelled { get; }
// parse options:
public abstract int ERR_BadSourceCodeKind { get; }
public abstract int ERR_BadDocumentationMode { get; }
// compilation options:
public abstract int ERR_BadCompilationOptionValue { get; }
public abstract int ERR_MutuallyExclusiveOptions { get; }
// emit options:
public abstract int ERR_InvalidDebugInformationFormat { get; }
public abstract int ERR_InvalidFileAlignment { get; }
public abstract int ERR_InvalidSubsystemVersion { get; }
public abstract int ERR_InvalidOutputName { get; }
public abstract int ERR_InvalidInstrumentationKind { get; }
public abstract int ERR_InvalidHashAlgorithmName { get; }
// reference manager:
public abstract int ERR_MetadataFileNotAssembly { get; }
public abstract int ERR_MetadataFileNotModule { get; }
public abstract int ERR_InvalidAssemblyMetadata { get; }
public abstract int ERR_InvalidModuleMetadata { get; }
public abstract int ERR_ErrorOpeningAssemblyFile { get; }
public abstract int ERR_ErrorOpeningModuleFile { get; }
public abstract int ERR_MetadataFileNotFound { get; }
public abstract int ERR_MetadataReferencesNotSupported { get; }
public abstract int ERR_LinkedNetmoduleMetadataMustProvideFullPEImage { get; }
public abstract void ReportDuplicateMetadataReferenceStrong(DiagnosticBag diagnostics, Location location, MetadataReference reference, AssemblyIdentity identity, MetadataReference equivalentReference, AssemblyIdentity equivalentIdentity);
public abstract void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnostics, Location location, MetadataReference reference, AssemblyIdentity identity, MetadataReference equivalentReference, AssemblyIdentity equivalentIdentity);
// signing:
public abstract int ERR_PublicKeyFileFailure { get; }
public abstract int ERR_PublicKeyContainerFailure { get; }
public abstract int ERR_OptionMustBeAbsolutePath { get; }
// resources:
public abstract int ERR_CantReadResource { get; }
public abstract int ERR_CantOpenWin32Resource { get; }
public abstract int ERR_CantOpenWin32Manifest { get; }
public abstract int ERR_CantOpenWin32Icon { get; }
public abstract int ERR_BadWin32Resource { get; }
public abstract int ERR_ErrorBuildingWin32Resource { get; }
public abstract int ERR_ResourceNotUnique { get; }
public abstract int ERR_ResourceFileNameNotUnique { get; }
public abstract int ERR_ResourceInModule { get; }
// pseudo-custom attributes:
public abstract int ERR_PermissionSetAttributeFileReadError { get; }
// PDB writing:
public abstract int ERR_EncodinglessSyntaxTree { get; }
public abstract int WRN_PdbUsingNameTooLong { get; }
public abstract int WRN_PdbLocalNameTooLong { get; }
public abstract int ERR_PdbWritingFailed { get; }
// PE writing:
public abstract int ERR_MetadataNameTooLong { get; }
public abstract int ERR_EncReferenceToAddedMember { get; }
public abstract int ERR_TooManyUserStrings { get; }
public abstract int ERR_PeWritingFailure { get; }
public abstract int ERR_ModuleEmitFailure { get; }
public abstract int ERR_EncUpdateFailedMissingSymbol { get; }
public abstract int ERR_InvalidDebugInfo { get; }
public abstract int ERR_FunctionPointerTypesInAttributeNotSupported { get; }
// Generators:
public abstract int WRN_GeneratorFailedDuringInitialization { get; }
public abstract int WRN_GeneratorFailedDuringGeneration { get; }
/// <summary>
/// Takes an exception produced while writing to a file stream and produces a diagnostic.
/// </summary>
public void ReportStreamWriteException(Exception e, string filePath, DiagnosticBag diagnostics)
{
diagnostics.Add(CreateDiagnostic(ERR_OutputWriteFailed, Location.None, filePath, e.Message));
}
protected abstract void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute);
public void ReportInvalidAttributeArgument(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportInvalidAttributeArgument(diagnosticBag, attributeSyntax, parameterIndex, attribute);
}
}
protected abstract void ReportInvalidNamedArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName);
public void ReportInvalidNamedArgument(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportInvalidNamedArgument(diagnosticBag, attributeSyntax, namedArgumentIndex, attributeClass, parameterName);
}
}
protected abstract void ReportParameterNotValidForType(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex);
public void ReportParameterNotValidForType(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportParameterNotValidForType(diagnosticBag, attributeSyntax, namedArgumentIndex);
}
}
protected abstract void ReportMarshalUnmanagedTypeNotValidForFields(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, string unmanagedTypeName, AttributeData attribute);
public void ReportMarshalUnmanagedTypeNotValidForFields(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, string unmanagedTypeName, AttributeData attribute)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportMarshalUnmanagedTypeNotValidForFields(diagnosticBag, attributeSyntax, parameterIndex, unmanagedTypeName, attribute);
}
}
protected abstract void ReportMarshalUnmanagedTypeOnlyValidForFields(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, string unmanagedTypeName, AttributeData attribute);
public void ReportMarshalUnmanagedTypeOnlyValidForFields(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, string unmanagedTypeName, AttributeData attribute)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportMarshalUnmanagedTypeOnlyValidForFields(diagnosticBag, attributeSyntax, parameterIndex, unmanagedTypeName, attribute);
}
}
protected abstract void ReportAttributeParameterRequired(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, string parameterName);
public void ReportAttributeParameterRequired(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, string parameterName)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportAttributeParameterRequired(diagnosticBag, attributeSyntax, parameterName);
}
}
protected abstract void ReportAttributeParameterRequired(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, string parameterName1, string parameterName2);
public void ReportAttributeParameterRequired(BindingDiagnosticBag diagnostics, SyntaxNode attributeSyntax, string parameterName1, string parameterName2)
{
if (diagnostics.DiagnosticBag is DiagnosticBag diagnosticBag)
{
ReportAttributeParameterRequired(diagnosticBag, attributeSyntax, parameterName1, parameterName2);
}
}
public abstract int ERR_BadAssemblyName { get; }
public abstract int? WRN_ByValArraySizeConstRequired { get; }
}
}
|