Browse Source

Fully qualify ambiguous type names.

pull/124/head
Daniel Grunwald 14 years ago
parent
commit
6cb77e63e9
  1. 2
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 8
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  3. 53
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  4. 2
      ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
  5. 2
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  6. 23
      ILSpy/CSharpLanguage.cs
  7. 2
      ILSpy/ILAstLanguage.cs

2
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast
public class AstBuilder public class AstBuilder
{ {
DecompilerContext context = new DecompilerContext(); DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit(); CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
bool transformationsHaveRun; bool transformationsHaveRun;

8
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -10,11 +10,19 @@ namespace ICSharpCode.Decompiler
{ {
public class DecompilerContext public class DecompilerContext
{ {
public ModuleDefinition CurrentModule;
public CancellationToken CancellationToken; public CancellationToken CancellationToken;
public TypeDefinition CurrentType; public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod; public MethodDefinition CurrentMethod;
public DecompilerSettings Settings = new DecompilerSettings(); public DecompilerSettings Settings = new DecompilerSettings();
public DecompilerContext(ModuleDefinition currentModule)
{
if (currentModule == null)
throw new ArgumentNullException("currentModule");
this.CurrentModule = currentModule;
}
/// <summary> /// <summary>
/// Used to pass variable names from a method to its anonymous methods. /// Used to pass variable names from a method to its anonymous methods.
/// </summary> /// </summary>

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

@ -44,10 +44,22 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, CompilationUnit.MemberRole); compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, CompilationUnit.MemberRole);
} }
// TODO: verify that the SimpleTypes refer to the correct type (no ambiguities) FindAmbiguousTypeNames(context.CurrentModule, internalsVisible: true);
foreach (AssemblyNameReference r in context.CurrentModule.AssemblyReferences) {
AssemblyDefinition d = context.CurrentModule.AssemblyResolver.Resolve(r);
if (d != null)
FindAmbiguousTypeNames(d.MainModule, internalsVisible: false);
}
// verify that the SimpleTypes refer to the correct type (no ambiguities)
FullyQualifyAmbiguousTypeNames(compilationUnit);
} }
readonly HashSet<string> declaredNamespaces = new HashSet<string>() { string.Empty };
readonly HashSet<string> importedNamespaces = new HashSet<string>(); readonly HashSet<string> importedNamespaces = new HashSet<string>();
readonly HashSet<string> availableTypeNames = new HashSet<string>();
readonly HashSet<string> ambiguousTypeNames = new HashSet<string>();
string currentNamespace; string currentNamespace;
bool IsParentOfCurrentNamespace(string ns) bool IsParentOfCurrentNamespace(string ns)
@ -77,10 +89,49 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
string oldNamespace = currentNamespace; string oldNamespace = currentNamespace;
foreach (Identifier ident in namespaceDeclaration.Identifiers) { foreach (Identifier ident in namespaceDeclaration.Identifiers) {
currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident.Name); currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident.Name);
declaredNamespaces.Add(currentNamespace);
} }
base.VisitNamespaceDeclaration(namespaceDeclaration, data); base.VisitNamespaceDeclaration(namespaceDeclaration, data);
currentNamespace = oldNamespace; currentNamespace = oldNamespace;
return null; return null;
} }
void FindAmbiguousTypeNames(ModuleDefinition module, bool internalsVisible)
{
foreach (TypeDefinition type in module.Types) {
if (internalsVisible || type.IsPublic) {
if (importedNamespaces.Contains(type.Namespace) || declaredNamespaces.Contains(type.Namespace)) {
if (!availableTypeNames.Add(type.Name))
ambiguousTypeNames.Add(type.Name);
}
}
}
}
void FullyQualifyAmbiguousTypeNames(AstNode compilationUnit)
{
foreach (SimpleType simpleType in compilationUnit.Descendants.OfType<SimpleType>()) {
TypeReference tr = simpleType.Annotation<TypeReference>();
if (tr != null && ambiguousTypeNames.Contains(tr.Name)) {
AstType ns;
if (string.IsNullOrEmpty(tr.Namespace)) {
ns = new SimpleType("global");
} else {
string[] parts = tr.Namespace.Split('.');
ns = new SimpleType(parts[0]);
for (int i = 1; i < parts.Length; i++) {
ns = new MemberType { Target = ns, MemberName = parts[i] };
}
}
MemberType mt = new MemberType();
mt.Target = ns;
mt.IsDoubleColon = string.IsNullOrEmpty(tr.Namespace);
mt.MemberName = simpleType.Identifier;
mt.CopyAnnotationsFrom(simpleType);
simpleType.TypeArguments.MoveTo(mt.TypeArguments);
simpleType.ReplaceWith(mt);
}
}
}
} }
} }

