| File: UseSiteAttributeProvider.cs | Web Access |
| Project: src\runtime\src\libraries\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj (Microsoft.Interop.SourceGeneration) |
// 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.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; namespace Microsoft.Interop { /// <summary> /// Parses information for all use-site attributes and tracks their usage. /// </summary> public sealed class UseSiteAttributeProvider { private readonly ImmutableDictionary<int, UseSiteAttributeData> _useSiteAttributesByIndirectionDepth; private readonly int _maxIndirectionLevelDataProvided; private readonly GeneratorDiagnosticsBag _diagnostics; private int _maxIndirectionLevelUsed; /// <summary> /// Construct a new <see cref="UseSiteAttributeProvider"/> for a given usage site. /// </summary> /// <param name="useSiteAttributeParsers">The parsers for the attributes at the given usage site.</param> /// <param name="useSiteAttributes">The attributes at the usage site.</param> /// <param name="elementInfoProvider">The provider for additional element information, used by the attribute parsers.</param> /// <param name="diagnostics">Diagnostics sink for any invalid configurations.</param> /// <param name="getMarshallingInfoCallback">A callback to get marshalling information for other elements. Used by <paramref name="elementInfoProvider"/>.</param> internal UseSiteAttributeProvider( ImmutableArray<IUseSiteAttributeParser> useSiteAttributeParsers, IEnumerable<AttributeData> useSiteAttributes, IElementInfoProvider elementInfoProvider, GeneratorDiagnosticsBag diagnostics, GetMarshallingInfoCallback getMarshallingInfoCallback) { ImmutableDictionary<int, UseSiteAttributeData>.Builder useSiteAttributesByIndirectionDepth = ImmutableDictionary.CreateBuilder<int, UseSiteAttributeData>(); _maxIndirectionLevelDataProvided = 0; foreach (AttributeData attribute in useSiteAttributes) { UseSiteAttributeData? useSiteAttributeData = GetUseSiteInfoForAttribute(attribute); if (useSiteAttributeData is not null) { int indirectionDepth = useSiteAttributeData.IndirectionDepth; if (useSiteAttributesByIndirectionDepth.ContainsKey(indirectionDepth)) { diagnostics.ReportInvalidMarshallingAttributeInfo(attribute, nameof(SR.DuplicateMarshallingInfo), indirectionDepth.ToString()); } else { useSiteAttributesByIndirectionDepth.Add(indirectionDepth, useSiteAttributeData); _maxIndirectionLevelDataProvided = Math.Max(_maxIndirectionLevelDataProvided, indirectionDepth); } } } _useSiteAttributesByIndirectionDepth = useSiteAttributesByIndirectionDepth.ToImmutable(); _diagnostics = diagnostics; UseSiteAttributeData? GetUseSiteInfoForAttribute(AttributeData attribute) { foreach (var parser in useSiteAttributeParsers) { // Automatically ignore invalid attributes. // The compiler will already error on them. if (attribute.AttributeConstructor is not null && parser.CanParseAttributeType(attribute.AttributeClass)) { return parser.ParseAttribute(attribute, elementInfoProvider, getMarshallingInfoCallback); } } return null; } } /// <summary> /// Get the <see cref="UseSiteAttributeData"/> provided for a given <paramref name="indirectionDepth"/>, if it exists. /// </summary> /// <param name="indirectionDepth">The indirection depth to retrieve info for.</param> /// <param name="useSiteInfo">The use site information, if it exists.</param> /// <returns><c>true</c> if an attribute was provided for the given indirection depth.</returns> public bool TryGetUseSiteAttributeInfo(int indirectionDepth, out UseSiteAttributeData useSiteInfo) { _maxIndirectionLevelUsed = Math.Max(indirectionDepth, _maxIndirectionLevelUsed); return _useSiteAttributesByIndirectionDepth.TryGetValue(indirectionDepth, out useSiteInfo); } /// <summary> /// Call when no more of the use-site attribute information will be used. /// Records any information or diagnostics about unused marshalling information. /// </summary> internal void OnAttributeUsageFinished() { if (_maxIndirectionLevelUsed < _maxIndirectionLevelDataProvided) { _diagnostics.ReportInvalidMarshallingAttributeInfo( _useSiteAttributesByIndirectionDepth[_maxIndirectionLevelDataProvided].AttributeData, nameof(SR.ExtraneousMarshallingInfo), _maxIndirectionLevelDataProvided.ToString(), _maxIndirectionLevelUsed.ToString()); } } } }