File: Compiler\DependencyAnalysis\InlineableStringsResourceNode.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler)
// 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.Collections.Generic;

using ILCompiler.DependencyAnalysisFramework;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a resource blob used by the SR class in the BCL.
    /// If this node is present in the graph, it means we were not able to optimize its use away
    /// and the blob has to be generated.
    /// </summary>
    internal sealed class InlineableStringsResourceNode : DependencyNodeCore<NodeFactory>
    {
        private readonly EcmaModule _module;

        public static ReadOnlySpan<byte> ResourceAccessorTypeName => "SR"u8;
        public static ReadOnlySpan<byte> ResourceAccessorTypeNamespace => "System"u8;
        public static ReadOnlySpan<byte> ResourceAccessorGetStringMethodName => "GetResourceString"u8;

        public InlineableStringsResourceNode(EcmaModule module)
        {
            _module = module;
        }

        public override bool InterestingForDynamicDependencyAnalysis => false;

        public override bool HasDynamicDependencies => false;

        public override bool HasConditionalStaticDependencies => false;

        public override bool StaticDependenciesAreComputed => true;

        public static bool IsInlineableStringsResource(EcmaModule module, string resourceName)
        {
            if (!resourceName.EndsWith(".resources", StringComparison.Ordinal))
                return false;

            // Make a guess at the name of the resource Arcade tooling generated for the resource
            // strings.
            // https://github.com/dotnet/runtime/issues/81385 tracks not having to guess this.
            string simpleName = module.Assembly.GetName().Name;
            string resourceName1 = $"{simpleName}.Strings.resources";
            string resourceName2 = $"FxResources.{simpleName}.SR.resources";

            if (resourceName != resourceName1 && resourceName != resourceName2)
                return false;

            MetadataType srType = module.GetType(ResourceAccessorTypeNamespace, ResourceAccessorTypeName, throwIfNotFound: false);
            if (srType == null)
                return false;

            return srType.GetMethod(ResourceAccessorGetStringMethodName, null) != null;
        }

        public static void AddDependenciesDueToResourceStringUse(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
        {
            if (method.Name.SequenceEqual(ResourceAccessorGetStringMethodName) && method.OwningType is MetadataType mdType
                && mdType.Name.SequenceEqual(ResourceAccessorTypeName) && mdType.Namespace.SequenceEqual(ResourceAccessorTypeNamespace))
            {
                dependencies ??= new DependencyList();
                dependencies.Add(factory.InlineableStringResource((EcmaModule)mdType.Module), "Using the System.SR class");
            }
        }

        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) => null;
        public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
        protected override string GetName(NodeFactory context)
            => $"String resources for {_module.Assembly.GetName().Name}";
    }
}