File: src\roslyn\src\Analyzers\CSharp\Analyzers\RemoveUnnecessaryImports\CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer.cs
Web Access
Project: src\roslyn\src\CodeStyle\CSharp\Analyzers\Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle)
// 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;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.LanguageService;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.RemoveUnnecessaryImports;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer :
    AbstractRemoveUnnecessaryImportsDiagnosticAnalyzer<UsingDirectiveSyntax>
{
    public CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer()
        : base(new LocalizableResourceString(nameof(CSharpAnalyzersResources.Using_directive_is_unnecessary), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)))
    {
    }

    protected override GeneratedCodeAnalysisFlags GeneratedCodeAnalysisFlags => GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics;

    protected override ISyntaxFacts SyntaxFacts
        => CSharpSyntaxFacts.Instance;

    // C# has no need to do any merging of using statements.  Only VB needs to
    // merge import clauses to an import statement if it all the import clauses
    // are unnecessary.
    protected override ImmutableArray<SyntaxNode> MergeImports(ImmutableArray<UsingDirectiveSyntax> unnecessaryImports)
        => ImmutableArray<SyntaxNode>.CastUp(unnecessaryImports);

    protected override IUnnecessaryImportsProvider<UsingDirectiveSyntax> UnnecessaryImportsProvider
        => CSharpUnnecessaryImportsProvider.Instance;

    protected override bool IsRegularCommentOrDocComment(SyntaxTrivia trivia)
        => trivia.IsRegularComment() || trivia.IsDocComment();

    protected override SyntaxToken? TryGetLastToken(SyntaxNode node)
        // No special behavior needed for C#
        => null;

    protected override IEnumerable<TextSpan> GetFixableDiagnosticSpans(
        IEnumerable<SyntaxNode> nodes, SyntaxTree tree, CancellationToken cancellationToken)
    {
        Contract.ThrowIfFalse(nodes.Any());

        foreach (var node in nodes.Select(n => n.GetAncestors().First(n => n is BaseNamespaceDeclarationSyntax or CompilationUnitSyntax)).Distinct())
        {
            if (node is BaseNamespaceDeclarationSyntax namespaceDeclaration)
            {
                yield return namespaceDeclaration.Usings.GetContainedSpan();
            }
            else if (node is CompilationUnitSyntax compilationUnit)
            {
                yield return compilationUnit.Usings.GetContainedSpan();
            }
        }
    }

    protected override void AnalyzeSemanticModel(SemanticModelAnalysisContext context, SyntaxTree tree, CancellationToken cancellationToken)
    {
        // We've opted in to generated code analysis above, but we actually only want to analyze generated code for Razor
        if (context.IsGeneratedCode &&
            tree.FilePath.IndexOf("Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator") == -1)
        {
            return;
        }

        base.AnalyzeSemanticModel(context, tree, cancellationToken);
    }
}