File: Evaluation\Expander.MetadataMatchEvaluator.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.Text.RegularExpressions;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using ItemSpecModifiers = Microsoft.Build.Framework.ItemSpecModifiers;

#nullable disable

namespace Microsoft.Build.Evaluation;

internal partial class Expander<P, I>
    where P : class, IProperty
    where I : class, IItem
{
    /// <summary>
    /// A functor that returns the value of the metadata in the match
    /// that is contained in the metadata dictionary it was created with.
    /// </summary>
    private struct MetadataMatchEvaluator
    {
        /// <summary>
        /// Source of the metadata.
        /// </summary>
        private IMetadataTable _metadata;

        /// <summary>
        /// Whether to expand built-in metadata, custom metadata, or both kinds.
        /// </summary>
        private ExpanderOptions _options;

        private IElementLocation _elementLocation;

        private LoggingContext _loggingContext;

        /// <summary>
        /// Constructor taking a source of metadata.
        /// </summary>
        internal MetadataMatchEvaluator(
            IMetadataTable metadata,
            ExpanderOptions options,
            IElementLocation elementLocation,
            LoggingContext loggingContext)
        {
            _metadata = metadata;
            _options = options & (ExpanderOptions.ExpandMetadata | ExpanderOptions.Truncate | ExpanderOptions.LogOnItemMetadataSelfReference);
            _elementLocation = elementLocation;
            _loggingContext = loggingContext;

            Assumed.NotEqual(options, ExpanderOptions.Invalid, "Must be expanding metadata of some kind");
        }

        /// <summary>
        /// Expands a single item metadata, which may be qualified with an item type.
        /// </summary>
        internal static string ExpandSingleMetadata(Match itemMetadataMatch, MetadataMatchEvaluator evaluator)
        {
            Assumed.True(itemMetadataMatch.Success, "Need a valid item metadata.");

            string metadataName = itemMetadataMatch.Groups[RegularExpressions.NameGroup].Value;

            string metadataValue = null;

            bool isBuiltInMetadata = ItemSpecModifiers.IsItemSpecModifier(metadataName);

            if (
                (isBuiltInMetadata && ((evaluator._options & ExpanderOptions.ExpandBuiltInMetadata) != 0)) ||
               (!isBuiltInMetadata && ((evaluator._options & ExpanderOptions.ExpandCustomMetadata) != 0)))
            {
                string itemType = null;

                // check if the metadata is qualified with the item type
                if (itemMetadataMatch.Groups[RegularExpressions.ItemSpecificationGroup].Length > 0)
                {
                    itemType = itemMetadataMatch.Groups[RegularExpressions.ItemTypeGroup].Value;
                }

                metadataValue = evaluator._metadata.GetEscapedValue(itemType, metadataName);

                if ((evaluator._options & ExpanderOptions.LogOnItemMetadataSelfReference) != 0 &&
                    evaluator._loggingContext != null &&
                    !string.IsNullOrEmpty(metadataName) &&
                    evaluator._metadata is IItemTypeDefinition itemMetadata &&
                    (string.IsNullOrEmpty(itemType) || string.Equals(itemType, itemMetadata.ItemType, StringComparison.Ordinal)))
                {
                    evaluator._loggingContext.LogComment(MessageImportance.Low, new BuildEventFileInfo(evaluator._elementLocation),
                        "ItemReferencingSelfInTarget", itemMetadata.ItemType, metadataName);
                }

                if (IsTruncationEnabled(evaluator._options) && metadataValue.Length > CharacterLimitPerExpansion)
                {
                    metadataValue = TruncateString(metadataValue);
                }
            }
            else
            {
                // look up the metadata - we may not have a value for it
                metadataValue = itemMetadataMatch.Value;
            }

            return metadataValue;
        }
    }
}