File: ErrorHandlingInfoParser.cs
Web Access
Project: LibraryImportGenerator.csproj (Microsoft.Interop.LibraryImportGenerator)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;

namespace Microsoft.Interop
{
    internal static class ErrorHandlingInfoParser
    {
        public static ErrorHandlingInfo? Parse(
            IMethodSymbol method,
            StubEnvironment environment,
            GeneratorDiagnosticsBag diagnostics)
        {
            AttributeData? attribute = null;
            foreach (AttributeData candidate in method.GetAttributes())
            {
                if (candidate.AttributeClass?.ToDisplayString() == TypeNames.ErrorHandlerAttribute)
                {
                    if (attribute is not null)
                    {
                        diagnostics.ReportConfigurationNotSupported(candidate, nameof(TypeNames.ErrorHandlerAttribute));
                        return null;
                    }

                    attribute = candidate;
                }
            }

            if (attribute is null)
            {
                return null;
            }

            if (attribute.AttributeConstructor is null
                || attribute.ConstructorArguments.Length != 2
                || attribute.ConstructorArguments[0].Value is not INamedTypeSymbol marshallerType
                || attribute.ConstructorArguments[1].Value is not int locationValue
                || locationValue is < (int)ErrorHandlingLocation.ReturnValue or > (int)ErrorHandlingLocation.HiddenLastParameter)
            {
                diagnostics.ReportConfigurationNotSupported(attribute, nameof(TypeNames.ErrorHandlerAttribute));
                return null;
            }

            if (!ManualTypeMarshallingHelper.TryGetManagedTypeFromEntryType(marshallerType, environment.Compilation, out ITypeSymbol? managedType))
            {
                diagnostics.ReportConfigurationNotSupported(attribute, nameof(TypeNames.ErrorHandlerAttribute));
                return null;
            }

            ErrorHandlingLocation location = (ErrorHandlingLocation)locationValue;
            if (location == ErrorHandlingLocation.ReturnValue
                && method.ReturnType.SpecialType != SpecialType.System_Void
                && !SymbolEqualityComparer.Default.Equals(method.ReturnType, managedType))
            {
                diagnostics.ReportConfigurationNotSupported(attribute, nameof(TypeNames.ErrorHandlerAttribute));
                return null;
            }

            if (location == ErrorHandlingLocation.LastParameter
                && (method.Parameters.Length == 0
                    || method.Parameters[method.Parameters.Length - 1] is not { RefKind: RefKind.Out or RefKind.Ref } lastParameter
                    || !SymbolEqualityComparer.Default.Equals(lastParameter.Type, managedType)))
            {
                diagnostics.ReportConfigurationNotSupported(attribute, nameof(TypeNames.ErrorHandlerAttribute));
                return null;
            }

            MarshallingInfo marshallingInfo = CustomMarshallingInfoHelper.CreateNativeMarshallingInfoForNonSignatureElement(
                managedType,
                marshallerType,
                attribute,
                environment.Compilation,
                diagnostics);

            if (marshallingInfo == NoMarshallingInfo.Instance)
            {
                diagnostics.ReportConfigurationNotSupported(attribute, nameof(TypeNames.ErrorHandlerAttribute));
                return null;
            }

            return new ErrorHandlingInfo(
                ManagedTypeInfo.CreateTypeInfoForTypeSymbol(managedType),
                marshallingInfo,
                location);
        }
    }
}