| File: DiagnosticAnalyzer\DiagnosticAnalysisContextHelpers.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// 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.Immutable; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.FlowAnalysis; using Microsoft.CodeAnalysis.Operations; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { internal static class DiagnosticAnalysisContextHelpers { internal static void VerifyArguments<TContext>(Action<TContext> action) { VerifyAction(action); } internal static void VerifyArguments<TContext>(Action<TContext> action, ImmutableArray<SymbolKind> symbolKinds) { VerifyAction(action); VerifySymbolKinds(symbolKinds); } internal static void VerifyArguments<TContext, TLanguageKindEnum>(Action<TContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds) where TLanguageKindEnum : struct { VerifyAction(action); VerifySyntaxKinds(syntaxKinds); } internal static void VerifyArguments<TContext>(Action<TContext> action, ImmutableArray<OperationKind> operationKinds) { VerifyAction(action); VerifyOperationKinds(operationKinds); } internal static void VerifyArguments(Diagnostic diagnostic, Compilation? compilation, Func<Diagnostic, CancellationToken, bool> isSupportedDiagnostic, CancellationToken cancellationToken) { if (diagnostic is DiagnosticWithInfo) { // Compiler diagnostic, skip validations. return; } if (diagnostic == null) { throw new ArgumentNullException(nameof(diagnostic)); } if (compilation != null) { VerifyDiagnosticLocationsInCompilation(diagnostic, compilation); } if (!isSupportedDiagnostic(diagnostic, cancellationToken)) { throw new ArgumentException(string.Format(CodeAnalysisResources.UnsupportedDiagnosticReported, diagnostic.Id), nameof(diagnostic)); } if (!UnicodeCharacterUtilities.IsValidIdentifier(diagnostic.Id)) { // Disallow invalid diagnostic IDs. // Note that the parsing logic in Csc/Vbc MSBuild tasks to decode command line compiler output relies on diagnostics having a valid ID. // See https://github.com/dotnet/roslyn/issues/4376 for details. throw new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticIdReported, diagnostic.Id), nameof(diagnostic)); } } internal static void VerifyDiagnosticLocationsInCompilation(Diagnostic diagnostic, Compilation compilation) { VerifyDiagnosticLocationInCompilation(diagnostic.Id, diagnostic.Location, compilation); if (diagnostic.AdditionalLocations != null) { foreach (var location in diagnostic.AdditionalLocations) { VerifyDiagnosticLocationInCompilation(diagnostic.Id, location, compilation); } } } private static void VerifyDiagnosticLocationInCompilation(string id, Location location, Compilation compilation) { if (!location.IsInSource) { return; } Debug.Assert(location.SourceTree != null); if (!compilation.ContainsSyntaxTree(location.SourceTree)) { // Disallow diagnostics with source locations outside this compilation. throw new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticLocationReported, id, location.SourceTree.FilePath), "diagnostic"); } if (location.SourceSpan.End > location.SourceTree.Length) { // Disallow diagnostics with source locations outside this compilation. throw new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticSpanReported, id, location.SourceSpan, location.SourceTree.FilePath), "diagnostic"); } } private static void VerifyAction<TContext>(Action<TContext> action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } } private static void VerifySymbolKinds(ImmutableArray<SymbolKind> symbolKinds) { if (symbolKinds.IsDefault) { throw new ArgumentNullException(nameof(symbolKinds)); } if (symbolKinds.IsEmpty) { throw new ArgumentException(CodeAnalysisResources.ArgumentCannotBeEmpty, nameof(symbolKinds)); } } private static void VerifySyntaxKinds<TLanguageKindEnum>(ImmutableArray<TLanguageKindEnum> syntaxKinds) where TLanguageKindEnum : struct { if (syntaxKinds.IsDefault) { throw new ArgumentNullException(nameof(syntaxKinds)); } if (syntaxKinds.IsEmpty) { throw new ArgumentException(CodeAnalysisResources.ArgumentCannotBeEmpty, nameof(syntaxKinds)); } } private static void VerifyOperationKinds(ImmutableArray<OperationKind> operationKinds) { if (operationKinds.IsDefault) { throw new ArgumentNullException(nameof(operationKinds)); } if (operationKinds.IsEmpty) { throw new ArgumentException(CodeAnalysisResources.ArgumentCannotBeEmpty, nameof(operationKinds)); } } internal static void VerifyArguments<TKey, TValue>(TKey key, AnalysisValueProvider<TKey, TValue> valueProvider) where TKey : class { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } } internal static ControlFlowGraph GetControlFlowGraph(IOperation operation, Func<IOperation, ControlFlowGraph>? getControlFlowGraph, CancellationToken cancellationToken) { IOperation rootOperation = operation.GetRootOperation(); return getControlFlowGraph != null ? getControlFlowGraph(rootOperation) : ControlFlowGraph.CreateCore(rootOperation, nameof(rootOperation), cancellationToken); } } }