File: Analyzers\ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer.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.Diagnostics;
using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
using Microsoft.CodeAnalysis.Operations;
using static Microsoft.Interop.Analyzers.AnalyzerDiagnostics;
 
namespace Microsoft.Interop.Analyzers
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class ComHostingDoesNotSupportGeneratedComInterfaceAnalyzer : DiagnosticAnalyzer
    {
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(ComHostingDoesNotSupportGeneratedComInterface);
 
        public override void Initialize(AnalysisContext context)
        {
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            context.EnableConcurrentExecution();
            context.RegisterCompilationStartAction(context =>
            {
                if (!context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue("build_property.EnableComHosting", out string? enableComHosting)
                    || !bool.TryParse(enableComHosting, out bool enableComHostingValue)
                    || !enableComHostingValue)
                {
                    return;
                }
 
                INamedTypeSymbol? generatedComClassAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComClassAttribute);
                INamedTypeSymbol? generatedComInterfaceAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.GeneratedComInterfaceAttribute);
                INamedTypeSymbol? comVisibleAttribute = context.Compilation.GetBestTypeByMetadataName(TypeNames.System_Runtime_InteropServices_ComVisibleAttribute)!;
 
                if (generatedComClassAttribute is null || generatedComInterfaceAttribute is null || comVisibleAttribute is null)
                {
                    return;
                }
 
                context.RegisterOperationAction(context =>
                {
                    IAttributeOperation attr = (IAttributeOperation)context.Operation;
                    if (attr.Operation is not IObjectCreationOperation ctor
                        || !comVisibleAttribute.Equals(ctor.Type, SymbolEqualityComparer.Default)
                        || ctor.Arguments[0].Value.ConstantValue.Value is not true)
                    {
                        return;
                    }
 
                    INamedTypeSymbol containingType = (INamedTypeSymbol)context.ContainingSymbol;
 
                    if (containingType.GetAttributes().Any(attr => generatedComClassAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default)))
                    {
                        context.ReportDiagnostic(context.ContainingSymbol.CreateDiagnostic(ComHostingDoesNotSupportGeneratedComInterface, context.ContainingSymbol.Name));
                        return;
                    }
 
                    foreach (var iface in containingType.AllInterfaces)
                    {
                        if (iface.GetAttributes().Any(attr => generatedComInterfaceAttribute.Equals(attr.AttributeClass, SymbolEqualityComparer.Default)))
                        {
                            context.ReportDiagnostic(context.ContainingSymbol.CreateDiagnostic(ComHostingDoesNotSupportGeneratedComInterface, context.ContainingSymbol.Name));
                            return;
                        }
                    }
                }, OperationKind.Attribute);
            });
        }
    }
}