Skip to content

Commit

Permalink
Add the Dotnet runtimes to the list of assemblies (#290)
Browse files Browse the repository at this point in the history
Co-authored-by: ElektroKill <[email protected]>
  • Loading branch information
QianMoXi and ElektroKill authored Mar 1, 2024
1 parent d028370 commit cc7533e
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
6 changes: 6 additions & 0 deletions dnSpy/dnSpy.Contracts.Logic/Utilities/DotNetPathProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ static FrameworkPaths[] CreateAndSortFrameworkPaths(IEnumerable<FrameworkPath> l
return array;
}

/// <summary>
/// Returns the .NET Core runtime assembly directories found on the system.
/// </summary>
/// <returns>.NET Core framework path info</returns>
public FrameworkPath[] GetSharedDotNetPaths() => netPathsShared.SelectMany(x => x.frameworkPaths).ToArray();

/// <summary>
/// Returns the .NET Core runtime assembly directories found on the system.
/// </summary>
Expand Down
53 changes: 51 additions & 2 deletions dnSpy/dnSpy.Contracts.Logic/Utilities/FrameworkPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ sealed class FrameworkPaths : IComparable<FrameworkPaths> {
public readonly FrameworkVersion Version;
public readonly Version SystemVersion;
public readonly bool IsReferencePath;
internal readonly FrameworkPath[] frameworkPaths;

string DebuggerPaths => string.Join(Path.PathSeparator.ToString(), Paths);

public FrameworkPaths(FrameworkPath[] paths, bool isRef) {
frameworkPaths = paths;
var firstPath = paths[0];
#if DEBUG
for (int i = 1; i < paths.Length; i++) {
Expand Down Expand Up @@ -122,39 +124,82 @@ public bool IsCompatibleWithNetStandard(Version netStandardVersion) {
}
}

/// <summary>
/// .NET Core path info
/// </summary>
// It's a class since very few of these are created
[DebuggerDisplay("{Bitness,d}-bit {Version,nq} {Path,nq}")]
sealed class FrameworkPath {
public sealed class FrameworkPath {
/// <summary>
/// .NET Core assembly directories
/// </summary>
public readonly string Path;
/// <summary>
/// Assembly bitness
/// </summary>
public readonly int Bitness;
/// <summary>
/// Assembly version
/// </summary>
public readonly FrameworkVersion Version;

/// <summary>
/// Constructor
/// </summary>
/// <param name="path">.NET Core assembly directories</param>
/// <param name="bitness">Assembly bitness</param>
/// <param name="version">Assembly version</param>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is null</exception>
public FrameworkPath(string path, int bitness, FrameworkVersion version) {
Path = path ?? throw new ArgumentNullException(nameof(path));
Bitness = bitness;
Version = version;
}
}

readonly struct FrameworkVersion : IComparable<FrameworkVersion>, IEquatable<FrameworkVersion> {
/// <summary>
/// .NET Core version info
/// </summary>
public readonly struct FrameworkVersion : IComparable<FrameworkVersion>, IEquatable<FrameworkVersion> {
/// <summary>
/// The major component
/// </summary>
public readonly int Major;
/// <summary>
/// The minor component
/// </summary>
public readonly int Minor;
/// <summary>
/// The patch component
/// </summary>
public readonly int Patch;
/// <summary>
/// The extra component
/// </summary>
public readonly string Extra;

/// <summary>
/// Constructor
/// </summary>
/// <param name="major">The major component</param>
/// <param name="minor">The minor component</param>
/// <param name="patch">The patch component</param>
/// <param name="extra">The extra component</param>
public FrameworkVersion(int major, int minor, int patch, string extra) {
Major = major;
Minor = minor;
Patch = patch;
Extra = extra;
}

/// <inheritdoc/>
public override string ToString() {
if (Extra.Length == 0)
return $"{Major}.{Minor}.{Patch}";
return $"{Major}.{Minor}.{Patch}-{Extra}";
}

/// <inheritdoc/>
public int CompareTo(FrameworkVersion other) {
int c = Major.CompareTo(other.Major);
if (c != 0)
Expand All @@ -178,13 +223,17 @@ static int CompareExtra(string a, string b) {
return StringComparer.Ordinal.Compare(a, b);
}

/// <inheritdoc/>
public bool Equals(FrameworkVersion other) =>
Major == other.Major &&
Minor == other.Minor &&
Patch == other.Patch &&
StringComparer.Ordinal.Equals(Extra, other.Extra);

/// <inheritdoc/>
public override bool Equals(object? obj) => obj is FrameworkVersion other && Equals(other);

/// <inheritdoc/>
public override int GetHashCode() => Major ^ Minor ^ Patch ^ StringComparer.Ordinal.GetHashCode(Extra ?? string.Empty);
}
}
62 changes: 62 additions & 0 deletions dnSpy/dnSpy/Documents/Tabs/DefaultDocumentList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ You should have received a copy of the GNU General Public License
using System.Xml.Linq;
using dnSpy.Contracts.App;
using dnSpy.Contracts.Documents;
using dnSpy.Contracts.Utilities;

namespace dnSpy.Documents.Tabs {
sealed class DefaultDocumentList {
Expand All @@ -48,6 +49,61 @@ public DefaultDocumentList(string name, IEnumerable<DsDocumentInfo> asmNames) {
public void Add(DsDocumentInfo file) => files.Add(file);
}

sealed class DotnetReferenceFileFinder {
readonly CancellationToken cancellationToken;
readonly List<DefaultDocumentList> allLists;

public DotnetReferenceFileFinder(CancellationToken cancellationToken) {
this.cancellationToken = cancellationToken;
allLists = new List<DefaultDocumentList>();
}

public IEnumerable<DefaultDocumentList> AllFiles => allLists.ToArray();

public void Find() {
cancellationToken.ThrowIfCancellationRequested();

var dotNetPathProvider = new DotNetPathProvider();

foreach (var frameworkPath in dotNetPathProvider.GetSharedDotNetPaths()) {
cancellationToken.ThrowIfCancellationRequested();
var appName = $"{Path.GetFileName(Path.GetDirectoryName(frameworkPath.Path))} {frameworkPath.Version} (x{frameworkPath.Bitness:d})";
allLists.Add(new DefaultDocumentList(appName, Directory.GetFiles(frameworkPath.Path, "*.dll").Where(FilterFiles).Select(DsDocumentInfo.CreateDocument)));
}
}

static bool FilterFiles(string file) {
var fileName = Path.GetFileName(file);

if (fileName.Length == 0)
return false;

// The official managed assemblies in .NET Core almost always start with uppercase characters, which makes it easy for quick filtering.
if (fileName[0] >= 'A' && fileName[0] <= 'Z') {
// Exclude native assemblies here
// Microsoft.NETCore.App
if (fileName.StartsWith("Microsoft.DiaSymReader.Native.", StringComparison.Ordinal))
return false;

// Microsoft.WindowsDesktop.App
if (fileName.StartsWith("D3DCompiler_", StringComparison.Ordinal) || fileName.Equals("PenImc_cor3") || fileName.Equals("PresentationNative_cor3"))
return false;

return true;
}
if (fileName[0] >= 'a' && fileName[0] <= 'z') {
// Include managed assemblies here
// Microsoft.NETCore.App
if (fileName.Equals("mscorlib") || fileName.Equals("netstandard"))
return true;

return false;
}

return true;
}
}

sealed class ReferenceFileFinder {
readonly CancellationToken cancellationToken;
readonly List<RefFileList> allFiles;
Expand Down Expand Up @@ -356,6 +412,9 @@ public DefaultDocumentList[] Find() {
var finder = new ReferenceFileFinder(cancellationToken);
finder.Find();

var dotnetFinder = new DotnetReferenceFileFinder(cancellationToken);
dotnetFinder.Find();

var xmlFiles = new List<(DefaultDocumentList list, bool isDefault)>();
foreach (var dir in FilesDirs) {
cancellationToken.ThrowIfCancellationRequested();
Expand All @@ -381,6 +440,9 @@ public DefaultDocumentList[] Find() {
foreach (var f in finder.AllFiles)
dict[f.Name] = f;

foreach (var f in dotnetFinder.AllFiles)
dict[f.Name] = f;

foreach (var t in xmlFiles) {
if (!t.isDefault) // if user file
dict[t.list.Name] = t.list;
Expand Down

0 comments on commit cc7533e

Please sign in to comment.