|
|
@ -23,45 +23,46 @@ namespace ICSharpCode.ILSpyAddIn |
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public static class ILSpyDecompilerService |
|
|
|
public static class ILSpyDecompilerService |
|
|
|
{ |
|
|
|
{ |
|
|
|
class AssemblyCacheInfo |
|
|
|
class ModuleCacheInfo |
|
|
|
{ |
|
|
|
{ |
|
|
|
public readonly DateTime LastUpdateTime; |
|
|
|
public readonly DateTime LastUpdateTime; |
|
|
|
public readonly WeakReference<AssemblyDefinition> Assembly; |
|
|
|
public readonly WeakReference<ModuleDefinition> Module; |
|
|
|
|
|
|
|
|
|
|
|
public AssemblyCacheInfo(DateTime lastUpdateTime, AssemblyDefinition assembly) |
|
|
|
public ModuleCacheInfo(DateTime lastUpdateTime, ModuleDefinition assembly) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (assembly == null) |
|
|
|
if (assembly == null) |
|
|
|
throw new ArgumentNullException("assembly"); |
|
|
|
throw new ArgumentNullException("assembly"); |
|
|
|
this.LastUpdateTime = lastUpdateTime; |
|
|
|
this.LastUpdateTime = lastUpdateTime; |
|
|
|
this.Assembly = new WeakReference<AssemblyDefinition>(assembly); |
|
|
|
this.Module = new WeakReference<ModuleDefinition>(assembly); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static readonly Dictionary<FileName, AssemblyCacheInfo> assemblyCache = new Dictionary<FileName, AssemblyCacheInfo>(); |
|
|
|
static readonly Dictionary<FileName, ModuleCacheInfo> moduleCache = new Dictionary<FileName, ModuleCacheInfo>(); |
|
|
|
|
|
|
|
|
|
|
|
static AssemblyDefinition GetAssemblyDefinitionFromCache(FileName file, ReaderParameters parameters = null) |
|
|
|
static ModuleDefinition GetModuleDefinitionFromCache(FileName file) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (file == null) return null; |
|
|
|
if (file == null) return null; |
|
|
|
if (parameters == null) parameters = new ReaderParameters(); |
|
|
|
ReaderParameters parameters = new ReaderParameters(); |
|
|
|
|
|
|
|
var resolver = new ILSpyAssemblyResolver(file); |
|
|
|
var lastUpdateTime = File.GetLastWriteTimeUtc(file); |
|
|
|
var lastUpdateTime = File.GetLastWriteTimeUtc(file); |
|
|
|
lock (assemblyCache) { |
|
|
|
lock (moduleCache) { |
|
|
|
AssemblyCacheInfo info; |
|
|
|
ModuleCacheInfo info; |
|
|
|
AssemblyDefinition asm; |
|
|
|
ModuleDefinition module; |
|
|
|
if (!assemblyCache.TryGetValue(file, out info)) { |
|
|
|
if (!moduleCache.TryGetValue(file, out info)) { |
|
|
|
asm = AssemblyDefinition.ReadAssembly(file, parameters); |
|
|
|
module = ModuleDefinition.ReadModule(file, parameters); |
|
|
|
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm)); |
|
|
|
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module)); |
|
|
|
return asm; |
|
|
|
return module; |
|
|
|
} else if (info.LastUpdateTime < lastUpdateTime) { |
|
|
|
} else if (info.LastUpdateTime < lastUpdateTime) { |
|
|
|
assemblyCache.Remove(file); |
|
|
|
moduleCache.Remove(file); |
|
|
|
asm = AssemblyDefinition.ReadAssembly(file, parameters); |
|
|
|
module = ModuleDefinition.ReadModule(file, parameters); |
|
|
|
assemblyCache.Add(file, new AssemblyCacheInfo(lastUpdateTime, asm)); |
|
|
|
moduleCache.Add(file, new ModuleCacheInfo(lastUpdateTime, module)); |
|
|
|
return asm; |
|
|
|
return module; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (info.Assembly.TryGetTarget(out asm)) |
|
|
|
if (info.Module.TryGetTarget(out module)) |
|
|
|
return asm; |
|
|
|
return module; |
|
|
|
asm = AssemblyDefinition.ReadAssembly(file, parameters); |
|
|
|
module = ModuleDefinition.ReadModule(file, parameters); |
|
|
|
info.Assembly.SetTarget(asm); |
|
|
|
info.Module.SetTarget(module); |
|
|
|
return asm; |
|
|
|
return module; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -77,14 +78,19 @@ namespace ICSharpCode.ILSpyAddIn |
|
|
|
{ |
|
|
|
{ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Used to remember the referenced assemblies for the WeakReference cache policy.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
readonly ISet<AssemblyDefinition> resolvedAssemblies = new HashSet<AssemblyDefinition>(); |
|
|
|
readonly ISet<AssemblyDefinition> resolvedAssemblies = new HashSet<AssemblyDefinition>(); |
|
|
|
|
|
|
|
|
|
|
|
AssemblyDefinition Resolve(DomAssemblyName name, ReaderParameters parameters) |
|
|
|
AssemblyDefinition Resolve(DomAssemblyName name, ReaderParameters parameters) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var assemblyDefinition = GetAssemblyDefinitionFromCache(FindAssembly(name), parameters); |
|
|
|
var moduleDefinition = GetModuleDefinitionFromCache(FindAssembly(name)); |
|
|
|
if (assemblyDefinition != null) |
|
|
|
if (moduleDefinition != null) { |
|
|
|
resolvedAssemblies.Add(assemblyDefinition); |
|
|
|
resolvedAssemblies.Add(moduleDefinition.Assembly); |
|
|
|
return assemblyDefinition; |
|
|
|
return moduleDefinition.Assembly; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public AssemblyDefinition Resolve(AssemblyNameReference name) |
|
|
|
public AssemblyDefinition Resolve(AssemblyNameReference name) |
|
|
@ -111,7 +117,7 @@ namespace ICSharpCode.ILSpyAddIn |
|
|
|
public static ILSpyUnresolvedFile DecompileType(DecompiledTypeReference name) |
|
|
|
public static ILSpyUnresolvedFile DecompileType(DecompiledTypeReference name) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (name == null) |
|
|
|
if (name == null) |
|
|
|
throw new ArgumentNullException("entity"); |
|
|
|
throw new ArgumentNullException("name"); |
|
|
|
return DoDecompile(name); |
|
|
|
return DoDecompile(name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -122,17 +128,16 @@ namespace ICSharpCode.ILSpyAddIn |
|
|
|
cancellationToken); |
|
|
|
cancellationToken); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, out AssemblyDefinition[] neededAssemblies, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ReaderParameters readerParameters = new ReaderParameters(); |
|
|
|
ReaderParameters readerParameters = new ReaderParameters(); |
|
|
|
// Use new assembly resolver instance so that the AssemblyDefinitions
|
|
|
|
// Use new assembly resolver instance so that the AssemblyDefinitions
|
|
|
|
// can be garbage-collected once the code is decompiled.
|
|
|
|
// can be garbage-collected once the code is decompiled.
|
|
|
|
var resolver = new ILSpyAssemblyResolver(name.AssemblyFile); |
|
|
|
var resolver = new ILSpyAssemblyResolver(name.AssemblyFile); |
|
|
|
readerParameters.AssemblyResolver = resolver; |
|
|
|
readerParameters.AssemblyResolver = resolver; |
|
|
|
AssemblyDefinition asm = GetAssemblyDefinitionFromCache(name.AssemblyFile, readerParameters); |
|
|
|
ModuleDefinition module = GetModuleDefinitionFromCache(name.AssemblyFile); |
|
|
|
if (asm == null) |
|
|
|
if (module == null) |
|
|
|
throw new InvalidOperationException("Could not find assembly file"); |
|
|
|
throw new InvalidOperationException("Could not find assembly file"); |
|
|
|
ModuleDefinition module = asm.MainModule; |
|
|
|
|
|
|
|
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName); |
|
|
|
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName); |
|
|
|
if (typeDefinition == null) |
|
|
|
if (typeDefinition == null) |
|
|
|
throw new InvalidOperationException("Could not find type"); |
|
|
|
throw new InvalidOperationException("Could not find type"); |
|
|
@ -140,21 +145,18 @@ namespace ICSharpCode.ILSpyAddIn |
|
|
|
context.CancellationToken = cancellationToken; |
|
|
|
context.CancellationToken = cancellationToken; |
|
|
|
AstBuilder astBuilder = new AstBuilder(context); |
|
|
|
AstBuilder astBuilder = new AstBuilder(context); |
|
|
|
astBuilder.AddType(typeDefinition); |
|
|
|
astBuilder.AddType(typeDefinition); |
|
|
|
neededAssemblies = resolver.ResolvedAssemblies.ToArray(); |
|
|
|
|
|
|
|
return astBuilder; |
|
|
|
return astBuilder; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AssemblyDefinition[] assemblies; |
|
|
|
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, cancellationToken)); |
|
|
|
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, out assemblies, cancellationToken)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static ILSpyFullParseInformation ParseDecompiledType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
public static ILSpyFullParseInformation ParseDecompiledType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AssemblyDefinition[] assemblies; |
|
|
|
var astBuilder = CreateAstBuilder(name, cancellationToken); |
|
|
|
var astBuilder = CreateAstBuilder(name, out assemblies, cancellationToken); |
|
|
|
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree); |
|
|
|
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree, assemblies); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|