|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if HAS_IOPERATION
namespace Analyzer.Utilities.Lightup
{
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Operations;
[SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "Not a comparable instance.")]
internal readonly struct IFunctionPointerInvocationOperationWrapper : IOperationWrapper
{
internal const string WrappedTypeName = "Microsoft.CodeAnalysis.Operations.IFunctionPointerInvocationOperation";
private static readonly Type? WrappedType = OperationWrapperHelper.GetWrappedType(typeof(IFunctionPointerInvocationOperationWrapper));
private static readonly Func<IOperation, ImmutableArray<IArgumentOperation>> ArgumentsAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, ImmutableArray<IArgumentOperation>>(WrappedType, nameof(Arguments), fallbackResult: ImmutableArray<IArgumentOperation>.Empty);
private static readonly Func<IOperation, IOperation> TargetAccessor = LightupHelpers.CreateOperationPropertyAccessor<IOperation, IOperation>(WrappedType, nameof(Target), fallbackResult: null!);
private static readonly Func<IOperation, IMethodSymbol> GetFunctionPointerSignatureAccessor = CreateFunctionPointerSignatureAccessor(WrappedType);
private static Func<IOperation, IMethodSymbol> CreateFunctionPointerSignatureAccessor(Type? wrappedType)
{
if (wrappedType == null)
{
return op => null!;
}
var targetMethod = typeof(OperationExtensions).GetTypeInfo().GetDeclaredMethod("GetFunctionPointerSignature");
if (targetMethod is null)
{
return op => null!;
}
var operation = Expression.Variable(typeof(IOperation));
return Expression.Lambda<Func<IOperation, IMethodSymbol>>(Expression.Call(targetMethod, Expression.Convert(operation, wrappedType)), operation).Compile();
}
private IFunctionPointerInvocationOperationWrapper(IOperation operation)
{
WrappedOperation = operation;
}
public IOperation WrappedOperation { get; }
public ITypeSymbol? Type => WrappedOperation.Type;
public ImmutableArray<IArgumentOperation> Arguments => ArgumentsAccessor(WrappedOperation);
public IOperation Target => TargetAccessor(WrappedOperation);
public IMethodSymbol GetFunctionPointerSignature() => GetFunctionPointerSignatureAccessor(WrappedOperation);
public static IFunctionPointerInvocationOperationWrapper FromOperation(IOperation operation)
{
if (operation == null)
{
return default;
}
if (!IsInstance(operation))
{
throw new InvalidCastException($"Cannot cast '{operation.GetType().FullName}' to '{WrappedTypeName}'");
}
return new IFunctionPointerInvocationOperationWrapper(operation);
}
public static bool IsInstance(IOperation operation)
{
return operation != null && LightupHelpers.CanWrapOperation(operation, WrappedType);
}
}
}
#endif
|