Skip to content

Commit 6299d9c

Browse files
committed
C#: Introduce AssemblyPath and re-factor AssemblyCache to use this instead of strings.
1 parent bee54e4 commit 6299d9c

File tree

3 files changed

+90
-44
lines changed

3 files changed

+90
-44
lines changed

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/AssemblyCache.cs

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,107 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34
using System.Linq;
45
using Semmle.Util.Logging;
56

67
namespace Semmle.Extraction.CSharp.DependencyFetching
78
{
89
/// <summary>
9-
/// Manages the set of assemblies.
10-
/// Searches for assembly DLLs, indexes them and provides
11-
/// a lookup facility from assembly ID to filename.
10+
/// Used to represent a path to an assembly or a directory containing assemblies
11+
/// and a selector function to determine which files to include, when indexing the assemblies.
1212
/// </summary>
13-
internal class AssemblyCache
13+
internal sealed class AssemblyPath(string p, Func<string, bool> includeFileName)
1414
{
15+
public string Path => p;
16+
17+
public AssemblyPath(string p) : this(p, _ => true) { }
18+
19+
public static implicit operator AssemblyPath(string path) => new(path);
20+
1521
/// <summary>
16-
/// Locate all reference files and index them.
22+
/// Finds all assemblies nested within the directory `path`
23+
/// and adds them to the a list of assembly names to index.
24+
/// Indexing is performed at a later stage. This only collects the names.
1725
/// </summary>
18-
/// <param name="paths">
19-
/// Paths to search. Directories are searched recursively. Files are added directly to the
20-
/// assembly cache.
21-
/// </param>
22-
/// <param name="logger">Callback for progress.</param>
23-
public AssemblyCache(IEnumerable<string> paths, IEnumerable<string> frameworkPaths, ILogger logger)
26+
/// <param name="dir">The directory to index.</param>
27+
private void AddReferenceDirectory(List<string> dllsToIndex, ILogger logger)
2428
{
25-
this.logger = logger;
26-
foreach (var path in paths)
29+
foreach (var dll in new DirectoryInfo(p).EnumerateFiles("*.dll", SearchOption.AllDirectories))
2730
{
28-
if (File.Exists(path))
31+
if (includeFileName(dll.Name))
2932
{
30-
dllsToIndex.Add(path);
31-
continue;
33+
dllsToIndex.Add(dll.FullName);
3234
}
35+
else
36+
{
37+
logger.LogInfo($"AssemblyPath: Skipping {dll.FullName}.");
38+
}
39+
}
40+
}
3341

34-
if (Directory.Exists(path))
42+
/// <summary>
43+
/// Finds all assemblies in `p` that should be indexed and adds them to
44+
/// the list of assembly names to index.
45+
/// </summary>
46+
/// <param name="dllsToIndex">List of assembly names to index.</param>
47+
/// <param name="logger">Logger</param>
48+
public void Process(List<string> dllsToIndex, ILogger logger)
49+
{
50+
if (File.Exists(p))
51+
{
52+
if (includeFileName(System.IO.Path.GetFileName(p)))
3553
{
36-
logger.LogInfo($"Finding reference DLLs in {path}...");
37-
AddReferenceDirectory(path);
54+
dllsToIndex.Add(p);
3855
}
3956
else
4057
{
41-
logger.LogInfo("AssemblyCache: Path not found: " + path);
58+
logger.LogInfo($"AssemblyPath: Skipping {p}.");
4259
}
60+
return;
61+
}
62+
63+
if (Directory.Exists(p))
64+
{
65+
logger.LogInfo($"AssemblyPath: Finding reference DLLs in {p}...");
66+
AddReferenceDirectory(dllsToIndex, logger);
67+
}
68+
else
69+
{
70+
logger.LogInfo("AssemblyCache: Path not found: " + p);
4371
}
44-
IndexReferences(frameworkPaths);
4572
}
4673

74+
public override bool Equals(object? obj) =>
75+
obj is AssemblyPath ap && p.Equals(ap.Path);
76+
77+
public override int GetHashCode() => p.GetHashCode();
78+
79+
public override string ToString() => p;
80+
}
81+
82+
/// <summary>
83+
/// Manages the set of assemblies.
84+
/// Searches for assembly DLLs, indexes them and provides
85+
/// a lookup facility from assembly ID to filename.
86+
/// </summary>
87+
internal class AssemblyCache
88+
{
4789
/// <summary>
48-
/// Finds all assemblies nested within a directory
49-
/// and adds them to its index.
50-
/// (Indexing is performed at a later stage by IndexReferences()).
90+
/// Locate all reference files and index them.
5191
/// </summary>
52-
/// <param name="dir">The directory to index.</param>
53-
private void AddReferenceDirectory(string dir)
92+
/// <param name="paths">
93+
/// Paths to search. Directories are searched recursively. Files are added directly to the
94+
/// assembly cache.
95+
/// </param>
96+
/// <param name="logger">Callback for progress.</param>
97+
public AssemblyCache(IEnumerable<AssemblyPath> paths, IEnumerable<string> frameworkPaths, ILogger logger)
5498
{
55-
foreach (var dll in new DirectoryInfo(dir).EnumerateFiles("*.dll", SearchOption.AllDirectories))
99+
this.logger = logger;
100+
foreach (var path in paths)
56101
{
57-
dllsToIndex.Add(dll.FullName);
102+
path.Process(dllsToIndex, logger);
58103
}
104+
IndexReferences(frameworkPaths);
59105
}
60106

61107
/// <summary>

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.Nuget.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
1212
{
1313
public sealed partial class DependencyManager
1414
{
15-
private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<string> allProjects, IEnumerable<string> allSolutions, HashSet<string> dllPaths)
15+
private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<string> allProjects, IEnumerable<string> allSolutions, HashSet<AssemblyPath> dllPaths)
1616
{
1717
try
1818
{
@@ -55,7 +55,7 @@ private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<
5555
}
5656

5757
nugetPackageDllPaths.ExceptWith(excludedPaths);
58-
dllPaths.UnionWith(nugetPackageDllPaths);
58+
dllPaths.UnionWith(nugetPackageDllPaths.Select(p => new AssemblyPath(p)));
5959
}
6060
catch (Exception exc)
6161
{
@@ -72,7 +72,7 @@ private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<
7272
.Paths
7373
.Select(d => Path.Combine(packageDirectory.DirInfo.FullName, d))
7474
.ToList();
75-
dllPaths.UnionWith(paths);
75+
dllPaths.UnionWith(paths.Select(p => new AssemblyPath(p)));
7676

7777
LogAllUnusedPackages(dependencies);
7878
DownloadMissingPackages(allNonBinaryFiles, dllPaths);
@@ -148,7 +148,7 @@ private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<strin
148148
CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
149149
}
150150

151-
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths, bool withNugetConfig = true)
151+
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<AssemblyPath> dllPaths, bool withNugetConfig = true)
152152
{
153153
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(packageDirectory.DirInfo);
154154
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public sealed partial class DependencyManager : IDisposable
4646
/// <summary>
4747
/// Performs C# dependency fetching.
4848
/// </summary>
49-
/// <param name="options">Dependency fetching options</param>
49+
/// <param name="srcDir">Path to directory containing source code.</param>
5050
/// <param name="logger">Logger for dependency fetching progress.</param>
5151
public DependencyManager(string srcDir, ILogger logger)
5252
{
@@ -91,7 +91,7 @@ public DependencyManager(string srcDir, ILogger logger)
9191
this.generatedSources = new();
9292
var allProjects = allNonBinaryFiles.SelectFileNamesByExtension(".csproj").ToList();
9393
var allSolutions = allNonBinaryFiles.SelectFileNamesByExtension(".sln").ToList();
94-
var dllPaths = allFiles.SelectFileNamesByExtension(".dll").ToHashSet();
94+
var dllPaths = allFiles.SelectFileNamesByExtension(".dll").Select<string, AssemblyPath>(x => x).ToHashSet();
9595

9696
logger.LogInfo($"Found {allFiles.Count} files, {nonGeneratedSources.Count} source files, {allProjects.Count} project files, {allSolutions.Count} solution files, {dllPaths.Count} DLLs.");
9797

@@ -192,7 +192,7 @@ void exitCallback(int ret, string msg, bool silent)
192192
]);
193193
}
194194

