File: ComClassInfo.cs
Web Access
Project: src\src\libraries\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj (Microsoft.Interop.ComInterfaceGenerator)
// 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.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace Microsoft.Interop
{
    internal sealed record ComClassInfo
    {
        public string ClassName { get; init; }
        public ContainingSyntaxContext ContainingSyntaxContext { get; init; }
        public ContainingSyntax ClassSyntax { get; init; }
        public SequenceEqualImmutableArray<string> ImplementedInterfacesNames { get; init; }
 
        private ComClassInfo(string className, ContainingSyntaxContext containingSyntaxContext, ContainingSyntax classSyntax, SequenceEqualImmutableArray<string> implementedInterfacesNames)
        {
            ClassName = className;
            ContainingSyntaxContext = containingSyntaxContext;
            ClassSyntax = classSyntax;
            ImplementedInterfacesNames = implementedInterfacesNames;
        }
 
        public static DiagnosticOr<ComClassInfo> From(INamedTypeSymbol type, ClassDeclarationSyntax syntax, bool unsafeCodeIsEnabled)
        {
            if (!unsafeCodeIsEnabled)
            {
                return DiagnosticOr<ComClassInfo>.From(DiagnosticInfo.Create(GeneratorDiagnostics.RequiresAllowUnsafeBlocks, syntax.Identifier.GetLocation()));
            }
 
            if (!syntax.IsInPartialContext(out _))
            {
                return DiagnosticOr<ComClassInfo>.From(
                    DiagnosticInfo.Create(
                        GeneratorDiagnostics.InvalidAttributedClassMissingPartialModifier,
                        syntax.Identifier.GetLocation(),
                        type.ToDisplayString()));
            }
 
            ImmutableArray<string>.Builder names = ImmutableArray.CreateBuilder<string>();
            foreach (INamedTypeSymbol iface in type.AllInterfaces)
            {
                AttributeData? generatedComInterfaceAttribute = iface.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.GeneratedComInterfaceAttribute);
                if (generatedComInterfaceAttribute is not null)
                {
                    var attributeData = GeneratedComInterfaceCompilationData.GetDataFromAttribute(generatedComInterfaceAttribute);
                    if (attributeData.Options.HasFlag(ComInterfaceOptions.ManagedObjectWrapper))
                    {
                        names.Add(iface.ToDisplayString());
                    }
                }
            }
 
            if (names.Count == 0)
            {
                return DiagnosticOr<ComClassInfo>.From(DiagnosticInfo.Create(GeneratorDiagnostics.ClassDoesNotImplementAnyGeneratedComInterface,
                    syntax.Identifier.GetLocation(),
                    type.ToDisplayString()));
            }
 
            return DiagnosticOr<ComClassInfo>.From(
                new ComClassInfo(
                    type.ToDisplayString(),
                    new ContainingSyntaxContext(syntax),
                    new ContainingSyntax(syntax.Modifiers, syntax.Kind(), syntax.Identifier, syntax.TypeParameterList),
                    new(names.ToImmutable())));
        }
 
        public bool Equals(ComClassInfo? other)
        {
            return other is not null
                && ClassName == other.ClassName
                && ContainingSyntaxContext.Equals(other.ContainingSyntaxContext)
                && ImplementedInterfacesNames.SequenceEqual(other.ImplementedInterfacesNames);
        }
 
        public override int GetHashCode()
        {
            return HashCode.Combine(ClassName, ContainingSyntaxContext, ImplementedInterfacesNames);
        }
    }
}