File: Linker\CustomAttributeSource.cs
Web Access
Project: src\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;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Mono.Cecil;
 
namespace Mono.Linker
{
	public class CustomAttributeSource
	{
		public AttributeInfo PrimaryAttributeInfo { get; }
		private readonly Dictionary<AssemblyDefinition, AttributeInfo?> _embeddedXmlInfos;
		readonly LinkContext _context;
 
		public CustomAttributeSource (LinkContext context)
		{
			PrimaryAttributeInfo = new AttributeInfo ();
			_embeddedXmlInfos = new Dictionary<AssemblyDefinition, AttributeInfo?> ();
			_context = context;
		}
 
		public static AssemblyDefinition GetAssemblyFromCustomAttributeProvider (ICustomAttributeProvider provider)
		{
			return provider switch {
				MemberReference mr => mr.Module.Assembly,
				AssemblyDefinition ad => ad,
				ModuleDefinition md => md.Assembly,
				InterfaceImplementation ii => ii.InterfaceType.Module.Assembly,
				GenericParameterConstraint gpc => gpc.ConstraintType.Module.Assembly,
				ParameterDefinition pd => pd.ParameterType.Module.Assembly,
				MethodReturnType mrt => mrt.ReturnType.Module.Assembly,
				_ => throw new NotImplementedException (provider.GetType ().ToString ()),
			};
		}
 
		public bool TryGetEmbeddedXmlInfo (ICustomAttributeProvider provider, [NotNullWhen (true)] out AttributeInfo? xmlInfo)
		{
			AssemblyDefinition assembly = GetAssemblyFromCustomAttributeProvider (provider);
 
			if (!_embeddedXmlInfos.TryGetValue (assembly, out xmlInfo)) {
				// Add an empty record - this prevents reentrancy
				// If the embedded XML itself generates warnings, trying to log such warning
				// may ask for attributes (suppressions) and thus we could end up in this very place again
				// So first add a dummy record and once processed we will replace it with the real data
				_embeddedXmlInfos.Add (assembly, new AttributeInfo ());
				xmlInfo = _context.EmbeddedXmlInfo.ProcessAttributes (assembly, _context);
				_embeddedXmlInfos[assembly] = xmlInfo;
			}
 
			return xmlInfo != null;
		}
 
		public IEnumerable<CustomAttribute> GetCustomAttributes (ICustomAttributeProvider provider, string attributeNamespace, string attributeName)
		{
			foreach (var attr in GetCustomAttributes (provider)) {
				if (attr.AttributeType.Namespace == attributeNamespace && attr.AttributeType.Name == attributeName)
					yield return attr;
			}
		}
 
		public IEnumerable<CustomAttribute> GetCustomAttributes (ICustomAttributeProvider provider)
		{
			if (provider.HasCustomAttributes) {
				foreach (var customAttribute in provider.CustomAttributes)
					yield return customAttribute;
			}
 
			if (PrimaryAttributeInfo.CustomAttributes.TryGetValue (provider, out var annotations)) {
				foreach (var customAttribute in annotations)
					yield return customAttribute;
			}
 
			if (!TryGetEmbeddedXmlInfo (provider, out var embeddedXml))
				yield break;
 
			if (embeddedXml.CustomAttributes.TryGetValue (provider, out annotations)) {
				foreach (var customAttribute in annotations)
					yield return customAttribute;
			}
		}
 
		public bool TryGetCustomAttributeOrigin (ICustomAttributeProvider provider, CustomAttribute customAttribute, out MessageOrigin origin)
		{
			if (PrimaryAttributeInfo.CustomAttributesOrigins.TryGetValue (customAttribute, out origin))
				return true;
 
			if (!TryGetEmbeddedXmlInfo (provider, out var embeddedXml))
				return false;
 
			return embeddedXml.CustomAttributesOrigins.TryGetValue (customAttribute, out origin);
		}
 
		public bool HasAny (ICustomAttributeProvider provider)
		{
			if (provider.HasCustomAttributes)
				return true;
 
			if (PrimaryAttributeInfo.CustomAttributes.ContainsKey (provider))
				return true;
 
			if (!TryGetEmbeddedXmlInfo (provider, out var embeddedXml))
				return false;
 
			return embeddedXml.CustomAttributes.ContainsKey (provider);
		}
	}
}