| File: Symbols\Attributes\AttributeUsageInfo.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { internal readonly struct AttributeUsageInfo : IEquatable<AttributeUsageInfo> { [Flags()] private enum PackedAttributeUsage { None = 0, Assembly = AttributeTargets.Assembly, Module = AttributeTargets.Module, Class = AttributeTargets.Class, Struct = AttributeTargets.Struct, Enum = AttributeTargets.Enum, Constructor = AttributeTargets.Constructor, Method = AttributeTargets.Method, Property = AttributeTargets.Property, Field = AttributeTargets.Field, Event = AttributeTargets.Event, Interface = AttributeTargets.Interface, Parameter = AttributeTargets.Parameter, Delegate = AttributeTargets.Delegate, ReturnValue = AttributeTargets.ReturnValue, GenericParameter = AttributeTargets.GenericParameter, All = AttributeTargets.All, // NOTE: VB allows AttributeUsageAttribute with no valid target, i.e. <AttributeUsageAttribute(0)>, and doesn't generate any diagnostics. // We use PackedAttributeUsage.Initialized field to differentiate between uninitialized AttributeUsageInfo and initialized AttributeUsageInfo with no valid target. Initialized = GenericParameter << 1, AllowMultiple = Initialized << 1, Inherited = AllowMultiple << 1 } private readonly PackedAttributeUsage _flags; /// <summary> /// Default attribute usage for attribute types: /// (a) Valid targets: AttributeTargets.All /// (b) AllowMultiple: false /// (c) Inherited: true /// </summary> internal static readonly AttributeUsageInfo Default = new AttributeUsageInfo(validTargets: AttributeTargets.All, allowMultiple: false, inherited: true); internal static readonly AttributeUsageInfo Null = default(AttributeUsageInfo); internal AttributeUsageInfo(AttributeTargets validTargets, bool allowMultiple, bool inherited) { // NOTE: VB allows AttributeUsageAttribute with no valid target, i.e. <AttributeUsageAttribute(0)>, and doesn't generate any diagnostics. // We use PackedAttributeUsage.Initialized field to differentiate between uninitialized AttributeUsageInfo and initialized AttributeUsageInfo with no valid targets. _flags = (PackedAttributeUsage)validTargets | PackedAttributeUsage.Initialized; if (allowMultiple) { _flags |= PackedAttributeUsage.AllowMultiple; } if (inherited) { _flags |= PackedAttributeUsage.Inherited; } } public bool IsNull { get { return (_flags & PackedAttributeUsage.Initialized) == 0; } } internal AttributeTargets ValidTargets { get { return (AttributeTargets)(_flags & PackedAttributeUsage.All); } } internal bool AllowMultiple { get { return (_flags & PackedAttributeUsage.AllowMultiple) != 0; } } internal bool Inherited { get { return (_flags & PackedAttributeUsage.Inherited) != 0; } } public static bool operator ==(AttributeUsageInfo left, AttributeUsageInfo right) { return left._flags == right._flags; } public static bool operator !=(AttributeUsageInfo left, AttributeUsageInfo right) { return left._flags != right._flags; } public override bool Equals(object? obj) { if (obj is AttributeUsageInfo) { return this.Equals((AttributeUsageInfo)obj); } return false; } public bool Equals(AttributeUsageInfo other) { return this == other; } public override int GetHashCode() { return ((int)_flags).GetHashCode(); } internal bool HasValidAttributeTargets { get { var value = (int)ValidTargets; return value != 0 && (value & (int)~AttributeTargets.All) == 0; } } internal object GetValidTargetsErrorArgument() { var validTargetsInt = (int)ValidTargets; if (!HasValidAttributeTargets) { return string.Empty; } var builder = ArrayBuilder<string>.GetInstance(); int flag = 0; while (validTargetsInt > 0) { if ((validTargetsInt & 1) != 0) { builder.Add(GetErrorDisplayNameResourceId((AttributeTargets)(1 << flag))); } validTargetsInt >>= 1; flag++; } return new ValidTargetsStringLocalizableErrorArgument(builder.ToArrayAndFree()); } private readonly struct ValidTargetsStringLocalizableErrorArgument : IFormattable { private readonly string[]? _targetResourceIds; internal ValidTargetsStringLocalizableErrorArgument(string[] targetResourceIds) { RoslynDebug.Assert(targetResourceIds != null); _targetResourceIds = targetResourceIds; } public override string ToString() { return ToString(null, null); } public string ToString(string? format, IFormatProvider? formatProvider) { var builder = PooledStringBuilder.GetInstance(); var culture = formatProvider as System.Globalization.CultureInfo; if (_targetResourceIds != null) { foreach (string id in _targetResourceIds) { if (builder.Builder.Length > 0) { builder.Builder.Append(", "); } builder.Builder.Append(CodeAnalysisResources.ResourceManager.GetString(id, culture)); } } var message = builder.Builder.ToString(); builder.Free(); return message; } } private static string GetErrorDisplayNameResourceId(AttributeTargets target) { switch (target) { case AttributeTargets.Assembly: return nameof(CodeAnalysisResources.Assembly); case AttributeTargets.Class: return nameof(CodeAnalysisResources.Class1); case AttributeTargets.Constructor: return nameof(CodeAnalysisResources.Constructor); case AttributeTargets.Delegate: return nameof(CodeAnalysisResources.Delegate1); case AttributeTargets.Enum: return nameof(CodeAnalysisResources.Enum1); case AttributeTargets.Event: return nameof(CodeAnalysisResources.Event1); case AttributeTargets.Field: return nameof(CodeAnalysisResources.Field); case AttributeTargets.GenericParameter: return nameof(CodeAnalysisResources.TypeParameter); case AttributeTargets.Interface: return nameof(CodeAnalysisResources.Interface1); case AttributeTargets.Method: return nameof(CodeAnalysisResources.Method); case AttributeTargets.Module: return nameof(CodeAnalysisResources.Module); case AttributeTargets.Parameter: return nameof(CodeAnalysisResources.Parameter); case AttributeTargets.Property: return nameof(CodeAnalysisResources.Property); case AttributeTargets.ReturnValue: return nameof(CodeAnalysisResources.Return1); case AttributeTargets.Struct: return nameof(CodeAnalysisResources.Struct1); default: throw ExceptionUtilities.UnexpectedValue(target); } } } }