195-
private HashSet<string> AddFrameworkDlls(HashSet<string> dllPaths)
195+
private HashSet<string> AddFrameworkDlls(HashSet<AssemblyPath> dllPaths)
196196
{
197197
var frameworkLocations = new HashSet<string>();
198198

@@ -230,7 +230,7 @@ private HashSet<string> AddFrameworkDlls(HashSet<string> dllPaths)
230230
continue;
231231
}
232232

233-
dllPaths.UnionWith(dlls);
233+
dllPaths.UnionWith(dlls.Select<string, AssemblyPath>(x => x));
234234
frameworkLocations.UnionWith(dlls);
235235
}
236236
catch (Exception e)
@@ -284,7 +284,7 @@ private void RemoveNugetAnalyzerReferences()
284284
}
285285
}
286286

287-
private void SelectNewestFrameworkPath(string frameworkPath, string frameworkType, ISet<string> dllPaths, ISet<string> frameworkLocations)
287+
private void SelectNewestFrameworkPath(string frameworkPath, string frameworkType, ISet<AssemblyPath> dllPaths, ISet<string> frameworkLocations)
288288
{
289289
var versionFolders = GetPackageVersionSubDirectories(frameworkPath);
290290
if (versionFolders.Length > 1)
@@ -313,7 +313,7 @@ private static DirectoryInfo[] GetPackageVersionSubDirectories(string packagePat
313313
.ToArray();
314314
}
315315

316-
private void RemoveFrameworkNugetPackages(ISet<string> dllPaths, int fromIndex = 0)
316+
private void RemoveFrameworkNugetPackages(ISet<AssemblyPath> dllPaths, int fromIndex = 0)
317317
{
318318
var packagesInPrioOrder = FrameworkPackageNames.NetFrameworks;
319319
for (var i = fromIndex; i < packagesInPrioOrder.Length; i++)
@@ -322,7 +322,7 @@ private void RemoveFrameworkNugetPackages(ISet<string> dllPaths, int fromIndex =
322322
}
323323
}
324324

325-
private void AddNetFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
325+
private void AddNetFrameworkDlls(ISet<AssemblyPath> dllPaths, ISet<string> frameworkLocations)
326326
{
327327
// Multiple dotnet framework packages could be present.
328328
// The order of the packages is important, we're adding the first one that is present in the nuget cache.
@@ -375,7 +375,7 @@ private void AddNetFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLo
375375
frameworkLocations.Add(runtimeLocation);
376376
}
377377

378-
private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllPaths)
378+
private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyPath> dllPaths)
379379
{
380380
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
381381
if (packageFolder == null)
@@ -384,7 +384,7 @@ private void RemoveNugetPackageReference(string packagePrefix, ISet<string> dllP
384384
}
385385

386386
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
387-
var toRemove = dllPaths.Where(s => s.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
387+
var toRemove = dllPaths.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
388388
foreach (var path in toRemove)
389389
{
390390
dllPaths.Remove(path);
@@ -397,7 +397,7 @@ private bool IsAspNetCoreDetected()
397397
return fileContent.IsNewProjectStructureUsed && fileContent.UseAspNetCoreDlls;
398398
}
399399

400-
private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
400+
private void AddAspNetCoreFrameworkDlls(ISet<AssemblyPath> dllPaths, ISet<string> frameworkLocations)
401401
{
402402
if (!IsAspNetCoreDetected())
403403
{
@@ -419,7 +419,7 @@ private void AddAspNetCoreFrameworkDlls(ISet<string> dllPaths, ISet<string> fram
419419
}
420420
}
421421

422-
private void AddMicrosoftWindowsDesktopDlls(ISet<string> dllPaths, ISet<string> frameworkLocations)
422+
private void AddMicrosoftWindowsDesktopDlls(ISet<AssemblyPath> dllPaths, ISet<string> frameworkLocations)
423423
{
424424
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework, packageDirectory) is string windowsDesktopApp)
425425
{

0 commit comments

Comments
 (0)