Browse Source

Introduce using declarations in decompiled code.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
3211ccbf6a
  1. 5
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 148
      ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
  3. 2
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  4. 87
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  5. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  6. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

5
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -89,11 +89,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -89,11 +89,6 @@ namespace ICSharpCode.Decompiler.Ast
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
{
astCompileUnit.AddChild(
new UsingDeclaration {
Import = new SimpleType("System")
}, CompilationUnit.MemberRole);
ConvertCustomAttributes(astCompileUnit, assemblyDefinition, AttributeTarget.Assembly);
ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, AttributeTarget.Module);

148
ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs

@ -0,0 +1,148 @@ @@ -0,0 +1,148 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// ITypeResolveContext implementation that lazily loads types from Cecil.
/// </summary>
public class CecilTypeResolveContext : ISynchronizedTypeResolveContext, IProjectContent
{
readonly ModuleDefinition module;
readonly string[] namespaces;
readonly CecilLoader loader;
Dictionary<TypeDefinition, WeakReference> dict = new Dictionary<TypeDefinition, WeakReference>();
int countUntilNextCleanup = 4;
public CecilTypeResolveContext(ModuleDefinition module)
{
this.loader = new CecilLoader();
this.loader.IncludeInternalMembers = true;
this.module = module;
this.namespaces = module.Types.Select(t => t.Namespace).Distinct().ToArray();
List<IAttribute> assemblyAttributes = new List<IAttribute>();
foreach (var attr in module.Assembly.CustomAttributes) {
assemblyAttributes.Add(loader.ReadAttribute(attr));
}
this.AssemblyAttributes = assemblyAttributes.AsReadOnly();
}
ITypeDefinition GetClass(TypeDefinition cecilType)
{
lock (dict) {
WeakReference wr;
ITypeDefinition type;
if (dict.TryGetValue(cecilType, out wr)) {
type = (ITypeDefinition)wr.Target;
} else {
wr = null;
type = null;
}
if (type == null) {
type = loader.LoadType(cecilType, this);
}
if (wr == null) {
if (--countUntilNextCleanup <= 0)
CleanupDict();
wr = new WeakReference(type);
dict.Add(cecilType, wr);
} else {
wr.Target = type;
}
return type;
}
}
void CleanupDict()
{
List<TypeDefinition> deletedKeys = new List<TypeDefinition>();
foreach (var pair in dict) {
if (!pair.Value.IsAlive) {
deletedKeys.Add(pair.Key);
}
}
foreach (var key in deletedKeys) {
dict.Remove(key);
}
countUntilNextCleanup = dict.Count + 4;
}
public IList<IAttribute> AssemblyAttributes { get; private set; }
public ITypeDefinition GetClass(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer)
{
if (typeParameterCount > 0)
name = name + "`" + typeParameterCount.ToString();
if (nameComparer == StringComparer.Ordinal) {
TypeDefinition cecilType = module.GetType(nameSpace, name);
if (cecilType != null)
return GetClass(cecilType);
else
return null;
}
foreach (TypeDefinition cecilType in module.Types) {
if (nameComparer.Equals(name, cecilType.Name)
&& nameComparer.Equals(nameSpace, cecilType.Namespace)
&& cecilType.GenericParameters.Count == typeParameterCount)
{
return GetClass(cecilType);
}
}
return null;
}
public IEnumerable<ITypeDefinition> GetClasses()
{
foreach (TypeDefinition cecilType in module.Types) {
yield return GetClass(cecilType);
}
}
public IEnumerable<ITypeDefinition> GetClasses(string nameSpace, StringComparer nameComparer)
{
foreach (TypeDefinition cecilType in module.Types) {
if (nameComparer.Equals(nameSpace, cecilType.Namespace))
yield return GetClass(cecilType);
}
}
public IEnumerable<string> GetNamespaces()
{
return namespaces;
}
public string GetNamespace(string nameSpace, StringComparer nameComparer)
{
foreach (string ns in namespaces) {
if (nameComparer.Equals(ns, nameSpace))
return ns;
}
return null;
}
ICSharpCode.NRefactory.Utils.CacheManager ITypeResolveContext.CacheManager {
get {
// We don't support caching
return null;
}
}
ISynchronizedTypeResolveContext ITypeResolveContext.Synchronize()
{
// This class is logically immutable
return this;
}
void IDisposable.Dispose()
{
// exit from Synchronize() block
}
}
}

2
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
base.VisitBlockStatement(blockStatement, data);
foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>()) {
foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>().ToArray()) {
if (stmt.Variables.Count() != 1)
continue;
var variable = stmt.Variables.Single();

87
ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Introduces using declarations.
/// </summary>
public class IntroduceUsingDeclarations : DepthFirstAstVisitor<object, object>, IAstTransform
{
DecompilerContext context;
public IntroduceUsingDeclarations(DecompilerContext context)
{
this.context = context;
currentNamespace = context.CurrentType != null ? context.CurrentType.Namespace : string.Empty;
}
public void Run(AstNode compilationUnit)
{
// Don't show using when decompiling a single method or nested types:
if (context.CurrentMethod != null || (context.CurrentType != null && context.CurrentType.IsNested))
return;
// First determine all the namespaces that need to be imported:
compilationUnit.AcceptVisitor(this, null);
importedNamespaces.Add("System"); // always import System, even when not necessary
// Now add using declarations for those namespaces:
foreach (string ns in importedNamespaces.OrderByDescending(n => n)) {
// we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards
// (always inserting at the start of the list)
string[] parts = ns.Split('.');
AstType nsType = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
nsType = new MemberType { Target = nsType, MemberName = parts[i] };
}
compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, CompilationUnit.MemberRole);
}
// TODO: verify that the SimpleTypes refer to the correct type (no ambiguities)
}
readonly HashSet<string> importedNamespaces = new HashSet<string>();
string currentNamespace;
bool IsParentOfCurrentNamespace(string ns)
{
if (ns.Length == 0)
return true;
if (currentNamespace.StartsWith(ns, StringComparison.Ordinal)) {
if (currentNamespace.Length == ns.Length)
return true;
if (currentNamespace[ns.Length] == '.')
return true;
}
return false;
}
public override object VisitSimpleType(SimpleType simpleType, object data)
{
TypeReference tr = simpleType.Annotation<TypeReference>();
if (tr != null && !IsParentOfCurrentNamespace(tr.Namespace)) {
importedNamespaces.Add(tr.Namespace);
}
return base.VisitSimpleType(simpleType, data); // also visit type arguments
}
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
{
string oldNamespace = currentNamespace;
foreach (Identifier ident in namespaceDeclaration.Identifiers) {
currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident.Name);
}
base.VisitNamespaceDeclaration(namespaceDeclaration, data);
currentNamespace = oldNamespace;
return null;
}
}
}

1
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -23,6 +23,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -23,6 +23,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
new IntroduceUsingDeclarations(context)
};
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -51,6 +51,7 @@ @@ -51,6 +51,7 @@
<ItemGroup>
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CecilTypeResolveContext.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DeclareVariableInSmallestScope.cs" />
<Compile Include="Ast\DecompilerContext.cs" />
@ -61,6 +62,7 @@ @@ -61,6 +62,7 @@
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="Ast\Transforms\IntroduceUsingDeclarations.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" />

Loading…
Cancel
Save