| File: DiagnosticAnalyzer\CompilerDiagnosticAnalyzer.CompilationAnalyzer.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.Generic; using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.Diagnostics { internal abstract partial class CompilerDiagnosticAnalyzer : DiagnosticAnalyzer { private const string Origin = nameof(Origin); private const string Syntactic = nameof(Syntactic); private const string Declaration = nameof(Declaration); private static readonly ImmutableDictionary<string, string?> s_syntactic = ImmutableDictionary<string, string?>.Empty.Add(Origin, Syntactic); private static readonly ImmutableDictionary<string, string?> s_declaration = ImmutableDictionary<string, string?>.Empty.Add(Origin, Declaration); /// <summary> /// Per-compilation DiagnosticAnalyzer for compiler's syntax/semantic/compilation diagnostics. /// </summary> private class CompilationAnalyzer { private readonly Compilation _compilation; public CompilationAnalyzer(Compilation compilation) { _compilation = compilation; } public void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context) { var semanticModel = _compilation.GetSemanticModel(context.Tree); var diagnostics = semanticModel.GetSyntaxDiagnostics(context.FilterSpan, context.CancellationToken); ReportDiagnostics(diagnostics, context.ReportDiagnostic, IsSourceLocation, s_syntactic); } public static void AnalyzeSemanticModel(SemanticModelAnalysisContext context) { var declDiagnostics = context.SemanticModel.GetDeclarationDiagnostics(context.FilterSpan, context.CancellationToken); var bodyDiagnostics = context.SemanticModel.GetMethodBodyDiagnostics(context.FilterSpan, context.CancellationToken); ReportDiagnostics(declDiagnostics, context.ReportDiagnostic, IsSourceLocation, s_declaration); ReportDiagnostics(bodyDiagnostics, context.ReportDiagnostic, IsSourceLocation); } public static void AnalyzeCompilation(CompilationAnalysisContext context) { var diagnostics = context.Compilation.GetDeclarationDiagnostics(cancellationToken: context.CancellationToken); ReportDiagnostics(diagnostics, context.ReportDiagnostic, location => !IsSourceLocation(location), s_declaration); } private static bool IsSourceLocation(Location location) { return location != null && location.Kind == LocationKind.SourceFile; } private static void ReportDiagnostics( ImmutableArray<Diagnostic> diagnostics, Action<Diagnostic> reportDiagnostic, Func<Location, bool> locationFilter, ImmutableDictionary<string, string?>? properties = null) { foreach (var diagnostic in diagnostics) { if (locationFilter(diagnostic.Location) && diagnostic.Severity != DiagnosticSeverity.Hidden) { var current = properties == null ? diagnostic : new CompilerDiagnostic(diagnostic, properties); reportDiagnostic(current); } } } private sealed class CompilerDiagnostic : Diagnostic { private readonly Diagnostic _original; private readonly ImmutableDictionary<string, string?> _properties; public CompilerDiagnostic(Diagnostic original, ImmutableDictionary<string, string?> properties) { _original = original; _properties = properties; } #pragma warning disable RS0013 // we are delegating so it is okay here public override DiagnosticDescriptor Descriptor => _original.Descriptor; #pragma warning restore RS0013 internal override int Code => _original.Code; internal override IReadOnlyList<object?> Arguments => _original.Arguments; public override string Id => _original.Id; public override DiagnosticSeverity Severity => _original.Severity; public override int WarningLevel => _original.WarningLevel; public override Location Location => _original.Location; public override IReadOnlyList<Location> AdditionalLocations => _original.AdditionalLocations; public override bool IsSuppressed => _original.IsSuppressed; public override ImmutableDictionary<string, string?> Properties => _properties; public override string GetMessage(IFormatProvider? formatProvider = null) { return _original.GetMessage(formatProvider); } public override int GetHashCode() { return _original.GetHashCode(); } public override bool Equals(Diagnostic? obj) { // We only support equality check with another instance of "CompilerDiagnostic". // Hosts that want to compare compiler diagnostics from different sources, // such as with diagnostic reported from compilation.GetDiagnostics(), should // use a custom equality comparer. return obj is CompilerDiagnostic other && _original.Equals(other._original); } internal override Diagnostic WithLocation(Location location) { return new CompilerDiagnostic(_original.WithLocation(location), _properties); } internal override Diagnostic WithSeverity(DiagnosticSeverity severity) { return new CompilerDiagnostic(_original.WithSeverity(severity), _properties); } internal override Diagnostic WithIsSuppressed(bool isSuppressed) { return new CompilerDiagnostic(_original.WithIsSuppressed(isSuppressed), _properties); } } } } }