File: RestoreCommand\DependencyGraphResolver.ResolvedDependencyGraphItem.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.Commands\NuGet.Commands.csproj (NuGet.Commands)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using NuGet.DependencyResolver;
using NuGet.LibraryModel;

namespace NuGet.Commands
{
    internal sealed partial class DependencyGraphResolver
    {
        /// <summary>
        /// Represents a resolved dependency graph item for the dependency graph resolver.
        /// </summary>
        [DebuggerDisplay("{LibraryDependency}, RangeIndex={LibraryRangeIndex}")]
        public class ResolvedDependencyGraphItem
        {
            /// <summary>
            /// Stores an array containing all of the <see cref="LibraryDependencyIndex" /> of dependencies of this item. This allows fast lookup of their indices rather than having to convert the name to an index.
            /// </summary>
            private LibraryDependencyIndex[] _dependencyIndices;

            /// <summary>
            /// Stores an array containing all of the <see cref="LibraryRangeIndex" /> of dependencies of this item. This allows fast lookup of their range indices rather than having to convert the <see cref="LibraryRange" /> to an index.
            /// </summary>
            private LibraryRangeIndex[] _rangeIndices;

            /// <summary>
            /// Initializes a new instance of the <see cref="ResolvedDependencyGraphItem" /> class.
            /// </summary>
            /// <param name="item">The <see cref="GraphItem{TItem}" /> with a <see cref="RemoteResolveResult" /> of the resolved library.</param>
            /// <param name="dependencyGraphItem">The <see cref="DependencyGraphItem" /> that is being resolved.</param>
            /// <param name="indexingTable">The <see cref="DependencyGraphItemIndexer" /> to use when indexing dependencies.</param>
            /// <param name="parents">An optional <see cref="HashSet{T}" /> containing parent <see cref="LibraryRangeIndex" /> values.</param>
            public ResolvedDependencyGraphItem(
                GraphItem<RemoteResolveResult> item,
                DependencyGraphItem dependencyGraphItem,
                DependencyGraphItemIndexer indexingTable,
                HashSet<LibraryRangeIndex>? parents = null)
            {
                Item = item;

                LibraryDependency = dependencyGraphItem.LibraryDependency;
                LibraryRangeIndex = dependencyGraphItem.LibraryRangeIndex;
                Path = dependencyGraphItem.Path;

                if (parents != null)
                {
                    Parents = parents;
                }
                else if (dependencyGraphItem.IsCentrallyPinnedTransitivePackage && !dependencyGraphItem.IsRootPackageReference)
                {
                    // Keep track of parents if the item is transitively pinned
                    Parents = new HashSet<LibraryRangeIndex> { dependencyGraphItem.Parent };
                }

                int dependencyCount = item.Data.Dependencies.Count;

                if (dependencyCount == 0)
                {
                    _dependencyIndices = Array.Empty<LibraryDependencyIndex>();
                    _rangeIndices = Array.Empty<LibraryRangeIndex>();
                }
                else
                {
                    // Index all of the dependencies ahead of time so that later on the value can be retrieved very quickly
                    _dependencyIndices = new LibraryDependencyIndex[dependencyCount];
                    _rangeIndices = new LibraryRangeIndex[dependencyCount];

                    for (int i = 0; i < dependencyCount; i++)
                    {
                        LibraryDependency dependency = item.Data.Dependencies[i];

                        _dependencyIndices[i] = indexingTable.Index(dependency);
                        _rangeIndices[i] = indexingTable.Index(dependency.LibraryRange);
                    }
                }
            }

            /// <summary>
            /// Gets or sets a value indicating whether or not the dependency graph item is transitively pinned.
            /// </summary>
            public bool IsCentrallyPinnedTransitivePackage { get; init; }

            /// <summary>
            /// Gets or sets a value indicating whether or not the dependency graph item is a direct package reference.
            /// </summary>
            public bool IsRootPackageReference { get; init; }

            /// <summary>
            /// Gets the <see cref="GraphItem{TItem}" /> with a <see cref="RemoteResolveResult" /> of the resolved library.
            /// </summary>
            public GraphItem<RemoteResolveResult> Item { get; }

            /// <summary>
            /// Gets the <see cref="LibraryDependency" /> of the declared dependency in the graph.
            /// </summary>
            public LibraryDependency LibraryDependency { get; }

            /// <summary>
            /// Gets the <see cref="LibraryRangeIndex" /> of this dependency graph item.
            /// </summary>
            public LibraryRangeIndex LibraryRangeIndex { get; }

            /// <summary>
            /// Gets or sets a <see cref="HashSet{T}" /> of parent <see cref="LibraryRangeIndex" /> that have been eclipsed by this dependency graph item.
            /// </summary>
            public HashSet<LibraryRangeIndex>? ParentPathsThatHaveBeenEclipsed { get; set; }

            /// <summary>
            /// Gets or sets a <see cref="HashSet{T}" /> of all of the parent <see cref="LibraryRangeIndex" /> of this dependency graph item.
            /// </summary>
            public HashSet<LibraryRangeIndex>? Parents { get; }

            /// <summary>
            /// Gets an array containing the <see cref="LibraryRangeIndex" /> values of all parent dependency graph items and their parent up to the root.
            /// </summary>
            public LibraryRangeIndex[] Path { get; }

            /// <summary>
            /// Gets or sets a <see cref="List{T}" /> of <see cref="HashSet{T}" /> containing <see cref="LibraryDependencyIndex" /> representing dependencies that should be suppressed under this item.
            /// </summary>
            public required List<HashSet<LibraryDependencyIndex>> Suppressions { get; init; }

            /// <summary>
            /// Gets the <see cref="LibraryDependencyIndex" /> of the dependency at the specified position.
            /// </summary>
            /// <param name="position">The position of the dependency to get the <see cref="LibraryDependencyIndex" /> of.</param>
            /// <returns>The <see cref="LibraryDependencyIndex" /> of the dependency at the specified position.</returns>
            public LibraryDependencyIndex GetDependencyIndexForDependencyAt(int position)
            {
                return _dependencyIndices[position];
            }

            /// <summary>
            /// Gets the <see cref="LibraryRangeIndex" /> of the dependency at the specified position.
            /// </summary>
            /// <param name="position">The position of the dependency to get the <see cref="LibraryRangeIndex" /> of.</param>
            /// <returns>The <see cref="LibraryRangeIndex" /> of the dependency at the specified position.</returns>
            public LibraryRangeIndex GetRangeIndexForDependencyAt(int position)
            {
                return _rangeIndices[position];
            }

            /// <summary>
            /// Sets the <see cref="LibraryRangeIndex" /> of the dependency at the specified position.
            /// </summary>
            /// <param name="position">The position of the dependency to set the <see cref="LibraryRangeIndex" /> of.</param>
            /// <param name="libraryRangeIndex">The new <see cref="LibraryRangeIndex" /> to set.</param>
            public void SetRangeIndexForDependencyAt(int position, LibraryRangeIndex libraryRangeIndex)
            {
                _rangeIndices[position] = libraryRangeIndex;
            }
        }
    }
}