Repository: dotnet/roslyn
File: src/Analyzers/CSharp/Analyzers/RemoveUnnecessarySuppressions/UnnecessaryNullableWarningSuppressionsUtilities.cs (C#)

Code before:
        var originalTree = semanticModel.SyntaxTree;
        var originalRoot = originalTree.GetRoot(cancellationToken);

        var updatedTree = originalTree.WithRootAndOptions(
            originalRoot.ReplaceNodes(
                nodesToCheck,
                (original, current) => current.Operand.WithAdditionalAnnotations(nodeToAnnotation[original])),
            originalTree.Options);
        var updateRoot = updatedTree.GetRoot(cancellationToken);
        var updatedCompilation = semanticModel.Compilation
            .ReplaceSyntaxTree(originalTree, updatedTree)
            .WithOptions(semanticModel.Compilation.Options.WithSpecificDiagnosticOptions([]));
        var updatedSemanticModel = updatedCompilation.GetSemanticModel(updatedTree);

        foreach (var (node, annotation) in nodeToAnnotation)
        {
            var updatedNode = updateRoot.GetAnnotatedNodes(annotation).Single();
            var span = GetSpanToCheck(updatedNode);
            if (span is null)
                continue;

            var updatedDiagnostics = updatedSemanticModel.GetDiagnostics(span, cancellationToken);
            if (ContainsErrorOrWarning(updatedDiagnostics))
                continue;

            result.Add(node);
        }
    }

    private static TextSpan? GetSpanToCheck(SyntaxNode updatedNode)
    {
        var globalStatement = updatedNode.Ancestors().OfType<GlobalStatementSyntax>().FirstOrDefault();
        if (globalStatement is not null)
        {
            var compilationUnit = (CompilationUnitSyntax)globalStatement.GetRequiredParent();
            return TextSpan.FromBounds(globalStatement.SpanStart, compilationUnit.Members.OfType<GlobalStatementSyntax>().Last().Span.End);
        }

        var ancestor = updatedNode.Ancestors().LastOrDefault(
            n => n is BaseFieldDeclarationSyntax or BaseMethodDeclarationSyntax or BasePropertyDeclarationSyntax);

        return ancestor?.Span;
    }
}


Review comment (suggestion):
It looks like the rough solution here is:

1. track all the `expr!` nodes from the original tree.
2. make a derived tree which changes all `expr!` to expr`
3. get a semantic model for the derived tree, and diagnostics for the method/subtree/whatever we are analyzing
4. for each `expr` which was previously suppressed, see if there is a diagnostic on it
5. mark `expr`s which don't have a diagnostic as having an unnecessary suppression in the user's code.

Is that right? Seems good, I think. I am curious if this is similar to how the "unnecessary `#pragma`" analysis works.


Code after:
        CancellationToken cancellationToken)
    {
        var originalTree = semanticModel.SyntaxTree;
        var originalRoot = originalTree.GetRoot(cancellationToken);

        var updatedTree = originalTree.WithRootAndOptions(
            originalRoot.ReplaceNodes(
                nodesToCheck,
                (original, current) => current.Operand.WithAdditionalAnnotations(nodeToAnnotation[original])),
            originalTree.Options);
        var updateRoot = updatedTree.GetRoot(cancellationToken);
        var updatedCompilation = semanticModel.Compilation
            .ReplaceSyntaxTree(originalTree, updatedTree)
            .WithOptions(semanticModel.Compilation.Options.WithSpecificDiagnosticOptions([]));
        var updatedSemanticModel = updatedCompilation.GetSemanticModel(updatedTree);

        // Group nodes by the span we need to check for errors/warnings. That way we only need to get the diagnostics
        // once per span instead of once per node.
        foreach (var group in nodeToAnnotation.GroupBy(tuple => GetSpanToCheck(updateRoot.GetAnnotatedNodes(tuple.Value).Single())))
        {
            var groupSpan = group.Key;
            if (groupSpan is null)
                continue;

            var updatedDiagnostics = updatedSemanticModel.GetDiagnostics(groupSpan, cancellationToken);
            if (ContainsErrorOrWarning(updatedDiagnostics))
                continue;

            // If there were no errors in that span after removing all the suppressions, then we can offer all of these
            // nodes up for fixing.
            foreach (var (suppressionNode, _) in group)
                result.Add(suppressionNode);
        }
    }

    private static TextSpan? GetSpanToCheck(SyntaxNode updatedNode)
    {
        // If we're in a global statement, check all global statements from the start of this one to the end of the last one.
        var globalStatement = updatedNode.Ancestors().OfType<GlobalStatementSyntax>().FirstOrDefault();
        if (globalStatement is not null)
        {
            var compilationUnit = (CompilationUnitSyntax)globalStatement.GetRequiredParent();
            return TextSpan.FromBounds(globalStatement.SpanStart, compilationUnit.Members.OfType<GlobalStatementSyntax>().Last().Span.End);
        }

        // Otherwise, find our containing code-containing member (attributes, accessors, fields, methods, properties,
        // anonymous methods), and check that entire member.  This means we only offer to remove the suppression if all
        // the suppressions in the member are unnecessary.  We need this granularity as doing things on a
        // per-suppression is just far too slow.
        //
        // We also check at this level because suppressions can have effects far outside of the containing statement (or