| File: Linker\MemberActionStore.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using ILLink.Shared; using Mono.Cecil; namespace Mono.Linker { public class MemberActionStore { public SubstitutionInfo PrimarySubstitutionInfo { get; } private readonly Dictionary<AssemblyDefinition, SubstitutionInfo?> _embeddedXmlInfos; readonly LinkContext _context; public MemberActionStore(LinkContext context) { PrimarySubstitutionInfo = new SubstitutionInfo(); _embeddedXmlInfos = new Dictionary<AssemblyDefinition, SubstitutionInfo?>(); _context = context; } private bool TryGetSubstitutionInfo(MemberReference member, [NotNullWhen(true)] out SubstitutionInfo? xmlInfo) { var assembly = member.Module.Assembly; if (!_embeddedXmlInfos.TryGetValue(assembly, out xmlInfo)) { xmlInfo = _context.EmbeddedXmlInfo.ProcessSubstitutions(assembly, _context); _embeddedXmlInfos.Add(assembly, xmlInfo); } return xmlInfo != null; } public MethodAction GetAction(MethodDefinition method) { if (PrimarySubstitutionInfo.MethodActions.TryGetValue(method, out MethodAction action)) return action; if (TryGetSubstitutionInfo(method, out var embeddedXml)) { if (embeddedXml.MethodActions.TryGetValue(method, out action)) return action; } if (TryGetFeatureCheckValue(method, out _)) return MethodAction.ConvertToStub; return MethodAction.Nothing; } public bool TryGetMethodStubValue(MethodDefinition method, out object? value) { if (PrimarySubstitutionInfo.MethodStubValues.TryGetValue(method, out value)) return true; if (TryGetSubstitutionInfo(method, out var embeddedXml) && embeddedXml.MethodStubValues.TryGetValue(method, out value)) return true; if (TryGetFeatureCheckValue(method, out bool bValue)) { value = bValue ? 1 : 0; return true; } return false; } internal bool TryGetFeatureCheckValue(MethodDefinition method, out bool value) { value = false; if (!method.IsStatic) return false; if (method.ReturnType.MetadataType != MetadataType.Boolean) return false; if (FindProperty(method) is not PropertyDefinition property) return false; if (property.SetMethod != null) return false; foreach (var featureSwitchDefinitionAttribute in _context.CustomAttributes.GetCustomAttributes(property, "System.Diagnostics.CodeAnalysis", "FeatureSwitchDefinitionAttribute")) { if (featureSwitchDefinitionAttribute.ConstructorArguments is not [CustomAttributeArgument { Value: string switchName }]) continue; // If there's a FeatureSwitchDefinition, don't continue looking for FeatureGuard. // We don't want to infer feature switch settings from FeatureGuard. if (_context.FeatureSettings.TryGetValue(switchName, out value)) return true; return false; } if (!_context.IsOptimizationEnabled(CodeOptimizations.SubstituteFeatureGuards, method)) return false; foreach (var featureGuardAttribute in _context.CustomAttributes.GetCustomAttributes(property, "System.Diagnostics.CodeAnalysis", "FeatureGuardAttribute")) { if (featureGuardAttribute.ConstructorArguments is not [CustomAttributeArgument { Value: TypeReference featureType }]) continue; if (featureType.Namespace == "System.Diagnostics.CodeAnalysis") { switch (featureType.Name) { case "RequiresUnreferencedCodeAttribute": return true; case "RequiresDynamicCodeAttribute": if (_context.FeatureSettings.TryGetValue( "System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported", out bool isDynamicCodeSupported) && !isDynamicCodeSupported) return true; break; } } } return false; static PropertyDefinition? FindProperty(MethodDefinition method) { if (!method.IsGetter) return null; foreach (var property in method.DeclaringType.Properties) { if (property.GetMethod == method) return property; } return null; } } public bool TryGetFieldUserValue(FieldDefinition field, out object? value) { if (PrimarySubstitutionInfo.FieldValues.TryGetValue(field, out value)) return true; if (!TryGetSubstitutionInfo(field, out var embeddedXml)) return false; return embeddedXml.FieldValues.TryGetValue(field, out value); } } }