|
// 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);
}
}
}
|