|
// 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.Linq;
using System.Reflection;
namespace Microsoft.Build.Shared
{
/// <summary>
/// Utility extension methods for working with <see cref="Type"/> metadata in a resilient manner.
/// </summary>
/// <remarks>
/// These helpers intentionally:
/// - Catch and suppress non-critical reflection/type loading exceptions so callers can probe for attributes safely
/// even when some referenced types cannot be loaded in the current load context.
/// - Compare attribute types by their simple <see cref="MemberInfo.Name"/> (e.g. <c>ObsoleteAttribute</c>) rather than
/// full name or assembly-qualified name. This mirrors existing MSBuild behavior but means ambiguous attribute
/// short names across different assemblies cannot be distinguished here.
/// </remarks>
internal static class TypeUtilities
{
/// <summary>
/// Determines whether the specified <paramref name="type"/> is decorated with an attribute of type <typeparamref name="T"/>.
/// </summary>
public static bool HasAttribute<T>(this Type type)
where T : Attribute => type.HasAttribute(typeof(T).Name);
/// <summary>
/// Determines whether the specified <paramref name="type"/> is decorated with an attribute whose simple type name
/// equals <paramref name="attributeName"/>.
/// </summary>
public static bool HasAttribute(this Type type, string attributeName)
{
if (type == null)
{
return false;
}
return CustomAttributeData
.GetCustomAttributes(type)
.Any(attr => SafeGetAttributeName(attr) == attributeName);
}
/// <summary>
/// Safely retrieves the simple name of an attribute's type, swallowing non-critical reflection exceptions.
/// </summary>
/// <param name="attr">The attribute metadata.</param>
/// <returns>The simple attribute type name, or <c>null</c> if it cannot be resolved.</returns>
private static string? SafeGetAttributeName(CustomAttributeData attr) => attr.AttributeType?.Name;
}
}
|