📄 Core/ExcludingMembersCollector.cs
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;

namespace Reacher;

internal class ExcludingMembersCollector(IReadOnlySet<ISymbol> excludedMembers, Predicate<ISymbol> predicate)
    : SymbolVisitor
{
    public IReadOnlySet<ISymbol> Members => members;
    private readonly HashSet<ISymbol> members = [];

    public override void VisitAssembly(IAssemblySymbol symbol)
    {
        symbol.GlobalNamespace.Accept(this);
    }

    public override void VisitNamespace(INamespaceSymbol symbol)
    {
        foreach (var namespaceOrType in symbol.GetMembers())
        {
            namespaceOrType.Accept(this);
        }
    }

    public override void VisitNamedType(INamedTypeSymbol type)
    {
        foreach (var member in type.GetMembers())
        {
            member.Accept(this);
        }

        foreach (var nestedType in type.GetTypeMembers())
        {
            nestedType.Accept(this);
        }
    }

    public override void VisitMethod(IMethodSymbol method) => VisitMember(method);

    public override void VisitProperty(IPropertySymbol property) => VisitMember(property);

    private void VisitMember(ISymbol member)
    {
        if (excludedMembers.Contains(member) || !predicate(member))
        {
            return;
        }

        members.Add(member);
    }
}