Merge pull request #14957 from tamasvajk/standalone/prefer-framework-assemblies

C#: Prefer framework assemblies over arbitrary nuget equivalents
This commit is contained in:
Tamás Vajk
2023-12-04 11:03:03 +01:00
committed by GitHub
3 changed files with 54 additions and 26 deletions

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,7 +19,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// assembly cache.
/// </param>
/// <param name="progressMonitor">Callback for progress.</param>
public AssemblyCache(IEnumerable<string> paths, ProgressMonitor progressMonitor)
public AssemblyCache(IEnumerable<string> paths, IEnumerable<string> frameworkPaths, ProgressMonitor progressMonitor)
{
foreach (var path in paths)
{
@@ -40,7 +39,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
progressMonitor.LogInfo("AssemblyCache: Path not found: " + path);
}
}
IndexReferences();
IndexReferences(frameworkPaths);
}
/// <summary>
@@ -57,13 +56,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private static readonly Version emptyVersion = new Version(0, 0, 0, 0);
/// <summary>
/// Indexes all DLLs we have located.
/// Because this is a potentially time-consuming operation, it is put into a separate stage.
/// </summary>
private void IndexReferences()
private void IndexReferences(IEnumerable<string> frameworkPaths)
{
// Read all of the files
foreach (var filename in pendingDllsToIndex)
@@ -71,13 +68,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
IndexReference(filename);
}
// Index "assemblyInfo" by version string
// The OrderBy is used to ensure that we by default select the highest version number.
foreach (var info in assemblyInfoByFileName.Values
.OrderBy(info => info.Name)
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
.ThenBy(info => info.Version ?? emptyVersion)
.ThenBy(info => info.Filename))
.OrderAssemblyInfosByPreference(frameworkPaths))
{
foreach (var index in info.IndexStrings)
{

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
internal static class AssemblyCacheExtensions
{
private static readonly Version emptyVersion = new Version(0, 0, 0, 0);
/// <summary>
/// This method orders AssemblyInfos by version numbers (.net core version first, then assembly version). Finally, it orders by filename to make the order deterministic.
/// </summary>
public static IOrderedEnumerable<AssemblyInfo> OrderAssemblyInfosByPreference(this IEnumerable<AssemblyInfo> assemblies, IEnumerable<string> frameworkPaths)
{
// prefer framework assemblies over others
int initialOrdering(AssemblyInfo info) => frameworkPaths.Any(framework => info.Filename.StartsWith(framework, StringComparison.OrdinalIgnoreCase)) ? 1 : 0;
var ordered = assemblies is IOrderedEnumerable<AssemblyInfo> o
? o.ThenBy(initialOrdering)
: assemblies.OrderBy(initialOrdering);
return ordered
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
.ThenBy(info => info.Version ?? emptyVersion)
.ThenBy(info => info.Filename);
}
}
}

View File

@@ -128,16 +128,18 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
DownloadMissingPackages(allNonBinaryFiles, dllPaths);
}
var frameworkLocations = new HashSet<string>();
// Find DLLs in the .Net / Asp.Net Framework
// This block needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
if (options.ScanNetFrameworkDlls)
{
AddNetFrameworkDlls(dllPaths);
AddAspNetCoreFrameworkDlls(dllPaths);
AddMicrosoftWindowsDesktopDlls(dllPaths);
AddNetFrameworkDlls(dllPaths, frameworkLocations);
AddAspNetCoreFrameworkDlls(dllPaths, frameworkLocations);
AddMicrosoftWindowsDesktopDlls(dllPaths, frameworkLocations);
}
assemblyCache = new AssemblyCache(dllPaths, progressMonitor);
assemblyCache = new AssemblyCache(dllPaths, frameworkLocations, progressMonitor);
AnalyseSolutions(solutions);
foreach (var filename in assemblyCache.AllAssemblies.Select(a => a.Filename))
@@ -146,7 +148,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
RemoveNugetAnalyzerReferences();
ResolveConflicts();
ResolveConflicts(frameworkLocations);
// Output the findings
foreach (var r in usedReferences.Keys.OrderBy(r => r))
@@ -228,7 +230,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private void AddNetFrameworkDlls(ISet<string> dllPaths)
private void AddNetFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
{
// Multiple dotnet framework packages could be present.
// The order of the packages is important, we're adding the first one that is present in the nuget cache.
@@ -241,6 +243,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (frameworkPath.Path is not null)
{
dllPaths.Add(frameworkPath.Path);
frameworkLocations.Add(frameworkPath.Path);
progressMonitor.LogInfo($"Found .NET Core/Framework DLLs in NuGet packages at {frameworkPath.Path}. Not adding installation directory.");
for (var i = frameworkPath.Index + 1; i < packagesInPrioOrder.Length; i++)
@@ -270,6 +273,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
progressMonitor.LogInfo($".NET runtime location selected: {runtimeLocation}");
dllPaths.Add(runtimeLocation);
frameworkLocations.Add(runtimeLocation);
}
private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllPaths)
@@ -294,7 +298,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths)
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
{
if (!fileContent.IsNewProjectStructureUsed || !fileContent.UseAspNetCoreDlls)
{
@@ -306,20 +310,25 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{
progressMonitor.LogInfo($"Found ASP.NET Core in NuGet packages. Not adding installation directory.");
dllPaths.Add(aspNetCorePackage);
frameworkLocations.Add(aspNetCorePackage);
return;
}
else if (Runtime.AspNetCoreRuntime is string aspNetCoreRuntime)
if (Runtime.AspNetCoreRuntime is string aspNetCoreRuntime)
{
progressMonitor.LogInfo($"ASP.NET runtime location selected: {aspNetCoreRuntime}");
dllPaths.Add(aspNetCoreRuntime);
frameworkLocations.Add(aspNetCoreRuntime);
}
}
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths)
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
{
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework) is string windowsDesktopApp)
{
progressMonitor.LogInfo($"Found Windows Desktop App in NuGet packages.");
dllPaths.Add(windowsDesktopApp);
frameworkLocations.Add(windowsDesktopApp);
}
}
@@ -472,7 +481,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// If the same assembly name is duplicated with different versions,
/// resolve to the higher version number.
/// </summary>
private void ResolveConflicts()
private void ResolveConflicts(IEnumerable<string> frameworkPaths)
{
var sortedReferences = new List<AssemblyInfo>();
foreach (var usedReference in usedReferences)
@@ -488,11 +497,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
}
var emptyVersion = new Version(0, 0);
sortedReferences = sortedReferences
.OrderBy(r => r.NetCoreVersion ?? emptyVersion)
.ThenBy(r => r.Version ?? emptyVersion)
.ThenBy(r => r.Filename)
.OrderAssemblyInfosByPreference(frameworkPaths)
.ToList();
var finalAssemblyList = new Dictionary<string, AssemblyInfo>();