File: Evaluation\Expander.FunctionBuilder.cs
Web Access
Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Shared.FileSystem;

#nullable disable

namespace Microsoft.Build.Evaluation;

internal partial class Expander<P, I>
    where P : class, IProperty
    where I : class, IItem
{
    private struct FunctionBuilder
    {
        /// <summary>
        /// Backing field for <see cref="ReceiverType"/>. Carries the same annotation as the property so the
        /// getter's return value is satisfied by a field with a matching requirement: a compiler-generated
        /// auto-property backing field does not inherit the property's annotation, which is what produces IL2078.
        /// </summary>
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicConstructors |
            DynamicallyAccessedMemberTypes.PublicMethods |
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicFields)]
        private Type _receiverType;

        /// <summary>
        /// The type of this function's receiver. Only the public member surface is preserved for trimming:
        /// property functions never bind non-public members (<see cref="BindingFlags.NonPublic"/> is rejected
        /// by <c>TypeExtensions.InvokePublicMember</c>). Keep in sync with <c>Function._receiverType</c> and
        /// <c>Constants.PropertyFunctionMembers</c>.
        /// </summary>
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicConstructors |
            DynamicallyAccessedMemberTypes.PublicMethods |
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicFields)]
        public readonly Type ReceiverType => _receiverType;

        /// <summary>
        /// Sets <see cref="ReceiverType"/> from a property-function receiver type. That type is always either
        /// a type from MSBuild's curated static-method allowlist (resolved by name, its public members
        /// preserved for trimming by <c>Constants.PropertyFunctionMembers</c>) or a runtime value's
        /// <c>GetType()</c>; property functions bind only the public surface. This one-line setter writes the
        /// annotated <see cref="_receiverType"/> field directly, so it is the single place an un-annotated
        /// <see cref="Type"/> enters the <c>DynamicallyAccessedMembers</c>-tracked flow and the localized,
        /// minimized home of the IL2069 suppression - every downstream hop (<c>Build</c> -> <c>Function</c>
        /// -> <c>InvokePublicMember</c>) is then machine-checked.
        /// </summary>
        [UnconditionalSuppressMessage("Trimming", "IL2069",
            Justification = "Receiver type comes from the static-method allowlist (public members preserved by Constants.PropertyFunctionMembers) or a runtime GetType(); only public members are bound. See the summary for the DAM-flow rationale.")]
        internal void SetReceiverType(Type receiverType) => _receiverType = receiverType;

        /// <summary>
        /// The name of the function.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// The arguments for the function.
        /// </summary>
        public string[] Arguments { get; set; }

        /// <summary>
        /// The expression that this function is part of.
        /// </summary>
        public string Expression { get; set; }

        /// <summary>
        /// The property name that this function is applied on.
        /// </summary>
        public string Receiver { get; set; }

        /// <summary>
        /// The binding flags that will be used during invocation of this function.
        /// </summary>
        public BindingFlags BindingFlags { get; set; }

        /// <summary>
        /// The remainder of the body once the function and arguments have been extracted.
        /// </summary>
        public string Remainder { get; set; }

        public IFileSystem FileSystem { get; set; }

        public LoggingContext LoggingContext { get; set; }

        /// <summary>
        /// List of properties which have been used but have not been initialized yet.
        /// </summary>
        public PropertiesUseTracker PropertiesUseTracker { get; set; }

        internal readonly Function Build()
        {
            return new Function(
                ReceiverType,
                Expression,
                Receiver,
                Name,
                Arguments,
                BindingFlags,
                Remainder,
                PropertiesUseTracker,
                FileSystem,
                LoggingContext);
        }
    }
}