Browse Source

#nullable enable for UniversalAssemblyResolver

pull/2423/head
Daniel Grunwald 5 years ago
parent
commit
7f36cc3e50
  1. 3
      ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
  2. 91
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  3. 11
      ICSharpCode.Decompiler/Util/NullAttributes.cs
  4. 1
      ILSpy.AddIn/ILSpy.AddIn.csproj

3
ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs

@ -19,6 +19,7 @@
#nullable enable #nullable enable
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Metadata; using System.Reflection.Metadata;
@ -81,7 +82,7 @@ namespace ICSharpCode.Decompiler.Metadata
/// For .NET Core framework references, the WholeProjectDecompiler will omit the /// For .NET Core framework references, the WholeProjectDecompiler will omit the
/// assembly reference if the runtimePack is already included as an SDK. /// assembly reference if the runtimePack is already included as an SDK.
/// </summary> /// </summary>
public virtual bool IsSharedAssembly(IAssemblyReference reference, out string? runtimePack) public virtual bool IsSharedAssembly(IAssemblyReference reference, [NotNullWhen(true)] out string? runtimePack)
{ {
runtimePack = null; runtimePack = null;
return false; return false;

91
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -16,8 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
@ -64,13 +67,13 @@ namespace ICSharpCode.Decompiler.Metadata
readonly bool throwOnError; readonly bool throwOnError;
readonly PEStreamOptions streamOptions; readonly PEStreamOptions streamOptions;
readonly MetadataReaderOptions metadataOptions; readonly MetadataReaderOptions metadataOptions;
readonly string mainAssemblyFileName; readonly string? mainAssemblyFileName;
readonly string baseDirectory; readonly string? baseDirectory;
readonly List<string> directories = new List<string>(); readonly List<string?> directories = new List<string?>();
static readonly List<string> gac_paths = GetGacPaths(); static readonly List<string> gac_paths = GetGacPaths();
static readonly DecompilerRuntime decompilerRuntime; static readonly DecompilerRuntime decompilerRuntime;
public void AddSearchDirectory(string directory) public void AddSearchDirectory(string? directory)
{ {
directories.Add(directory); directories.Add(directory);
if (dotNetCorePathFinder.IsValueCreated) if (dotNetCorePathFinder.IsValueCreated)
@ -79,7 +82,7 @@ namespace ICSharpCode.Decompiler.Metadata
} }
} }
public void RemoveSearchDirectory(string directory) public void RemoveSearchDirectory(string? directory)
{ {
directories.Remove(directory); directories.Remove(directory);
if (dotNetCorePathFinder.IsValueCreated) if (dotNetCorePathFinder.IsValueCreated)
@ -88,7 +91,7 @@ namespace ICSharpCode.Decompiler.Metadata
} }
} }
public string[] GetSearchDirectories() public string?[] GetSearchDirectories()
{ {
return directories.ToArray(); return directories.ToArray();
} }
@ -121,8 +124,8 @@ namespace ICSharpCode.Decompiler.Metadata
/// If omitted, falling back to "Microsoft.NETCore.App" and this is ignored in case of classic .NET</param> /// If omitted, falling back to "Microsoft.NETCore.App" and this is ignored in case of classic .NET</param>
/// <param name="streamOptions">Options used for the <see cref="PEReader"/>.</param> /// <param name="streamOptions">Options used for the <see cref="PEReader"/>.</param>
/// <param name="metadataOptions">Options used for the <see cref="MetadataReader"/>.</param> /// <param name="metadataOptions">Options used for the <see cref="MetadataReader"/>.</param>
public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework, public UniversalAssemblyResolver(string? mainAssemblyFileName, bool throwOnError, string? targetFramework,
string runtimePack = null, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) string? runtimePack = null, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default)
{ {
this.mainAssemblyFileName = mainAssemblyFileName; this.mainAssemblyFileName = mainAssemblyFileName;
this.throwOnError = throwOnError; this.throwOnError = throwOnError;
@ -162,7 +165,7 @@ namespace ICSharpCode.Decompiler.Metadata
break; break;
} }
Version version = null; Version? version = null;
for (int i = 1; i < tokens.Length; i++) for (int i = 1; i < tokens.Length; i++)
{ {
@ -191,20 +194,20 @@ namespace ICSharpCode.Decompiler.Metadata
} }
#if !VSADDIN #if !VSADDIN
public PEFile Resolve(IAssemblyReference name) public PEFile? Resolve(IAssemblyReference name)
{ {
var file = FindAssemblyFile(name); var file = FindAssemblyFile(name);
return CreatePEFileFromFileName(file, ex => new ResolutionException(name, file, ex)); return CreatePEFileFromFileName(file, ex => new ResolutionException(name, file, ex));
} }
public PEFile ResolveModule(PEFile mainModule, string moduleName) public PEFile? ResolveModule(PEFile mainModule, string moduleName)
{ {
string baseDirectory = Path.GetDirectoryName(mainModule.FileName); string baseDirectory = Path.GetDirectoryName(mainModule.FileName);
string moduleFileName = Path.Combine(baseDirectory, moduleName); string moduleFileName = Path.Combine(baseDirectory, moduleName);
return CreatePEFileFromFileName(moduleFileName, ex => new ResolutionException(mainModule.FileName, moduleName, moduleFileName, ex)); return CreatePEFileFromFileName(moduleFileName, ex => new ResolutionException(mainModule.FileName, moduleName, moduleFileName, ex));
} }
private PEFile CreatePEFileFromFileName(string fileName, Func<Exception?, Exception> makeException) private PEFile? CreatePEFileFromFileName(string? fileName, Func<Exception?, Exception> makeException)
{ {
if (fileName == null) if (fileName == null)
{ {
@ -231,30 +234,30 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
public Task<PEFile> ResolveAsync(IAssemblyReference name) public Task<PEFile?> ResolveAsync(IAssemblyReference name)
{ {
return Task.Run(() => Resolve(name)); return Task.Run(() => Resolve(name));
} }
public Task<PEFile> ResolveModuleAsync(PEFile mainModule, string moduleName) public Task<PEFile?> ResolveModuleAsync(PEFile mainModule, string moduleName)
{ {
return Task.Run(() => ResolveModule(mainModule, moduleName)); return Task.Run(() => ResolveModule(mainModule, moduleName));
} }
#endif #endif
public override bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack) public override bool IsSharedAssembly(IAssemblyReference reference, [NotNullWhen(true)] out string? runtimePack)
{ {
return dotNetCorePathFinder.Value.TryResolveDotNetCoreShared(reference, out runtimePack) != null; return dotNetCorePathFinder.Value.TryResolveDotNetCoreShared(reference, out runtimePack) != null;
} }
public string FindAssemblyFile(IAssemblyReference name) public string? FindAssemblyFile(IAssemblyReference name)
{ {
if (name.IsWindowsRuntime) if (name.IsWindowsRuntime)
{ {
return FindWindowsMetadataFile(name); return FindWindowsMetadataFile(name);
} }
string file; string? file;
switch (targetFrameworkIdentifier) switch (targetFrameworkIdentifier)
{ {
case TargetFrameworkIdentifier.NETCoreApp: case TargetFrameworkIdentifier.NETCoreApp:
@ -291,14 +294,14 @@ namespace ICSharpCode.Decompiler.Metadata
return dotNetCorePathFinder; return dotNetCorePathFinder;
} }
string FindWindowsMetadataFile(IAssemblyReference name) string? FindWindowsMetadataFile(IAssemblyReference name)
{ {
// Finding Windows Metadata (winmd) is currently only supported on Windows. // Finding Windows Metadata (winmd) is currently only supported on Windows.
if (Environment.OSVersion.Platform != PlatformID.Win32NT) if (Environment.OSVersion.Platform != PlatformID.Win32NT)
return null; return null;
// TODO : Find a way to detect the base directory for the required Windows SDK. // TODO : Find a way to detect the base directory for the required Windows SDK.
string basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Kits", "10", "References"); string? basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Kits", "10", "References");
if (!Directory.Exists(basePath)) if (!Directory.Exists(basePath))
return FindWindowsMetadataInSystemDirectory(name); return FindWindowsMetadataInSystemDirectory(name);
@ -332,7 +335,7 @@ namespace ICSharpCode.Decompiler.Metadata
return file; return file;
} }
string FindWindowsMetadataInSystemDirectory(IAssemblyReference name) string? FindWindowsMetadataInSystemDirectory(IAssemblyReference name)
{ {
string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name.Name + ".winmd"); string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name.Name + ".winmd");
if (File.Exists(file)) if (File.Exists(file))
@ -343,7 +346,7 @@ namespace ICSharpCode.Decompiler.Metadata
/// <summary> /// <summary>
/// This only works on Windows /// This only works on Windows
/// </summary> /// </summary>
string ResolveSilverlight(IAssemblyReference name, Version version) string? ResolveSilverlight(IAssemblyReference name, Version? version)
{ {
string[] targetFrameworkSearchPaths = { string[] targetFrameworkSearchPaths = {
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Microsoft Silverlight"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Microsoft Silverlight"),
@ -362,19 +365,19 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
string FindClosestVersionDirectory(string basePath, Version version) string FindClosestVersionDirectory(string? basePath, Version? version)
{ {
string path = null; string? path = null;
foreach (var folder in new DirectoryInfo(basePath).GetDirectories().Select(d => DotNetCorePathFinder.ConvertToVersion(d.Name)) foreach (var folder in new DirectoryInfo(basePath).GetDirectories().Select(d => DotNetCorePathFinder.ConvertToVersion(d.Name))
.Where(v => v.Item1 != null).OrderByDescending(v => v.Item1)) .Where(v => v.Item1 != null).OrderByDescending(v => v.Item1))
{ {
if (path == null || folder.Item1 >= version) if (path == null || version == null || folder.Item1 >= version)
path = folder.Item2; path = folder.Item2;
} }
return path ?? version.ToString(); return path ?? version?.ToString() ?? ".";
} }
string ResolveInternal(IAssemblyReference name) string? ResolveInternal(IAssemblyReference name)
{ {
if (name == null) if (name == null)
throw new ArgumentNullException(nameof(name)); throw new ArgumentNullException(nameof(name));
@ -421,11 +424,11 @@ namespace ICSharpCode.Decompiler.Metadata
} }
#region .NET / mono GAC handling #region .NET / mono GAC handling
string SearchDirectory(IAssemblyReference name, IEnumerable<string> directories) string? SearchDirectory(IAssemblyReference name, IEnumerable<string?> directories)
{ {
foreach (var directory in directories) foreach (var directory in directories)
{ {
string file = SearchDirectory(name, directory); string? file = SearchDirectory(name, directory);
if (file != null) if (file != null)
return file; return file;
} }
@ -438,7 +441,7 @@ namespace ICSharpCode.Decompiler.Metadata
return IsZeroOrAllOnes(reference.Version) || reference.IsRetargetable; return IsZeroOrAllOnes(reference.Version) || reference.IsRetargetable;
} }
string SearchDirectory(IAssemblyReference name, string directory) string? SearchDirectory(IAssemblyReference name, string? directory)
{ {
var extensions = name.IsWindowsRuntime ? new[] { ".winmd", ".dll" } : new[] { ".dll", ".exe" }; var extensions = name.IsWindowsRuntime ? new[] { ".winmd", ".dll" } : new[] { ".dll", ".exe" };
foreach (var extension in extensions) foreach (var extension in extensions)
@ -458,7 +461,7 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
static bool IsZeroOrAllOnes(Version version) static bool IsZeroOrAllOnes(Version? version)
{ {
return version == null return version == null
|| (version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0) || (version.Major == 0 && version.Minor == 0 && version.Build == 0 && version.Revision == 0)
@ -467,7 +470,7 @@ namespace ICSharpCode.Decompiler.Metadata
internal static Version ZeroVersion = new Version(0, 0, 0, 0); internal static Version ZeroVersion = new Version(0, 0, 0, 0);
string GetCorlib(IAssemblyReference reference) string? GetCorlib(IAssemblyReference reference)
{ {
var version = reference.Version; var version = reference.Version;
var corlib = typeof(object).Assembly.GetName(); var corlib = typeof(object).Assembly.GetName();
@ -481,15 +484,19 @@ namespace ICSharpCode.Decompiler.Metadata
if (reference.PublicKeyToken == null) if (reference.PublicKeyToken == null)
return null; return null;
string path; string? path;
if (decompilerRuntime == DecompilerRuntime.Mono) if (decompilerRuntime == DecompilerRuntime.Mono)
{ {
path = GetMonoMscorlibBasePath(version); path = GetMonoMscorlibBasePath(version);
} }
else else if (version != null)
{ {
path = GetMscorlibBasePath(version, reference.PublicKeyToken.ToHexString(8)); path = GetMscorlibBasePath(version, reference.PublicKeyToken.ToHexString(8));
} }
else
{
path = null;
}
if (path == null) if (path == null)
return null; return null;
@ -501,9 +508,9 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
string GetMscorlibBasePath(Version version, string publicKeyToken) string? GetMscorlibBasePath(Version version, string? publicKeyToken)
{ {
string GetSubFolderForVersion() string? GetSubFolderForVersion()
{ {
switch (version.Major) switch (version.Major)
{ {
@ -540,7 +547,7 @@ namespace ICSharpCode.Decompiler.Metadata
Path.Combine(rootPath, "Framework64") Path.Combine(rootPath, "Framework64")
}; };
string folder = GetSubFolderForVersion(); string? folder = GetSubFolderForVersion();
if (folder != null) if (folder != null)
{ {
@ -558,7 +565,7 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
string GetMonoMscorlibBasePath(Version version) string? GetMonoMscorlibBasePath(Version? version)
{ {
var path = Directory.GetParent(typeof(object).Module.FullyQualifiedName).Parent.FullName; var path = Directory.GetParent(typeof(object).Module.FullyQualifiedName).Parent.FullName;
if (version.Major == 1) if (version.Major == 1)
@ -614,7 +621,7 @@ namespace ICSharpCode.Decompiler.Metadata
continue; continue;
var gac_path = Path.Combine(Path.Combine(Path.Combine(prefix, "lib"), "mono"), "gac"); var gac_path = Path.Combine(Path.Combine(Path.Combine(prefix, "lib"), "mono"), "gac");
if (Directory.Exists(gac_path) && !paths.Contains(gac)) if (Directory.Exists(gac_path) && !paths.Contains(gac_path))
paths.Add(gac_path); paths.Add(gac_path);
} }
@ -629,7 +636,7 @@ namespace ICSharpCode.Decompiler.Metadata
"gac"); "gac");
} }
public static string GetAssemblyInGac(IAssemblyReference reference) public static string? GetAssemblyInGac(IAssemblyReference reference)
{ {
if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0) if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
return null; return null;
@ -640,7 +647,7 @@ namespace ICSharpCode.Decompiler.Metadata
return GetAssemblyInNetGac(reference); return GetAssemblyInNetGac(reference);
} }
static string GetAssemblyInMonoGac(IAssemblyReference reference) static string? GetAssemblyInMonoGac(IAssemblyReference reference)
{ {
for (int i = 0; i < gac_paths.Count; i++) for (int i = 0; i < gac_paths.Count; i++)
{ {
@ -653,7 +660,7 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
static string GetAssemblyInNetGac(IAssemblyReference reference) static string? GetAssemblyInNetGac(IAssemblyReference reference)
{ {
var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" }; var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
var prefixes = new[] { string.Empty, "v4.0_" }; var prefixes = new[] { string.Empty, "v4.0_" };
@ -672,7 +679,7 @@ namespace ICSharpCode.Decompiler.Metadata
return null; return null;
} }
static string GetAssemblyFile(IAssemblyReference reference, string prefix, string gac) static string GetAssemblyFile(IAssemblyReference reference, string? prefix, string? gac)
{ {
var gac_folder = new StringBuilder() var gac_folder = new StringBuilder()
.Append(prefix) .Append(prefix)

11
ICSharpCode.Decompiler/Util/NullAttributes.cs

@ -14,5 +14,16 @@ namespace System.Diagnostics.CodeAnalysis
ParameterName = parameterName; ParameterName = parameterName;
} }
} }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class NotNullWhenAttribute : Attribute
{
public NotNullWhenAttribute(bool returnValue)
{
ReturnValue = returnValue;
}
public bool ReturnValue { get; }
}
} }
#endif #endif

1
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -72,6 +72,7 @@
<Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Util\NullAttributes.cs" Link="NullAttributes.cs" />
<Compile Include="..\ILSpy\NativeMethods.cs" Link="NativeMethods.cs" /> <Compile Include="..\ILSpy\NativeMethods.cs" Link="NativeMethods.cs" />
<Compile Include="Commands\AssemblyReferenceForILSpy.cs" /> <Compile Include="Commands\AssemblyReferenceForILSpy.cs" />
<Compile Include="Commands\NuGetReferenceForILSpy.cs" /> <Compile Include="Commands\NuGetReferenceForILSpy.cs" />

Loading…
Cancel
Save