Skip to content

Commit 58c248e

Browse files
authored
Rework the NU1510 heuristic, only raise it when a package id can be completely removed from the project (#6469)
1 parent f61900e commit 58c248e

File tree

5 files changed

+1594
-1001
lines changed

5 files changed

+1594
-1001
lines changed

src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.DependencyGraphItem.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,8 @@ private static bool ShouldPrunePackage(
187187
return false;
188188
}
189189

190-
if (isRootProject)
190+
if (isRootProject) // Don't prune direct PRs
191191
{
192-
if (enablePruningWarnings && SdkAnalysisLevelMinimums.IsEnabled(
193-
projectRestoreMetadata.SdkAnalysisLevel,
194-
projectRestoreMetadata.UsingMicrosoftNETSdk,
195-
SdkAnalysisLevelMinimums.PruningWarnings))
196-
{
197-
logger.Log(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1510, string.Format(CultureInfo.CurrentCulture, Strings.Error_RestorePruningDirectPackageReference, dependency.Name),
198-
dependency.Name,
199-
targetGraphName));
200-
}
201-
202192
return false;
203193
}
204194

src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,7 @@ .. chosenResolvedItem.Suppressions
14141414

14151415
private static bool IsNewerThanNET10(NuGetFramework frameworkName)
14161416
{
1417-
if (frameworkName.Framework == FrameworkConstants.FrameworkIdentifiers.NetCoreApp)
1417+
if (StringComparer.OrdinalIgnoreCase.Equals(frameworkName.Framework, FrameworkConstants.FrameworkIdentifiers.NetCoreApp))
14181418
{
14191419
return frameworkName.Version.Major >= 10;
14201420
}

src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ public async Task<RestoreResult> ExecuteAsync(CancellationToken token)
239239
packagesLockFile,
240240
token);
241241

242+
AnalyzePruningResults(_request.Project, _logger);
243+
242244
var graphs = await GenerateRestoreGraphsAsync(telemetry, contextForProject, token);
243245

244246
bool auditRan = false;
@@ -758,6 +760,130 @@ private bool HasValidPlatformVersions()
758760
}
759761
}
760762

763+
internal static void AnalyzePruningResults(PackageSpec project, ILogger logger)
764+
{
765+
bool enablePruningWarnings =
766+
SdkAnalysisLevelMinimums.IsEnabled(
767+
project.RestoreMetadata.SdkAnalysisLevel,
768+
project.RestoreMetadata.UsingMicrosoftNETSdk,
769+
SdkAnalysisLevelMinimums.PruningWarnings) &&
770+
HasFrameworkNewerThanNET10(project);
771+
772+
if (!enablePruningWarnings)
773+
{
774+
return;
775+
}
776+
777+
Dictionary<string, List<string>> prunedDirectPackages = GetPrunableDirectPackages(project);
778+
779+
if (prunedDirectPackages != null)
780+
{
781+
RaiseNU1510WarningsIfNeeded(project, logger, prunedDirectPackages);
782+
}
783+
784+
static Dictionary<string, List<string>> GetPrunableDirectPackages(PackageSpec project)
785+
{
786+
Dictionary<string, List<string>> prunedDirectPackages = null;
787+
788+
// Calculate direct packages that are in the pruning range.
789+
foreach (TargetFrameworkInformation framework in project.TargetFrameworks)
790+
{
791+
if (framework.PackagesToPrune != null && framework.PackagesToPrune.Count > 0)
792+
{
793+
foreach (var dependency in framework.Dependencies)
794+
{
795+
if (framework.PackagesToPrune.TryGetValue(dependency.Name, out PrunePackageReference packageToPrune)
796+
&& dependency.LibraryRange.VersionRange.Satisfies(packageToPrune.VersionRange.MaxVersion!))
797+
{
798+
prunedDirectPackages ??= new(StringComparer.OrdinalIgnoreCase);
799+
if (!prunedDirectPackages.ContainsKey(dependency.Name))
800+
{
801+
prunedDirectPackages.Add(dependency.Name, [framework.TargetAlias]);
802+
}
803+
else
804+
{
805+
prunedDirectPackages[dependency.Name].Add(framework.TargetAlias);
806+
}
807+
}
808+
}
809+
}
810+
}
811+
812+
return prunedDirectPackages;
813+
}
814+
815+
static void RaiseNU1510WarningsIfNeeded(PackageSpec project, ILogger logger, Dictionary<string, List<string>> prunedDirectPackages)
816+
{
817+
Dictionary<string, string> aliasToTargetGraphName = null;
818+
foreach (var prunedPackage in prunedDirectPackages)
819+
{
820+
// Do not warn if the package exists in any framework.
821+
if (prunedPackage.Value.Count != project.TargetFrameworks.Count)
822+
{
823+
bool doesPackageRemain = false;
824+
foreach (var framework in project.TargetFrameworks)
825+
{
826+
if (!prunedPackage.Value.Contains(framework.TargetAlias))
827+
{
828+
if (ContainsPackage(prunedPackage, framework))
829+
{
830+
doesPackageRemain = true;
831+
break;
832+
}
833+
}
834+
}
835+
if (doesPackageRemain)
836+
{
837+
continue;
838+
}
839+
}
840+
841+
aliasToTargetGraphName ??= InitializeAliasToTargetGraphName(project);
842+
logger.Log(RestoreLogMessage.CreateWarning(
843+
NuGetLogCode.NU1510,
844+
string.Format(CultureInfo.CurrentCulture, Strings.Error_RestorePruningDirectPackageReference, prunedPackage.Key),
845+
prunedPackage.Key,
846+
prunedPackage.Value.Select(e => aliasToTargetGraphName[e]).ToArray()));
847+
}
848+
}
849+
850+
static bool HasFrameworkNewerThanNET10(PackageSpec project)
851+
{
852+
foreach (var framework in project.TargetFrameworks.NoAllocEnumerate())
853+
{
854+
if (StringComparer.OrdinalIgnoreCase.Equals(framework.FrameworkName.Framework, FrameworkConstants.FrameworkIdentifiers.NetCoreApp) &&
855+
framework.FrameworkName.Version.Major >= 10)
856+
{
857+
return true;
858+
}
859+
}
860+
return false;
861+
}
862+
863+
static Dictionary<string, string> InitializeAliasToTargetGraphName(PackageSpec project)
864+
{
865+
var aliasToTargetGraphName = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
866+
foreach (var framework in project.TargetFrameworks)
867+
{
868+
aliasToTargetGraphName.Add(framework.TargetAlias, FrameworkRuntimePair.GetTargetGraphName(framework.FrameworkName, runtimeIdentifier: null));
869+
}
870+
871+
return aliasToTargetGraphName;
872+
}
873+
874+
static bool ContainsPackage(KeyValuePair<string, List<string>> prunedPackage, TargetFrameworkInformation framework)
875+
{
876+
foreach (var dependency in framework.Dependencies.NoAllocEnumerate())
877+
{
878+
if (dependency.Name.Equals(prunedPackage.Key, StringComparison.OrdinalIgnoreCase))
879+
{
880+
return true;
881+
}
882+
}
883+
return false;
884+
}
885+
}
886+
761887
private async Task<bool> AreCentralVersionRequirementsSatisfiedAsync(RestoreRequest restoreRequest, int httpSourcesCount)
762888
{
763889
if (restoreRequest?.Project?.RestoreMetadata == null || !restoreRequest.Project.RestoreMetadata.CentralPackageVersionsEnabled)

0 commit comments

Comments
 (0)