GCが発生するIReadOnlyList<T>等のforeachに警告を出すRoslynAnalyzer

IReadOnlyList<T>をforeachで回すとGCが発生するのは周知の事実ですが、
外部にプロパティを公開するならIReadOnlyListやIReadOnlyDictionaryを使いたいし、
そもそも他にもGCが発生するforeachのパターンあるよな・・・と考え出すと、
気軽にforeachも書けないわけです。

ということで、RoslynAnalyzerでGCが発生するforeachを書いたら警告が出るようにしてみました。
これで本当に条件が網羅出来ているか不安...
もっと良い判定方法ご存知の方いたら教えてください。

ForeachGcAnalyzer.cs
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace MyAnalyzer;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class ForeachGcAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "GCFOREACH001";
    private static readonly LocalizableString Title = "GC アロケーションを伴う foreach";
    private static readonly LocalizableString MessageFormat = "この foreach は GC ヒープに IEnumerator を確保します。for ループや Span<T> の利用を検討してください";
    private static readonly LocalizableString Description = "参照型 IEnumerator または boxing が発生する foreach を検出して警告します。";
    private const string Category = "Performance";

    private static readonly DiagnosticDescriptor Rule = new(
        DiagnosticId,
        Title,
        MessageFormat,
        Category,
        DiagnosticSeverity.Warning,
        isEnabledByDefault: true,
        description: Description
    );

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

    public override void Initialize(AnalysisContext context)
    {
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.EnableConcurrentExecution();
        context.RegisterSyntaxNodeAction(AnalyzeForeach, SyntaxKind.ForEachStatement);
    }

    private static void AnalyzeForeach(SyntaxNodeAnalysisContext context)
    {
        var foreachStmt = (ForEachStatementSyntax) context.Node;
        var model = context.SemanticModel;
        var info = model.GetForEachStatementInfo(foreachStmt);
        var collectionType = model.GetTypeInfo(foreachStmt.Expression).Type;

        if (collectionType == null) return;

        if (ShouldWarn(info, collectionType))
        {
            var diag = Diagnostic.Create(Rule, foreachStmt.ForEachKeyword.GetLocation());
            context.ReportDiagnostic(diag);
        }
    }

    private static bool ShouldWarn(ForEachStatementInfo info, ITypeSymbol collectionType)
    {
        if (collectionType is IArrayTypeSymbol)
        {
            return false;
        }

        if (collectionType.SpecialType == SpecialType.System_String)
        {
            return false;
        }

        var enumeratorType = info.GetEnumeratorMethod?.ReturnType;
        if (enumeratorType == null)
        {
            return false;
        }

        if (enumeratorType.IsReferenceType)
        {
            return true;
        }

        if (enumeratorType.IsValueType)
        {
            switch (collectionType.TypeKind)
            {
                case TypeKind.Interface:
                case TypeKind.Dynamic:
                    return true;
            }

            if (collectionType.SpecialType == SpecialType.System_Object)
            {
                return true;
            }

            return false;
        }

        return true;
    }
}

netstandard2.0のクラスライブラリプロジェクトとしてビルドし、
できたdllをUnityプロジェクトのAssets以下に配置、
Asset LabelsにRoslynAnalyzerを追加するとUnityプロジェクトでも動作します。