File: ContextReceiver.cs
Web Access
Project: src\src\Generators\Microsoft.Gen.ContextualOptions\Microsoft.Gen.ContextualOptions.csproj (Microsoft.Gen.ContextualOptions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace Microsoft.Gen.ContextualOptions;
 
/// <summary>
/// Type declaration syntax receiver for generators.
/// </summary>
internal sealed class ContextReceiver : ISyntaxReceiver
{
    private readonly CancellationToken _token;
 
    public ContextReceiver(CancellationToken token)
    {
        _token = token;
    }
 
    private readonly List<TypeDeclarationSyntax> _typeDeclarations = [];
 
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        _token.ThrowIfCancellationRequested();
 
        if (syntaxNode is TypeDeclarationSyntax type
            && type is not InterfaceDeclarationSyntax)
        {
            _typeDeclarations.Add(type);
        }
    }
 
    public bool TryGetTypeDeclarations(Compilation compilation, out Dictionary<INamedTypeSymbol, List<TypeDeclarationSyntax>>? typeDeclarations)
    {
        if (!SymbolLoader.TryLoad(compilation, out var holder))
        {
            typeDeclarations = default;
            return false;
        }
 
        typeDeclarations = _typeDeclarations
            .ToLookup(declaration => declaration.SyntaxTree)
            .SelectMany(declarations => declarations.Select(declaration => (symbol: compilation.GetSemanticModel(declarations.Key).GetDeclaredSymbol(declaration), declaration)))
            .Where(_ => _.symbol is INamedTypeSymbol)
            .Where(_ => _.symbol!.GetAttributes().Any(attribute => SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, holder!.OptionsContextAttribute)))
            .ToLookup(_ => _.symbol, _ => _.declaration, comparer: SymbolEqualityComparer.Default)
            .ToDictionary<IGrouping<ISymbol?, TypeDeclarationSyntax>, INamedTypeSymbol, List<TypeDeclarationSyntax>>(
                group => (INamedTypeSymbol)group.Key!, group => group.ToList(), comparer: SymbolEqualityComparer.Default);
 
        return true;
    }
}