#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

171 lines
5.5 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using ICSharpCode.SharpDevelop.Parser;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// Description of DecompilerService.
/// </summary>
public static class ILSpyDecompilerService
{
class ILSpyAssemblyResolver : DefaultAssemblySearcher, IAssemblyResolver
{
public ILSpyAssemblyResolver(FileName fileName)
: base(fileName)
{
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return Resolve(name, new ReaderParameters());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
var file = FindAssembly(new DomAssemblyName(name.FullName));
if (file == null) return null;
return AssemblyDefinition.ReadAssembly(file, parameters);
}
public AssemblyDefinition Resolve(string fullName)
{
return Resolve(fullName, new ReaderParameters());
}
public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
{
var file = FindAssembly(new DomAssemblyName(fullName));
if (file == null) return null;
return AssemblyDefinition.ReadAssembly(file, parameters);
}
}
public static ILSpyUnresolvedFile DecompileType(DecompiledTypeReference name)
{
if (name == null)
throw new ArgumentNullException("entity");
return DoDecompile(name);
}
public static async Task<ILSpyUnresolvedFile> DecompileTypeAsync(DecompiledTypeReference name, CancellationToken cancellationToken)
{
return await Task.Run(
delegate() { return DoDecompile(name, cancellationToken); },
cancellationToken);
}
static AstBuilder CreateAstBuilder(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions
// can be garbage-collected once the code is decompiled.
readerParameters.AssemblyResolver = new ILSpyAssemblyResolver(name.AssemblyFile);
ModuleDefinition module = ModuleDefinition.ReadModule(name.AssemblyFile, readerParameters);
TypeDefinition typeDefinition = module.GetType(name.Type.ReflectionName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
DecompilerContext context = new DecompilerContext(module);
context.CancellationToken = cancellationToken;
AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(typeDefinition);
return astBuilder;
}
static ILSpyUnresolvedFile DoDecompile(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
return ILSpyUnresolvedFile.Create(name, CreateAstBuilder(name, cancellationToken));
}
public static ILSpyFullParseInformation ParseDecompiledType(DecompiledTypeReference name, CancellationToken cancellationToken = default(CancellationToken))
{
var astBuilder = CreateAstBuilder(name, cancellationToken);
return new ILSpyFullParseInformation(ILSpyUnresolvedFile.Create(name, astBuilder), null, astBuilder.SyntaxTree);
}
}
public class DecompiledTypeReference : IEquatable<DecompiledTypeReference>
{
public FileName AssemblyFile { get; private set; }
public FullTypeName Type { get; private set; }
public DecompiledTypeReference(FileName assemblyFile, FullTypeName type)
{
this.AssemblyFile = assemblyFile;
this.Type = type;
}
public FileName ToFileName()
{
return FileName.Create("ilspy://" + AssemblyFile + "/" + Type.ReflectionName + ".cs");
}
static readonly Regex nameRegex = new Regex(@"^ilspy\://(.+)/(.+)\.cs$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static DecompiledTypeReference FromFileName(string filename)
{
var match = nameRegex.Match(filename);
if (!match.Success) return null;
string asm, typeName;
asm = match.Groups[1].Value;
typeName = match.Groups[2].Value;
return new DecompiledTypeReference(new FileName(asm), new FullTypeName(typeName));
}
#region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
DecompiledTypeReference other = (DecompiledTypeReference)obj;
if (other == null)
return false;
return Equals(other);
}
public bool Equals(DecompiledTypeReference other)
{
return object.Equals(this.AssemblyFile, other.AssemblyFile) && this.Type == other.Type;
}
public override int GetHashCode()
{
int hashCode = 0;
unchecked {
if (AssemblyFile != null)
hashCode += 1000000007 * AssemblyFile.GetHashCode();
hashCode += 1000000009 * Type.GetHashCode();
}
return hashCode;
}
public static bool operator ==(DecompiledTypeReference lhs, DecompiledTypeReference rhs) {
if (ReferenceEquals(lhs, rhs))
return true;
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
return false;
return lhs.Equals(rhs);
}
public static bool operator !=(DecompiledTypeReference lhs, DecompiledTypeReference rhs) {
return !(lhs == rhs);
}
#endregion
}
}