2
ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.Tests
static string RoundtripCode(string code) static string RoundtripCode(string code)
{ {
AssemblyDefinition assembly = Compile(code); AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext()); AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly); decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
StringWriter output = new StringWriter(); StringWriter output = new StringWriter();

2
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.Tests
{ {
string code = File.ReadAllText(fileName); string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code); AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext()); AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly); decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
StringWriter output = new StringWriter(); StringWriter output = new StringWriter();

23
ILSpy/CSharpLanguage.cs

@ -51,8 +51,9 @@ namespace ICSharpCode.ILSpy
#if DEBUG #if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages() internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{ {
DecompilerContext context = new DecompilerContext(ModuleDefinition.CreateModule("dummy", ModuleKind.Dll));
string lastTransformName = "no transforms"; string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline(new DecompilerContext()).Select(v => v.GetType()).Distinct()) { foreach (Type _transformType in TransformationPipeline.CreatePipeline(context).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda Type transformType = _transformType; // copy for lambda
yield return new CSharpLanguage { yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v), transformAbortCondition = v => transformType.IsInstanceOfType(v),
@ -83,7 +84,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, method.DeclaringType); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType);
codeDomBuilder.AddMethod(method); codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -92,7 +93,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, property.DeclaringType); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType);
codeDomBuilder.AddProperty(property); codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -101,7 +102,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, field.DeclaringType); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType);
codeDomBuilder.AddField(field); codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -110,7 +111,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, ev.DeclaringType); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType);
codeDomBuilder.AddEvent(ev); codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -118,7 +119,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = CreateAstBuilder(options, type); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -133,7 +134,7 @@ namespace ICSharpCode.ILSpy
WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule); WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule);
} else { } else {
base.DecompileAssembly(assembly, fileName, output, options); base.DecompileAssembly(assembly, fileName, output, options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: null); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: !options.FullDecompilation); codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: !options.FullDecompilation);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
@ -296,7 +297,7 @@ namespace ICSharpCode.ILSpy
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
delegate (IGrouping<string, TypeDefinition> file) { delegate (IGrouping<string, TypeDefinition> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) { using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, null); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
foreach (TypeDefinition type in file) { foreach (TypeDefinition type in file) {
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
} }
@ -383,10 +384,12 @@ namespace ICSharpCode.ILSpy
} }
#endregion #endregion
AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType) AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null)
{ {
if (currentModule == null)
currentModule = currentType.Module;
return new AstBuilder( return new AstBuilder(
new DecompilerContext { new DecompilerContext(currentModule) {
CancellationToken = options.CancellationToken, CancellationToken = options.CancellationToken,
CurrentType = currentType, CurrentType = currentType,
Settings = options.DecompilerSettings Settings = options.DecompilerSettings

2
ILSpy/ILAstLanguage.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy
ilMethod.Body = astBuilder.Build(method, inlineVariables); ilMethod.Body = astBuilder.Build(method, inlineVariables);
if (abortBeforeStep != null) { if (abortBeforeStep != null) {
DecompilerContext context = new DecompilerContext { CurrentType = method.DeclaringType, CurrentMethod = method }; DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method };
new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value); new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
} }

Loading…
Cancel
Save