Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
c7de679125
  1. 2
      Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs
  2. 257
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  3. 12
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  4. 2
      ICSharpCode.Decompiler/Ast/CSharpCodeMapping.cs
  5. 2
      ICSharpCode.Decompiler/Ast/CommentStatement.cs
  6. 2
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  7. 2
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  8. 7
      ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs
  9. 4
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  10. 4
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  11. 2
      ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs
  12. 2
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  13. 19
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  14. 3
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  15. 2
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  16. 2
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  17. 2
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  18. 9
      ICSharpCode.Decompiler/CecilExtensions.cs
  19. 3
      ICSharpCode.Decompiler/CodeMappings.cs
  20. 2
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  21. 2
      ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs
  22. 2
      ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs
  23. 3
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  24. 112
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  25. 2
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  26. 3
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  27. 2
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  28. 2
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  29. 2
      ICSharpCode.Decompiler/ILAst/Pattern.cs
  30. 83
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  31. 3
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  32. 2
      ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
  33. 9
      ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
  34. 5
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  35. 3
      ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
  36. 3
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  37. 8
      ILSpy.sln
  38. 23
      ILSpy/AboutPage.cs
  39. 16
      ILSpy/App.xaml.cs
  40. 4
      ILSpy/AssemblyList.cs
  41. 92
      ILSpy/BamlDecompiler.cs
  42. 9
      ILSpy/CSharpLanguage.cs
  43. 122
      ILSpy/Commands.cs
  44. 56
      ILSpy/Commands/RoutedUICommands.cs
  45. 63
      ILSpy/ExportCommandAttribute.cs
  46. 2
      ILSpy/GacInterop.cs
  47. 4
      ILSpy/GuessFileType.cs
  48. 5
      ILSpy/ILAstLanguage.cs
  49. 7
      ILSpy/ILSpy.csproj
  50. 12
      ILSpy/Images/Images.cs
  51. 25
      ILSpy/Language.cs
  52. 2
      ILSpy/LoadedAssembly.cs
  53. 122
      ILSpy/MainWindow.xaml
  54. 346
      ILSpy/MainWindow.xaml.cs
  55. 2
      ILSpy/NavigationHistory.cs
  56. 2
      ILSpy/Properties/AssemblyInfo.template.cs
  57. 11
      ILSpy/TextView/AvalonEditTextOutput.cs
  58. 7
      ILSpy/TextView/DecompilerTextView.cs
  59. 2
      ILSpy/TextView/DecompilerTextView.xaml
  60. 2
      ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs
  61. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  62. 2
      ILSpy/TreeNodes/EventTreeNode.cs
  63. 2
      ILSpy/TreeNodes/FieldTreeNode.cs
  64. 4
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  65. 2
      ILSpy/TreeNodes/MethodTreeNode.cs
  66. 2
      ILSpy/TreeNodes/NamespaceTreeNode.cs
  67. 2
      ILSpy/TreeNodes/PropertyTreeNode.cs
  68. 149
      ILSpy/TreeNodes/ResourceEntryNode.cs
  69. 108
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  70. 174
      ILSpy/TreeNodes/ResourceTreeNode.cs
  71. 2
      ILSpy/TreeNodes/TypeTreeNode.cs
  72. 2
      Mono.Cecil/Mono.Cecil/PInvokeAttributes.cs
  73. 8
      Mono.Cecil/Mono.Cecil/PInvokeInfo.cs

2
Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs

@ -10,7 +10,7 @@ using System.Windows.Media; @@ -10,7 +10,7 @@ using System.Windows.Media;
using Debugger;
using Debugger.MetaData;
using Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.CSharp;
using ILSpy.Debugger.Services;

257
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -1,20 +1,25 @@ @@ -1,20 +1,25 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Ast = ICSharpCode.NRefactory.CSharp;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
using Ast = ICSharpCode.NRefactory.CSharp;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
public class AstBuilder
{
DecompilerContext context = new DecompilerContext();
@ -209,7 +214,7 @@ namespace Decompiler @@ -209,7 +214,7 @@ namespace Decompiler
AddTypeMembers(astType, typeDef);
}
ConvertCustomAttributes(astType, typeDef);
ConvertAttributes(astType, typeDef);
return astType;
}
@ -534,8 +539,7 @@ namespace Decompiler @@ -534,8 +539,7 @@ namespace Decompiler
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
}
ConvertCustomAttributes(astMethod, methodDef);
ConvertCustomAttributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astMethod, methodDef);
return astMethod;
}
@ -594,6 +598,7 @@ namespace Decompiler @@ -594,6 +598,7 @@ namespace Decompiler
astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
ConvertAttributes(astMethod, methodDef);
return astMethod;
}
@ -611,8 +616,7 @@ namespace Decompiler @@ -611,8 +616,7 @@ namespace Decompiler
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod);
ConvertCustomAttributes(astProp.Getter, propDef.GetMethod);
ConvertCustomAttributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astProp.Getter, propDef.GetMethod);
if (methodMapping != null)
astProp.Getter.AddAnnotation(methodMapping);
@ -624,8 +628,7 @@ namespace Decompiler @@ -624,8 +628,7 @@ namespace Decompiler
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return);
ConvertAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param);
if (methodMapping != null)
@ -649,6 +652,7 @@ namespace Decompiler @@ -649,6 +652,7 @@ namespace Decompiler
astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context)
}.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
if (methodMapping != null)
astEvent.AddAccessor.AddAnnotation(methodMapping);
@ -660,6 +664,7 @@ namespace Decompiler @@ -660,6 +664,7 @@ namespace Decompiler
astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context)
}.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
if (methodMapping != null)
astEvent.RemoveAccessor.AddAnnotation(methodMapping);
@ -681,7 +686,7 @@ namespace Decompiler @@ -681,7 +686,7 @@ namespace Decompiler
else
initializer.Initializer = new PrimitiveExpression(fieldDef.Constant);
}
ConvertCustomAttributes(astField, fieldDef);
ConvertAttributes(astField, fieldDef);
return astField;
}
@ -693,15 +698,227 @@ namespace Decompiler @@ -693,15 +698,227 @@ namespace Decompiler
astParam.Name = paramDef.Name;
if (paramDef.ParameterType is ByReferenceType) {
astParam.ParameterModifier = paramDef.IsOut ? ParameterModifier.Out : ParameterModifier.Ref;
astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref;
}
// TODO: params, this
ConvertCustomAttributes(astParam, paramDef);
ModuleDefinition module = ((MethodDefinition)paramDef.Method).Module;
if (paramDef.HasMarshalInfo) {
astParam.Attributes.Add(new AttributeSection(ConvertMarshalInfo(paramDef, module)));
}
if (astParam.ParameterModifier != ParameterModifier.Out) {
if (paramDef.IsIn)
astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(InAttribute), module)));
if (paramDef.IsOut)
astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(OutAttribute), module)));
}
yield return astParam;
}
}
#region ConvertAttributes
void ConvertAttributes(AttributedNode attributedNode, TypeDefinition typeDefinition)
{
ConvertCustomAttributes(attributedNode, typeDefinition);
// Handle the non-custom attributes:
#region SerializableAttribute
if (typeDefinition.IsSerializable)
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute))));
#endregion
#region StructLayoutAttribute
LayoutKind layoutKind = LayoutKind.Auto;
switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) {
case TypeAttributes.SequentialLayout:
layoutKind = LayoutKind.Sequential;
break;
case TypeAttributes.ExplicitLayout:
layoutKind = LayoutKind.Explicit;
break;
}
CharSet charSet = CharSet.None;
switch (typeDefinition.Attributes & TypeAttributes.StringFormatMask) {
case TypeAttributes.AnsiClass:
charSet = CharSet.Ansi;
break;
case TypeAttributes.AutoClass:
charSet = CharSet.Auto;
break;
case TypeAttributes.UnicodeClass:
charSet = CharSet.Unicode;
break;
}
LayoutKind defaultLayoutKind = (typeDefinition.IsValueType && !typeDefinition.IsEnum) ? LayoutKind.Sequential: LayoutKind.Auto;
if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) {
var structLayout = CreateNonCustomAttribute(typeof(StructLayoutAttribute));
structLayout.Arguments.Add(new IdentifierExpression("LayoutKind").Member(layoutKind.ToString()));
if (charSet != CharSet.Ansi) {
structLayout.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
}
if (typeDefinition.PackingSize > 0) {
structLayout.AddNamedArgument("Pack", new PrimitiveExpression((int)typeDefinition.PackingSize));
}
if (typeDefinition.ClassSize > 0) {
structLayout.AddNamedArgument("Size", new PrimitiveExpression((int)typeDefinition.ClassSize));
}
attributedNode.Attributes.Add(new AttributeSection(structLayout));
}
#endregion
}
void ConvertAttributes(AttributedNode attributedNode, MethodDefinition methodDefinition)
{
ConvertCustomAttributes(attributedNode, methodDefinition);
MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
#region DllImportAttribute
if (methodDefinition.HasPInvokeInfo) {
PInvokeInfo info = methodDefinition.PInvokeInfo;
Ast.Attribute dllImport = CreateNonCustomAttribute(typeof(DllImportAttribute));
dllImport.Arguments.Add(new PrimitiveExpression(info.Module.Name));
if (info.IsBestFitDisabled)
dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(false));
if (info.IsBestFitEnabled)
dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(true));
CallingConvention callingConvention;
switch (info.Attributes & PInvokeAttributes.CallConvMask) {
case PInvokeAttributes.CallConvCdecl:
callingConvention = CallingConvention.Cdecl;
break;
case PInvokeAttributes.CallConvFastcall:
callingConvention = CallingConvention.FastCall;
break;
case PInvokeAttributes.CallConvStdCall:
callingConvention = CallingConvention.StdCall;
break;
case PInvokeAttributes.CallConvThiscall:
callingConvention = CallingConvention.ThisCall;
break;
case PInvokeAttributes.CallConvWinapi:
callingConvention = CallingConvention.Winapi;
break;
default:
throw new NotSupportedException("unknown calling convention");
}
if (callingConvention != CallingConvention.Winapi)
dllImport.AddNamedArgument("CallingConvention", new IdentifierExpression("CallingConvention").Member(callingConvention.ToString()));
CharSet charSet = CharSet.None;
switch (info.Attributes & PInvokeAttributes.CharSetMask) {
case PInvokeAttributes.CharSetAnsi:
charSet = CharSet.Ansi;
break;
case PInvokeAttributes.CharSetAuto:
charSet = CharSet.Auto;
break;
case PInvokeAttributes.CharSetUnicode:
charSet = CharSet.Unicode;
break;
}
if (charSet != CharSet.None)
dllImport.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != methodDefinition.Name)
dllImport.AddNamedArgument("EntryPoint", new PrimitiveExpression(info.EntryPoint));
if (info.IsNoMangle)
dllImport.AddNamedArgument("ExactSpelling", new PrimitiveExpression(true));
if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig)
implAttributes &= ~MethodImplAttributes.PreserveSig;
else
dllImport.AddNamedArgument("PreserveSig", new PrimitiveExpression(false));
if (info.SupportsLastError)
dllImport.AddNamedArgument("SetLastError", new PrimitiveExpression(true));
if (info.IsThrowOnUnmappableCharDisabled)
dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(false));
if (info.IsThrowOnUnmappableCharEnabled)
dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(true));
attributedNode.Attributes.Add(new AttributeSection(dllImport));
}
#endregion
#region PreserveSigAttribute
if (implAttributes == MethodImplAttributes.PreserveSig) {
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(PreserveSigAttribute))));
implAttributes = 0;
}
#endregion
#region MethodImplAttribute
if (implAttributes != 0) {
Ast.Attribute methodImpl = CreateNonCustomAttribute(typeof(MethodImplAttribute));
TypeReference methodImplOptions = new TypeReference(
"System.Runtime.CompilerServices", "MethodImplOptions",
methodDefinition.Module, methodDefinition.Module.TypeSystem.Corlib);
methodImpl.Arguments.Add(MakePrimitive((long)implAttributes, methodImplOptions));
attributedNode.Attributes.Add(new AttributeSection(methodImpl));
}
#endregion
ConvertCustomAttributes(attributedNode, methodDefinition.MethodReturnType, AttributeTarget.Return);
if (methodDefinition.MethodReturnType.HasMarshalInfo) {
var marshalInfo = ConvertMarshalInfo(methodDefinition.MethodReturnType, methodDefinition.Module);
attributedNode.Attributes.Add(new AttributeSection(marshalInfo) { AttributeTarget = AttributeTarget.Return });
}
}
void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition)
{
ConvertCustomAttributes(attributedNode, fieldDefinition);
#region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) {
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute));
fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset));
attributedNode.Attributes.Add(new AttributeSection(fieldOffset));
}
#endregion
if (fieldDefinition.HasMarshalInfo) {
attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)));
}
}
#region MarshalAsAttribute (ConvertMarshalInfo)
static Ast.Attribute ConvertMarshalInfo(IMarshalInfoProvider marshalInfoProvider, ModuleDefinition module)
{
MarshalInfo marshalInfo = marshalInfoProvider.MarshalInfo;
Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
string memberName;
if (marshalInfo.NativeType == NativeType.Boolean)
memberName = "Bool";
else
memberName = marshalInfo.NativeType.ToString();
attr.Arguments.Add(new IdentifierExpression("UnmanagedType").Member(memberName));
return attr;
}
#endregion
Ast.Attribute CreateNonCustomAttribute(Type attributeType)
{
return CreateNonCustomAttribute(attributeType, context.CurrentType != null ? context.CurrentType.Module : null);
}
static Ast.Attribute CreateNonCustomAttribute(Type attributeType, ModuleDefinition module)
{
Debug.Assert(attributeType.Name.EndsWith("Attribute", StringComparison.Ordinal));
Ast.Attribute attr = new Ast.Attribute();
attr.Type = new SimpleType(attributeType.Name.Substring(0, attributeType.Name.Length - "Attribute".Length));
if (module != null) {
attr.Type.AddAnnotation(new TypeReference(attributeType.Namespace, attributeType.Name, module, module.TypeSystem.Corlib));
}
return attr;
}
static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None)
{
if (customAttributeProvider.HasCustomAttributes) {
@ -723,8 +940,9 @@ namespace Decompiler @@ -723,8 +940,9 @@ namespace Decompiler
}
}
if (customAttribute.HasProperties) {
TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
foreach (var propertyNamedArg in customAttribute.Properties) {
var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == propertyNamedArg.Name);
var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null;
var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference);
var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument);
attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue));
@ -732,8 +950,9 @@ namespace Decompiler @@ -732,8 +950,9 @@ namespace Decompiler
}
if (customAttribute.HasFields) {
TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
foreach (var fieldNamedArg in customAttribute.Fields) {
var fieldReference = customAttribute.AttributeType.Resolve().Fields.First(f => f.Name == fieldNamedArg.Name);
var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null;
var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference);
var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument);
attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue));
@ -758,7 +977,7 @@ namespace Decompiler @@ -758,7 +977,7 @@ namespace Decompiler
}
}
}
private static Expression ConvertArgumentValue(CustomAttributeArgument parameter)
{
var type = parameter.Type.Resolve();
@ -780,7 +999,7 @@ namespace Decompiler @@ -780,7 +999,7 @@ namespace Decompiler
}
return parameterValue;
}
#endregion
internal static Expression MakePrimitive(long val, TypeReference type)
{

12
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -4,16 +4,18 @@ using System.Collections.Generic; @@ -4,16 +4,18 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.Utils;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Decompiler.ControlFlow;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
using Ast = ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil;
public class AstMethodBodyBuilder
{
MethodDefinition methodDef;

2
ICSharpCode.Decompiler/Ast/CSharpCodeMapping.cs

@ -7,7 +7,7 @@ using System.Collections.Generic; @@ -7,7 +7,7 @@ using System.Collections.Generic;
using ICSharpCode.Decompiler;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// Stores the C# code mappings.

2
ICSharpCode.Decompiler/Ast/CommentStatement.cs

@ -6,7 +6,7 @@ using System.Linq; @@ -6,7 +6,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// Allows storing comments inside IEnumerable{Statement}. Used in the AstMethodBuilder.

2
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -6,7 +6,7 @@ using System.Linq; @@ -6,7 +6,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
/// <summary>
/// Helper class for declaring variables.

2
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -5,7 +5,7 @@ using System; @@ -5,7 +5,7 @@ using System;
using System.Threading;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler
{
public class DecompilerContext
{

7
ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
static class NRefactoryExtensions
{
@ -28,5 +28,10 @@ namespace Decompiler @@ -28,5 +28,10 @@ namespace Decompiler
node.Remove();
return node;
}
public static void AddNamedArgument(this NRefactory.CSharp.Attribute attribute, string name, Expression argument)
{
attribute.Arguments.Add(new AssignmentExpression(new IdentifierExpression(name), argument));
}
}
}

4
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -4,9 +4,11 @@ @@ -4,9 +4,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
public class NameVariables
{

4
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -4,11 +4,13 @@ @@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.Ast
{
public class TextOutputFormatter : IOutputFormatter
{

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

@ -6,7 +6,7 @@ using System.Diagnostics; @@ -6,7 +6,7 @@ using System.Diagnostics;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Base class for AST visitors that need the current type/method context info.

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

@ -6,7 +6,7 @@ using System.Linq; @@ -6,7 +6,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer.

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

@ -10,7 +10,7 @@ using ICSharpCode.NRefactory.CSharp; @@ -10,7 +10,7 @@ using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".
@ -94,13 +94,20 @@ namespace Decompiler.Transforms @@ -94,13 +94,20 @@ namespace Decompiler.Transforms
return base.VisitObjectCreateExpression(objectCreateExpression, data);
}
internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method)
{
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal))
return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType)))
return false;
return true;
}
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef)
{
// Anonymous methods are defined in the same assembly, so there's no need to Resolve().
MethodDefinition method = methodRef as MethodDefinition;
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal))
return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(method.DeclaringType)))
if (!IsAnonymousMethod(context, method))
return false;
// Decompile the anonymous method:
@ -143,7 +150,7 @@ namespace Decompiler.Transforms @@ -143,7 +150,7 @@ namespace Decompiler.Transforms
return true;
}
bool IsPotentialClosure(TypeDefinition potentialDisplayClass)
static bool IsPotentialClosure(DecompilerContext context, TypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGenerated())
return false;
@ -164,7 +171,7 @@ namespace Decompiler.Transforms @@ -164,7 +171,7 @@ namespace Decompiler.Transforms
continue;
var variable = stmt.Variables.Single();
TypeDefinition type = stmt.Type.Annotation<TypeDefinition>();
if (!IsPotentialClosure(type))
if (!IsPotentialClosure(context, type))
continue;
ObjectCreateExpression oce = variable.Initializer as ObjectCreateExpression;
if (oce == null || oce.Type.Annotation<TypeReference>() != type || oce.Arguments.Any() || !oce.Initializer.IsNull)

3
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -3,12 +3,11 @@ @@ -3,12 +3,11 @@
using System;
using System.Linq;
using Decompiler.Transforms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement.

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

@ -4,7 +4,7 @@ using System.Linq; @@ -4,7 +4,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{

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

@ -6,7 +6,7 @@ using Mono.Cecil; @@ -6,7 +6,7 @@ using Mono.Cecil;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Replaces method calls with the appropriate operator expressions.

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

@ -5,7 +5,7 @@ using System; @@ -5,7 +5,7 @@ using System;
using System.Threading;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms
namespace ICSharpCode.Decompiler.Ast.Transforms
{
public interface IAstTransform
{

9
ICSharpCode.Decompiler/CecilExtensions.cs

@ -169,5 +169,14 @@ namespace ICSharpCode.Decompiler @@ -169,5 +169,14 @@ namespace ICSharpCode.Decompiler
}
return false;
}
public static bool IsCompilerGeneratedOrIsInCompilerGeneratedClass(this IMemberDefinition member)
{
if (member == null)
return false;
if (member.IsCompilerGenerated())
return true;
return IsCompilerGeneratedOrIsInCompilerGeneratedClass(member.DeclaringType);
}
}
}

3
ICSharpCode.Decompiler/CodeMappings.cs

@ -6,8 +6,9 @@ using System.Collections.Concurrent; @@ -6,8 +6,9 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
namespace ICSharpCode.Decompiler

2
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -21,9 +21,9 @@ using System.Collections.Generic; @@ -21,9 +21,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Decompiler;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
using Mono.Cecil.Cil;

2
ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs

@ -21,7 +21,7 @@ using System; @@ -21,7 +21,7 @@ using System;
namespace ICSharpCode.Decompiler.FlowAnalysis
{
/// <summary>
///
/// Describes the type of a control flow egde.
/// </summary>
public enum JumpType
{

2
ICSharpCode.Decompiler/ILAst/ArrayInitializers.cs

@ -7,7 +7,7 @@ using System.Linq; @@ -7,7 +7,7 @@ using System.Linq;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
/// <summary>
/// IL AST transformation that introduces array initializers.

3
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -3,9 +3,8 @@ using System.Diagnostics; @@ -3,9 +3,8 @@ using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Decompiler.ControlFlow;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public class GotoRemoval
{

112
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -8,7 +8,7 @@ using Mono.Cecil; @@ -8,7 +8,7 @@ using Mono.Cecil;
using Mono.Cecil.Cil;
using Cecil = Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public class ILAstBuilder
{
@ -17,54 +17,59 @@ namespace Decompiler @@ -17,54 +17,59 @@ namespace Decompiler
/// </summary>
public static ConcurrentDictionary<int, List<ILVariable>> MemberLocalVariables = new ConcurrentDictionary<int, List<ILVariable>>();
static ByteCode[] EmptyByteCodeArray = new ByteCode[] {};
/// <summary> Immutable </summary>
class StackSlot
{
public List<ByteCode> PushedBy; // One of those
public ILVariable LoadFrom; // Where can we get the value from in AST
public readonly ByteCode[] PushedBy; // One of those
public readonly ILVariable LoadFrom; // Where can we get the value from in AST
public StackSlot()
public StackSlot(ByteCode[] pushedBy, ILVariable loadFrom)
{
this.PushedBy = pushedBy;
this.LoadFrom = loadFrom;
}
public StackSlot(ByteCode pushedBy)
{
this.PushedBy = new List<ByteCode>(1);
this.PushedBy.Add(pushedBy);
this.PushedBy = new[] { pushedBy };
this.LoadFrom = null;
}
public static List<StackSlot> CloneStack(List<StackSlot> stack, int? popCount)
{
List<StackSlot> clone = new List<StackSlot>();
if (popCount.HasValue) {
if (popCount.Value > stack.Count) {
throw new Exception("Can not pop - the stack is empty");
}
for(int i = 0; i < stack.Count - popCount.Value; i++) {
clone.Add(new StackSlot() { PushedBy = new List<ByteCode>(stack[i].PushedBy) });
}
return stack.GetRange(0, stack.Count - popCount.Value);
} else {
return new List<StackSlot>(0);
}
return clone;
}
}
/// <summary> Immutable </summary>
class VariableSlot
{
public static List<ByteCode> Empty = new List<ByteCode>();
{
public readonly ByteCode[] StoredBy; // One of those
public readonly bool StoredByAll; // Overestimate which is useful for exceptional control flow.
public VariableSlot(ByteCode[] storedBy, bool storedByAll)
{
this.StoredBy = storedBy;
this.StoredByAll = storedByAll;
}
public List<ByteCode> StoredBy = Empty; // One of those
public bool StoredByAll; // Overestimate which is useful for exceptional control flow.
public VariableSlot(ByteCode storedBy)
{
this.StoredBy = new[] { storedBy };
this.StoredByAll = false;
}
public static VariableSlot[] CloneVariableState(VariableSlot[] state)
{
VariableSlot[] clone = new ILAstBuilder.VariableSlot[state.Length];
if (VariableSlot.Empty.Count > 0)
throw new Exception("Constant data corrupted");
VariableSlot[] clone = new VariableSlot[state.Length];
for (int i = 0; i < clone.Length; i++) {
VariableSlot varSlot = state[i];
clone[i] = new VariableSlot() {
StoredBy = varSlot.StoredBy.Count == 0 ? VariableSlot.Empty : new List<ByteCode>(varSlot.StoredBy),
StoredByAll = varSlot.StoredByAll
};
clone[i] = state[i];
}
return clone;
}
@ -73,7 +78,7 @@ namespace Decompiler @@ -73,7 +78,7 @@ namespace Decompiler
{
VariableSlot[] emptyVariableState = new VariableSlot[varCount];
for (int i = 0; i < emptyVariableState.Length; i++) {
emptyVariableState[i] = new VariableSlot();
emptyVariableState[i] = new VariableSlot(EmptyByteCodeArray, false);
}
return emptyVariableState;
}
@ -82,7 +87,7 @@ namespace Decompiler @@ -82,7 +87,7 @@ namespace Decompiler
{
VariableSlot[] unknownVariableState = new VariableSlot[varCount];
for (int i = 0; i < unknownVariableState.Length; i++) {
unknownVariableState[i] = new VariableSlot() { StoredByAll = true };
unknownVariableState[i] = new VariableSlot(EmptyByteCodeArray, true);
}
return unknownVariableState;
}
@ -100,9 +105,9 @@ namespace Decompiler @@ -100,9 +105,9 @@ namespace Decompiler
public string Name { get { return "IL_" + this.Offset.ToString("X2"); } }
public ByteCode Next;
public Instruction[] Prefixes; // Non-null only if needed
public List<StackSlot> StackBefore;
public List<StackSlot> StackBefore; // Unique per bytecode; not shared
public List<ILVariable> StoreTo; // Store result of instruction to those AST variables
public VariableSlot[] VariablesBefore;
public VariableSlot[] VariablesBefore; // Unique per bytecode; not shared
public VariableDefinition OperandAsVariable { get { return (VariableDefinition)this.Operand; } }
@ -181,7 +186,7 @@ namespace Decompiler @@ -181,7 +186,7 @@ namespace Decompiler
if (!first) sb.Append(",");
if (varSlot.StoredByAll) {
sb.Append("*");
} else if (varSlot.StoredBy.Count == 0) {
} else if (varSlot.StoredBy.Length == 0) {
sb.Append("_");
} else {
bool first2 = true;
@ -304,8 +309,7 @@ namespace Decompiler @@ -304,8 +309,7 @@ namespace Decompiler
VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
if (byteCode.Code == ILCode.Stloc) {
int varIndex = ((VariableReference)byteCode.Operand).Index;
newVariableState[varIndex].StoredBy = new List<ByteCode>(1) { byteCode };
newVariableState[varIndex].StoredByAll = false;
newVariableState[varIndex] = new VariableSlot(byteCode);
}
// After the leave, finally block might have touched the variables
@ -360,10 +364,10 @@ namespace Decompiler @@ -360,10 +364,10 @@ namespace Decompiler
// Merge stacks - modify the target
for (int i = 0; i < newStack.Count; i++) {
List<ByteCode> oldPushedBy = branchTarget.StackBefore[i].PushedBy;
List<ByteCode> newPushedBy = oldPushedBy.Union(newStack[i].PushedBy).ToList();
if (newPushedBy.Count > oldPushedBy.Count) {
branchTarget.StackBefore[i].PushedBy = newPushedBy;
ByteCode[] oldPushedBy = branchTarget.StackBefore[i].PushedBy;
ByteCode[] newPushedBy = oldPushedBy.Union(newStack[i].PushedBy);
if (newPushedBy.Length > oldPushedBy.Length) {
branchTarget.StackBefore[i] = new StackSlot(newPushedBy, null);
modified = true;
}
}
@ -375,13 +379,13 @@ namespace Decompiler @@ -375,13 +379,13 @@ namespace Decompiler
// All can not be unioned further
if (!oldSlot.StoredByAll) {
if (newSlot.StoredByAll) {
oldSlot.StoredByAll = true;
branchTarget.VariablesBefore[i] = newSlot;
modified = true;
} else {
List<ByteCode> oldStoredBy = oldSlot.StoredBy;
List<ByteCode> newStoredBy = oldStoredBy.Union(newSlot.StoredBy).ToList();
if (newStoredBy.Count > oldStoredBy.Count) {
oldSlot.StoredBy = newStoredBy;
ByteCode[] oldStoredBy = oldSlot.StoredBy;
ByteCode[] newStoredBy = oldStoredBy.Union(newSlot.StoredBy);
if (newStoredBy.Length > oldStoredBy.Length) {
branchTarget.VariablesBefore[i] = new VariableSlot(newStoredBy, false);
modified = true;
}
}
@ -403,16 +407,15 @@ namespace Decompiler @@ -403,16 +407,15 @@ namespace Decompiler
int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
StackSlot arg = byteCode.StackBefore[i];
ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true };
arg.LoadFrom = tmpVar;
foreach(ByteCode pushedBy in arg.PushedBy) {
byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].PushedBy, tmpVar);
foreach(ByteCode pushedBy in byteCode.StackBefore[i].PushedBy) {
if (pushedBy.StoreTo == null) {
pushedBy.StoreTo = new List<ILVariable>(1);
}
pushedBy.StoreTo.Add(tmpVar);
}
if (arg.PushedBy.Count == 1) {
if (byteCode.StackBefore[i].PushedBy.Length == 1) {
allowInline[tmpVar] = true;
}
argIdx++;
@ -489,10 +492,10 @@ namespace Decompiler @@ -489,10 +492,10 @@ namespace Decompiler
// Add loads to the data structure; merge variables if necessary
foreach(ByteCode load in loads) {
List<ByteCode> storedBy = load.VariablesBefore[variableIndex].StoredBy;
if (storedBy.Count == 0) {
ByteCode[] storedBy = load.VariablesBefore[variableIndex].StoredBy;
if (storedBy.Length == 0) {
throw new Exception("Load of uninitialized variable");
} else if (storedBy.Count == 1) {
} else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Where(v => v.Stores.Contains(storedBy[0])).Single();
newVar.Loads.Add(load);
} else {
@ -738,5 +741,16 @@ namespace Decompiler @@ -738,5 +741,16 @@ namespace Decompiler
list.RemoveRange(start, count);
return ret;
}
public static T[] Union<T>(this T[] a, T[] b)
{
if (a.Length == 0)
return b;
if (b.Length == 0)
return a;
if (a.Length == 1 && b.Length == 1 && a[0].Equals(b[0]))
return a;
return Enumerable.Union(a, b).ToArray();
}
}
}

2
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -7,7 +7,7 @@ using Mono.Cecil; @@ -7,7 +7,7 @@ using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.CSharp;
namespace Decompiler.ControlFlow
namespace ICSharpCode.Decompiler.ILAst
{
public enum ILAstOptimizationStep
{

3
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -3,7 +3,6 @@ using System.Collections.Generic; @@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Decompiler.ControlFlow;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.Utils;
@ -12,7 +11,7 @@ using Mono.Cecil.Cil; @@ -12,7 +11,7 @@ using Mono.Cecil.Cil;
using Mono.CSharp;
using Cecil = Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public abstract class ILNode
{

2
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -27,7 +27,7 @@ using System; @@ -27,7 +27,7 @@ using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public enum ILCode
{

2
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -5,7 +5,7 @@ using System; @@ -5,7 +5,7 @@ using System;
using System.Diagnostics;
using System.Linq;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
/// <summary>
/// Performs inlining transformations.

2
ICSharpCode.Decompiler/ILAst/Pattern.cs

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
using System;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public interface IVariablePattern
{

83
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -2,23 +2,32 @@ @@ -2,23 +2,32 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
public delegate void PeepholeTransform(ILBlock block, ref int i);
/// <summary>
/// Handles peephole transformations on the ILAst.
/// </summary>
public static class PeepholeTransforms
public class PeepholeTransforms
{
DecompilerContext context;
ILBlock method;
public static void Run(DecompilerContext context, ILBlock method)
{
PeepholeTransforms transforms = new PeepholeTransforms();
transforms.context = context;
transforms.method = method;
PeepholeTransform[] blockTransforms = {
ArrayInitializers.Transform(method)
ArrayInitializers.Transform(method),
transforms.CachedDelegateInitialization
};
Func<ILExpression, ILExpression>[] exprTransforms = {
EliminateDups,
@ -43,6 +52,9 @@ namespace Decompiler @@ -43,6 +52,9 @@ namespace Decompiler
// apply block transforms
foreach (var t in blockTransforms) {
t(block, ref i);
Debug.Assert(i <= block.Body.Count && i >= 0);
if (i == block.Body.Count) // special case: retry all transforms
break;
}
}
}
@ -67,6 +79,7 @@ namespace Decompiler @@ -67,6 +79,7 @@ namespace Decompiler
return expr;
}
#region HandleDecimalConstants
static ILExpression HandleDecimalConstants(ILExpression expr)
{
if (expr.Code == ILCode.Newobj) {
@ -105,5 +118,69 @@ namespace Decompiler @@ -105,5 +118,69 @@ namespace Decompiler
else
return null;
}
#endregion
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)
{
// if (logicnot(brtrue(ldsfld(field)))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
// } else {
// }
// ...(..., ldsfld(field), ...)
ILCondition c = block.Body[i] as ILCondition;
if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
return;
ILExpression condition = UnpackBrFalse(c.Condition);
if (condition == null || condition.Code != ILCode.Ldsfld)
return;
FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly
if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return;
ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression;
if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && stsfld.Operand == field))
return;
ILExpression newObj = stsfld.Arguments[0];
if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
return;
if (newObj.Arguments[0].Code != ILCode.Ldnull)
return;
if (newObj.Arguments[1].Code != ILCode.Ldftn)
return;
MethodDefinition anonymousMethod = newObj.Arguments[1].Operand as MethodDefinition; // method is defined in current assembly
if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
return;
ILExpression expr = block.Body.ElementAtOrDefault(i + 1) as ILExpression;
if (expr != null && expr.GetSelfAndChildrenRecursive<ILExpression>().Count(e => e.Code == ILCode.Ldsfld && e.Operand == field) == 1) {
foreach (ILExpression parent in expr.GetSelfAndChildrenRecursive<ILExpression>()) {
for (int j = 0; j < parent.Arguments.Count; j++) {
if (parent.Arguments[j].Code == ILCode.Ldsfld && parent.Arguments[j].Operand == field) {
parent.Arguments[j] = newObj;
block.Body.RemoveAt(i);
i -= ILInlining.InlineInto(block, i, method);
return;
}
}
}
}
}
/// <summary>
/// Returns 'result' in brfalse(result) or logicnot(brtrue(result)).
/// </summary>
static ILExpression UnpackBrFalse(ILExpression condition)
{
if (condition.Code == ILCode.Brfalse) {
return condition.Arguments.Single();
} else if (condition.Code == ILCode.LogicNot && condition.Arguments.Single().Code == ILCode.Brtrue) {
return condition.Arguments.Single().Arguments.Single();
}
return null;
}
#endregion
}
}

3
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -5,11 +5,10 @@ using System; @@ -5,11 +5,10 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Decompiler;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
namespace ICSharpCode.Decompiler.ILAst
{
/// <summary>
/// Assigns C# types to IL expressions.

2
ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs

@ -11,7 +11,7 @@ using System.Runtime.InteropServices; @@ -11,7 +11,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription("IL decompiler engine")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPara for the SharpDevelop Team")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

9
ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs

@ -1,12 +1,13 @@ @@ -1,12 +1,13 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Mono.Cecil;
using System.IO;
using Decompiler;
using ICSharpCode.Decompiler.Ast;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using Mono.Cecil;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests

5
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -59,4 +59,9 @@ public static class DelegateConstruction @@ -59,4 +59,9 @@ public static class DelegateConstruction
}
return list;
}
public static Action StaticAnonymousMethodNoClosure()
{
return delegate { Console.WriteLine(); };
}
}

3
ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs

@ -2,8 +2,9 @@ @@ -2,8 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.NRefactory.CSharp;
using Decompiler.Transforms;
namespace ICSharpCode.Decompiler.Tests.Helpers
{

3
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -6,7 +6,8 @@ using System.CodeDom.Compiler; @@ -6,7 +6,8 @@ using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Decompiler;
using ICSharpCode.Decompiler.Ast;
using Microsoft.CSharp;
using Mono.Cecil;

8
ILSpy.sln

@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.1.0.7322-alpha
# SharpDevelop 4.1.0.7312-alpha
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Core", "Debugger\Debugger.Core\Debugger.Core.csproj", "{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.Debugger", "Debugger\ILSpy.Debugger\ILSpy.Debugger.csproj", "{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Core", "Debugger\Debugger.Core\Debugger.Core.csproj", "{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}"
@ -109,7 +109,7 @@ Global @@ -109,7 +109,7 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
{6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}
EndGlobalSection
EndGlobal

23
ILSpy/AboutPage.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -14,13 +15,23 @@ using System.Windows.Data; @@ -14,13 +15,23 @@ using System.Windows.Data;
using System.Windows.Input;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
namespace ICSharpCode.ILSpy
{
static class AboutPage
[ExportMainMenuCommand(Menu = "_Help", Header = "_About", MenuOrder = 99999)]
sealed class AboutPage : SimpleCommand
{
[Import]
DecompilerTextView decompilerTextView = null;
public override void Execute(object parameter)
{
Display(decompilerTextView);
}
static readonly Uri UpdateUrl = new Uri("http://www.ilspy.net/updates.xml");
static AvailableVersionInfo latestAvailableVersion;
@ -52,6 +63,8 @@ namespace ICSharpCode.ILSpy @@ -52,6 +63,8 @@ namespace ICSharpCode.ILSpy
};
});
output.WriteLine();
foreach (var plugin in App.CompositionContainer.GetExportedValues<IAboutPageAddition>())
plugin.Write(output);
output.WriteLine();
using (Stream s = typeof(AboutPage).Assembly.GetManifestResourceStream(typeof(AboutPage), "README.txt")) {
using (StreamReader r = new StreamReader(s)) {
@ -256,4 +269,12 @@ namespace ICSharpCode.ILSpy @@ -256,4 +269,12 @@ namespace ICSharpCode.ILSpy
return tcs.Task;
}
}
/// <summary>
/// Interface that allows plugins to extend the about page.
/// </summary>
public interface IAboutPageAddition
{
void Write(ISmartTextOutput textOutput);
}
}

16
ILSpy/App.xaml.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Diagnostics;
using System.Threading;
using System.Windows;
@ -31,10 +33,24 @@ namespace ICSharpCode.ILSpy @@ -31,10 +33,24 @@ namespace ICSharpCode.ILSpy
/// </summary>
public partial class App : Application
{
static CompositionContainer compositionContainer;
public static CompositionContainer CompositionContainer {
get { return compositionContainer; }
}
public App()
{
InitializeComponent();
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(App).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog(".", "*.Plugin.dll"));
compositionContainer = new CompositionContainer(catalog);
Languages.Initialize(compositionContainer);
if (!Debugger.IsAttached) {
AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;

4
ILSpy/AssemblyList.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// A list of assemblies.
/// </summary>
sealed class AssemblyList
public sealed class AssemblyList
{
readonly string listName;
@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy @@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Saves this assembly list to XML.
/// </summary>
public XElement SaveAsXml()
internal XElement SaveAsXml()
{
return new XElement(
"List",

92
ILSpy/BamlDecompiler.cs

@ -2,16 +2,23 @@ @@ -2,16 +2,23 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Baml2006;
using System.Xaml;
using System.Xml;
namespace ICSharpCode.ILSpy
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy.Baml
{
/// <remarks>Caution: use in separate AppDomain only!</remarks>
public class BamlDecompiler : MarshalByRefObject
sealed class BamlDecompiler : MarshalByRefObject
{
public BamlDecompiler()
{
@ -60,4 +67,85 @@ namespace ICSharpCode.ILSpy @@ -60,4 +67,85 @@ namespace ICSharpCode.ILSpy
return w.ToString();
}
}
[Export(typeof(IResourceNodeFactory))]
sealed class BamlResourceNodeFactory : IResourceNodeFactory
{
public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource)
{
return null;
}
public ILSpyTreeNode CreateNode(string key, Stream data)
{
if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase))
return new BamlResourceEntryNode(key, data);
else
return null;
}
}
sealed class BamlResourceEntryNode : ResourceEntryNode
{
public BamlResourceEntryNode(string key, Stream data) : base(key, data)
{
}
internal override bool View(DecompilerTextView textView)
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
IHighlightingDefinition highlighting = null;
textView.RunWithCancellation(
token => Task.Factory.StartNew(
() => {
try {
if (LoadBaml(output))
highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
} catch (Exception ex) {
output.Write(ex.ToString());
}
return output;
}),
t => textView.Show(t.Result, highlighting)
);
return true;
}
bool LoadBaml(AvalonEditTextOutput output)
{
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
AppDomain bamlDecompilerAppDomain = null;
try {
BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName);
MemoryStream bamlStream = new MemoryStream();
data.Position = 0;
data.CopyTo(bamlStream);
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName));
return true;
} finally {
if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain);
}
}
public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName)
{
if (appDomain == null) {
// Construct and initialize settings for a second AppDomain.
AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup();
bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName);
bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false;
bamlDecompilerAppDomainSetup.DisallowCodeDownload = true;
bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
// Create the second AppDomain.
appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup);
}
return (BamlDecompiler)appDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName);
}
}
}

9
ILSpy/CSharpLanguage.cs

@ -19,16 +19,16 @@ @@ -19,16 +19,16 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Resources;
using System.Threading.Tasks;
using System.Xaml;
using System.Xml;
using Decompiler;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -37,6 +37,7 @@ namespace ICSharpCode.ILSpy @@ -37,6 +37,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Decompiler logic for C#.
/// </summary>
[Export(typeof(Language))]
public class CSharpLanguage : Language
{
string name = "C#";
@ -323,7 +324,7 @@ namespace ICSharpCode.ILSpy @@ -323,7 +324,7 @@ namespace ICSharpCode.ILSpy
if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) {
MemoryStream ms = new MemoryStream();
entryStream.CopyTo(ms);
BamlDecompiler decompiler = TreeNodes.ResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assemblyFileName);
var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assemblyFileName);
string xaml = null;
try {
xaml = decompiler.DecompileBaml(ms, assemblyFileName);

122
ILSpy/Commands.cs

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
// 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.ComponentModel.Composition;
using System.Linq;
using System.Windows.Input;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(Menu = "_File", Header = "E_xit", MenuOrder = 99999, MenuCategory = "Exit")]
sealed class ExitCommand : SimpleCommand
{
public override void Execute(object parameter)
{
MainWindow.Instance.Close();
}
}
[ExportToolbarCommand(ToolTip = "Back", ToolbarIcon = "Images/Back.png", ToolbarCategory = "Navigation", ToolbarOrder = 0)]
sealed class BrowseBackCommand : CommandWrapper {
public BrowseBackCommand() : base(NavigationCommands.BrowseBack) {}
}
[ExportToolbarCommand(ToolTip = "Forward", ToolbarIcon = "Images/Forward.png", ToolbarCategory = "Navigation", ToolbarOrder = 1)]
sealed class BrowseForwardCommand : CommandWrapper {
public BrowseForwardCommand() : base(NavigationCommands.BrowseForward) {}
}
[ExportToolbarCommand(ToolTip = "Open", ToolbarIcon = "Images/Open.png", ToolbarCategory = "Open", ToolbarOrder = 0)]
[ExportMainMenuCommand(Menu = "_File", MenuIcon = "Images/Open.png", MenuCategory = "Open", MenuOrder = 0)]
sealed class OpenCommand : CommandWrapper {
public OpenCommand() : base(ApplicationCommands.Open) {}
}
[ExportMainMenuCommand(Menu = "_File", Header = "Open from _GAC", MenuCategory = "Open", MenuOrder = 1)]
sealed class OpenFromGacCommand : SimpleCommand
{
public override void Execute(object parameter)
{
OpenFromGacDialog dlg = new OpenFromGacDialog();
dlg.Owner = MainWindow.Instance;
if (dlg.ShowDialog() == true) {
MainWindow.Instance.OpenFiles(dlg.SelectedFileNames);
}
}
}
[ExportToolbarCommand(ToolTip = "Reload all assemblies", ToolbarIcon = "Images/Refresh.png", ToolbarCategory = "Open", ToolbarOrder = 2)]
[ExportMainMenuCommand(Menu = "_File", Header = "Reload", MenuIcon = "Images/Refresh.png", MenuCategory = "Open", MenuOrder = 2)]
sealed class RefreshCommand : CommandWrapper {
public RefreshCommand() : base(NavigationCommands.Refresh) {}
}
[ExportMainMenuCommand(Menu = "_File", Header = "_Save Code...", MenuIcon = "Images/SaveFile.png", MenuCategory = "Save", MenuOrder = 0)]
sealed class SaveCommand : SimpleCommand
{
public override void Execute(object parameter)
{
MainWindow mainWindow = MainWindow.Instance;
if (mainWindow.SelectedNodes.Count() == 1) {
if (mainWindow.SelectedNodes.Single().Save(mainWindow.TextView))
return;
}
mainWindow.TextView.SaveToDisk(mainWindow.CurrentLanguage,
mainWindow.SelectedNodes,
new DecompilationOptions() { FullDecompilation = true });
}
}
class CommandWrapper : ICommand
{
ICommand wrappedCommand;
public CommandWrapper(ICommand wrappedCommand)
{
this.wrappedCommand = wrappedCommand;
}
public static ICommand Unwrap(ICommand command)
{
CommandWrapper w = command as CommandWrapper;
if (w != null)
return w.wrappedCommand;
else
return command;
}
public event EventHandler CanExecuteChanged {
add { wrappedCommand.CanExecuteChanged += value; }
remove { wrappedCommand.CanExecuteChanged -= value; }
}
public void Execute(object parameter)
{
wrappedCommand.Execute(parameter);
}
public bool CanExecute(object parameter)
{
return wrappedCommand.CanExecute(parameter);
}
}
public abstract class SimpleCommand : ICommand
{
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public abstract void Execute(object parameter);
public virtual bool CanExecute(object parameter)
{
return true;
}
}
}

56
ILSpy/Commands/RoutedUICommands.cs

@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Input;
namespace ICSharpCode.ILSpy.Commands
{
public static class RoutedUICommands
{
static RoutedUICommands()
{
AttachToProcess = new RoutedUICommand("Attach to running process...", "AttachToProcess", typeof(RoutedUICommands));
DetachFromProcess = new RoutedUICommand("Detach from process...", "DetachFromProcess", typeof(RoutedUICommands));
ContinueDebugging = new RoutedUICommand("Continue debugging", "ContinueDebugging", typeof(RoutedUICommands));
StepInto = new RoutedUICommand("Step into", "StepInto", typeof(RoutedUICommands));
StepOver = new RoutedUICommand("Step over", "StepOver", typeof(RoutedUICommands));
StepOut = new RoutedUICommand("Step out", "StepOut", typeof(RoutedUICommands));
RemoveAllBreakpoint = new RoutedUICommand("Remove all breakpoints", "RemoveAllBreakpoint", typeof(RoutedUICommands));
DebugExecutable = new RoutedUICommand("Debug an executable", "DebugExecutable", typeof(RoutedUICommands));
}
public static RoutedUICommand AttachToProcess { get; private set; }
public static RoutedUICommand DetachFromProcess { get; private set; }
public static RoutedUICommand ContinueDebugging { get; private set; }
public static RoutedUICommand StepInto { get; private set; }
public static RoutedUICommand StepOver { get; private set; }
public static RoutedUICommand StepOut { get; private set; }
public static RoutedUICommand RemoveAllBreakpoint { get; private set; }
public static RoutedUICommand DebugExecutable { get; private set; }
}
}

63
ILSpy/ExportCommandAttribute.cs

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
// 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.ComponentModel.Composition;
using System.Windows.Input;
namespace ICSharpCode.ILSpy
{
#region Toolbar
public interface IToolbarCommandMetadata
{
string ToolbarIcon { get; }
string ToolTip { get; }
string ToolbarCategory { get; }
double ToolbarOrder { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportToolbarCommandAttribute : ExportAttribute
{
public ExportToolbarCommandAttribute()
: base("ToolbarCommand", typeof(ICommand))
{
}
public string ToolTip { get; set; }
public string ToolbarIcon { get; set; }
public string ToolbarCategory { get; set; }
public double ToolbarOrder { get; set; }
}
#endregion
#region Main Menu
public interface IMainMenuCommandMetadata
{
string MenuIcon { get; }
string Header { get; }
string Menu { get; }
string MenuCategory { get; }
double MenuOrder { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportMainMenuCommandAttribute : ExportAttribute
{
public ExportMainMenuCommandAttribute()
: base("MainMenuCommand", typeof(ICommand))
{
}
public string MenuIcon { get; set; }
public string Header { get; set; }
public string Menu { get; set; }
public string MenuCategory { get; set; }
public double MenuOrder { get; set; }
}
#endregion
}

2
ILSpy/GacInterop.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.ILSpy @@ -28,7 +28,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Interop with the .NET GAC.
/// </summary>
public static class GacInterop
static class GacInterop
{
/// <summary>
/// Gets the names of all assemblies in the GAC.

4
ILSpy/GuessFileType.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.ILSpy @@ -12,7 +12,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Static methods for determining the type of a file.
/// </summary>
public static class GuessFileType
static class GuessFileType
{
public static FileType DetectFileType(Stream stream)
{
@ -120,7 +120,7 @@ namespace ICSharpCode.ILSpy @@ -120,7 +120,7 @@ namespace ICSharpCode.ILSpy
}
}
public enum FileType
enum FileType
{
Binary,
Text,

5
ILSpy/ILAstLanguage.cs

@ -20,11 +20,10 @@ using System; @@ -20,11 +20,10 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Decompiler;
using Decompiler.ControlFlow;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;

7
ILSpy/ILSpy.csproj

@ -56,6 +56,9 @@ @@ -56,6 +56,9 @@
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
@ -86,11 +89,12 @@ @@ -86,11 +89,12 @@
<Compile Include="AssemblyList.cs" />
<Compile Include="AssemblyListManager.cs" />
<Compile Include="BamlDecompiler.cs" />
<Compile Include="Commands\RoutedUICommands.cs" />
<Compile Include="Commands.cs" />
<Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" />
<Compile Include="CSharpLanguage.cs" />
<Compile Include="DecompilationOptions.cs" />
<Compile Include="ExportCommandAttribute.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="FilterSettings.cs" />
<Compile Include="Fusion.cs" />
@ -157,6 +161,7 @@ @@ -157,6 +161,7 @@
<Compile Include="TreeNodes\ReferenceFolderTreeNode.cs" />
<Compile Include="TreeNodes\ResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceListTreeNode.cs" />
<Compile Include="TreeNodes\ResourceTreeNode.cs" />
<Compile Include="TreeNodes\ThreadingSupport.cs" />
<Compile Include="TreeNodes\TypeTreeNode.cs" />
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />

12
ILSpy/Images/Images.cs

@ -68,5 +68,17 @@ namespace ICSharpCode.ILSpy @@ -68,5 +68,17 @@ namespace ICSharpCode.ILSpy
public static readonly BitmapImage Delete = LoadBitmap("Delete");
public static readonly BitmapImage Search = LoadBitmap("Search");
public static BitmapImage LoadImage(object part, string icon)
{
Uri uri;
if (part.GetType().Assembly == typeof(Images).Assembly)
uri = new Uri("pack://application:,,,/" + icon);
else
throw new NotImplementedException();
BitmapImage image = new BitmapImage(uri);
image.Freeze();
return image;
}
}
}

25
ILSpy/Language.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -121,19 +122,29 @@ namespace ICSharpCode.ILSpy @@ -121,19 +122,29 @@ namespace ICSharpCode.ILSpy
public static class Languages
{
static ReadOnlyCollection<Language> allLanguages;
/// <summary>
/// A list of all languages.
/// </summary>
public static readonly ReadOnlyCollection<Language> AllLanguages = new List<Language>(
new Language[] {
new CSharpLanguage(),
new ILLanguage(true)
public static ReadOnlyCollection<Language> AllLanguages {
get {
return allLanguages;
}
}
internal static void Initialize(CompositionContainer composition)
{
List<Language> languages = new List<Language>();
languages.AddRange(composition.GetExportedValues<Language>());
languages.Add(new ILLanguage(true));
#if DEBUG
.Concat(ILAstLanguage.GetDebugLanguages())
.Concat(CSharpLanguage.GetDebugLanguages())
languages.AddRange(ILAstLanguage.GetDebugLanguages());
languages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif
).AsReadOnly();
allLanguages = languages.AsReadOnly();
}
/// <summary>
/// Gets a language using its name.

2
ILSpy/LoadedAssembly.cs

@ -14,7 +14,7 @@ namespace ICSharpCode.ILSpy @@ -14,7 +14,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Represents an assembly loaded into ILSpy.
/// </summary>
sealed class LoadedAssembly
public sealed class LoadedAssembly
{
readonly Task<AssemblyDefinition> assemblyTask;
readonly AssemblyList assemblyList;

122
ILSpy/MainWindow.xaml

@ -1,11 +1,10 @@ @@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="ICSharpCode.ILSpy.MainWindow"
x:ClassModifier="internal"
x:ClassModifier="public"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView"
xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:textView="clr-namespace:ICSharpCode.ILSpy.TextView"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:routedCommands="clr-namespace:ICSharpCode.ILSpy.Commands"
Title="ILSpy"
MinWidth="250"
MinHeight="200"
@ -17,30 +16,6 @@ @@ -17,30 +16,6 @@
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="routedCommands:RoutedUICommands.DebugExecutable"
Executed="DebugExecutableExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.RemoveAllBreakpoint"
Executed="RemoveAllBreakpointExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.AttachToProcess"
Executed="AttachToProcessExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.DetachFromProcess"
Executed="DetachFromProcessExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.ContinueDebugging"
Executed="ContinueDebuggingExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.StepInto"
Executed="StepIntoExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.StepOver"
Executed="StepOverExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.StepOut"
Executed="StepOutExecuted" />
<CommandBinding
Command="Open"
Executed="OpenCommandExecuted" />
@ -58,28 +33,8 @@ @@ -58,28 +33,8 @@
</Window.CommandBindings>
<DockPanel>
<!-- Main menu -->
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="Open">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="Images/Open.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Open from _GAC" Click="OpenFromGac_Click" />
<MenuItem Command="Refresh" Header="_Reload">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="Images/Refresh.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="_Save Code" Click="saveCode_Click">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="Images/SaveFile.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="E_xit" Click="ExitClick" />
</MenuItem>
<Menu DockPanel.Dock="Top" Name="mainMenu">
<MenuItem Header="_File" /> <!-- contents of file menu are added using MEF -->
<MenuItem Header="_View">
<MenuItem Header="Show _internal types and members" IsCheckable="True" IsChecked="{Binding FilterSettings.ShowInternalApi}">
<MenuItem.Icon>
@ -88,52 +43,6 @@ @@ -88,52 +43,6 @@
</MenuItem>
<MenuItem Header="Show _analyzer" Name="showAnalyzer" IsCheckable="True" Checked="ShowAnalyzer_Checked" Unchecked="ShowAnalyzer_Unchecked" />
</MenuItem>
<MenuItem Header="_Debugger">
<MenuItem x:Name="AttachMenuItem" Header="Attach to _running application" Command="routedCommands:RoutedUICommands.AttachToProcess">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/bug.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="ContinueDebuggingMenuItem" IsEnabled="False" Header="Continue debugging" InputGestureText="F5" Command="routedCommands:RoutedUICommands.ContinueDebugging">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/ContinueDebugging.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="StepIntoMenuItem" IsEnabled="False" Header="Step into" InputGestureText="F11" Command="routedCommands:RoutedUICommands.StepInto">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/StepInto.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="StepOverMenuItem" IsEnabled="False" Header="Step over" InputGestureText="F10" Command="routedCommands:RoutedUICommands.StepOver">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/StepOver.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="StepOutMenuItem" IsEnabled="False" Header="Step out" Command="routedCommands:RoutedUICommands.StepOut">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/StepOut.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="DetachMenuItem" IsEnabled="False"
Header="Detach from running application"
Command="routedCommands:RoutedUICommands.DetachFromProcess"/>
<Separator/>
<MenuItem x:Name="RemoveAllBreakpointsItem" Header="Remove all breakpoints" Command="routedCommands:RoutedUICommands.RemoveAllBreakpoint">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/DeleteAllBreakpoints.png" />
</MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem x:Name="DebugExecutableItem" Header="Debug an executable" Command="routedCommands:RoutedUICommands.DebugExecutable">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/application-x-executable.png" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" Click="AboutClick" />
</MenuItem>
</Menu>
<!-- ToolBar -->
<ToolBar
@ -151,19 +60,9 @@ @@ -151,19 +60,9 @@
</Style.Triggers>
</Style>
</ToolBar.Resources>
<Button Command="BrowseBack" ToolTip="Back">
<Image Width="16" Height="16" Source="Images/Back.png" />
</Button>
<Button Command="BrowseForward" ToolTip="Forward">
<Image Width="16" Height="16" Source="Images/Forward.png" />
</Button>
<!-- 'Navigation' toolbar category is inserted here -->
<Separator />
<Button Command="Open" ToolTip="Open">
<Image Width="16" Height="16" Source="Images/Open.png" />
</Button>
<Button Command="Refresh" ToolTip="Reload all assemblies">
<Image Width="16" Height="16" Source="Images/Refresh.png" />
</Button>
<!-- 'Open' toolbar category is inserted here -->
<Separator />
<CheckBox IsChecked="{Binding FilterSettings.ShowInternalApi}" ToolTip="Show internal types and members">
<Image Width="16" Height="16" Source="Images/PrivateInternal.png" />
@ -174,13 +73,6 @@ @@ -174,13 +73,6 @@
SelectedItem="{Binding FilterSettings.Language}"
SelectionChanged="LanguageComboBox_SelectionChanged"
/>
<Separator />
<Button x:Name="AttachButton" Command="routedCommands:RoutedUICommands.AttachToProcess" ToolTip="Attach to running process...">
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/bug.png" />
</Button>
<Button x:Name="DebugExecutableButton" Command="routedCommands:RoutedUICommands.DebugExecutable" ToolTip="Debug an executable">
<Image Width="16" Height="16" Source="pack://application:,,,/ILSpy.Debugger;component/Images/application-x-executable.png" />
</Button>
</ToolBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<Grid>
@ -222,7 +114,7 @@ @@ -222,7 +114,7 @@
VerticalAlignment="Stretch"
BorderBrush="Transparent" />
<!-- Right pane: Text Editor -->
<Grid Grid.Column="2">
<Grid Grid.Column="2" Name="rightPane">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="*" />
@ -243,7 +135,7 @@ @@ -243,7 +135,7 @@
</DockPanel>
</Border>
<textView:DecompilerTextView x:Name="decompilerTextView" Grid.Row="1" />
<!-- decompilerTextView is inserted into row 1 by code -->
<GridSplitter
Grid.ZIndex="1"

346
ILSpy/MainWindow.xaml.cs

@ -18,8 +18,10 @@ @@ -18,8 +18,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
@ -31,6 +33,7 @@ using System.Windows.Media.Imaging; @@ -31,6 +33,7 @@ using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using ICSharpCode.TreeView;
@ -56,6 +59,9 @@ namespace ICSharpCode.ILSpy @@ -56,6 +59,9 @@ namespace ICSharpCode.ILSpy
AssemblyList assemblyList;
AssemblyListTreeNode assemblyListTreeNode;
[Import]
DecompilerTextView decompilerTextView = null;
static MainWindow instance;
public static MainWindow Instance {
@ -83,7 +89,9 @@ namespace ICSharpCode.ILSpy @@ -83,7 +89,9 @@ namespace ICSharpCode.ILSpy
this.WindowState = sessionSettings.WindowState;
InitializeComponent();
decompilerTextView.mainWindow = this;
App.CompositionContainer.ComposeParts(this);
Grid.SetRow(decompilerTextView, 1);
rightPane.Children.Add(decompilerTextView);
if (sessionSettings.SplitterPosition > 0 && sessionSettings.SplitterPosition < 1) {
leftColumn.Width = new GridLength(sessionSettings.SplitterPosition, GridUnitType.Star);
@ -91,9 +99,89 @@ namespace ICSharpCode.ILSpy @@ -91,9 +99,89 @@ namespace ICSharpCode.ILSpy
}
sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged;
InitMainMenu();
InitToolbar();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
#region Toolbar extensibility
[ImportMany("ToolbarCommand", typeof(ICommand))]
Lazy<ICommand, IToolbarCommandMetadata>[] toolbarCommands = null;
void InitToolbar()
{
int navigationPos = 0;
int openPos = 1;
foreach (var commandGroup in toolbarCommands.OrderBy(c => c.Metadata.ToolbarOrder).GroupBy(c => c.Metadata.ToolbarCategory)) {
if (commandGroup.Key == "Navigation") {
foreach (var command in commandGroup) {
toolBar.Items.Insert(navigationPos++, MakeToolbarItem(command));
openPos++;
}
} else if (commandGroup.Key == "Open") {
foreach (var command in commandGroup) {
toolBar.Items.Insert(openPos++, MakeToolbarItem(command));
}
} else {
toolBar.Items.Add(new Separator());
foreach (var command in commandGroup) {
toolBar.Items.Add(MakeToolbarItem(command));
}
}
}
}
Button MakeToolbarItem(Lazy<ICommand, IToolbarCommandMetadata> command)
{
return new Button {
Command = CommandWrapper.Unwrap(command.Value),
ToolTip = command.Metadata.ToolTip,
Content = new Image {
Width = 16,
Height = 16,
Source = Images.LoadImage(command.Value, command.Metadata.ToolbarIcon)
}
};
}
#endregion
#region Main Menu extensibility
[ImportMany("MainMenuCommand", typeof(ICommand))]
Lazy<ICommand, IMainMenuCommandMetadata>[] mainMenuCommands = null;
void InitMainMenu()
{
foreach (var topLevelMenu in mainMenuCommands.OrderBy(c => c.Metadata.MenuOrder).GroupBy(c => c.Metadata.Menu)) {
var topLevelMenuItem = mainMenu.Items.OfType<MenuItem>().FirstOrDefault(m => (m.Header as string) == topLevelMenu.Key);
foreach (var category in topLevelMenu.GroupBy(c => c.Metadata.MenuCategory)) {
if (topLevelMenuItem == null) {
topLevelMenuItem = new MenuItem();
topLevelMenuItem.Header = topLevelMenu.Key;
mainMenu.Items.Add(topLevelMenuItem);
} else if (topLevelMenuItem.Items.Count > 0) {
topLevelMenuItem.Items.Add(new Separator());
}
foreach (var entry in category) {
MenuItem menuItem = new MenuItem();
menuItem.Command = CommandWrapper.Unwrap(entry.Value);
if (!string.IsNullOrEmpty(entry.Metadata.Header))
menuItem.Header = entry.Metadata.Header;
if (!string.IsNullOrEmpty(entry.Metadata.MenuIcon)) {
menuItem.Icon = new Image {
Width = 16,
Height = 16,
Source = Images.LoadImage(entry.Value, entry.Metadata.MenuIcon)
};
}
topLevelMenuItem.Items.Add(menuItem);
}
}
}
}
#endregion
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
ILSpySettings spySettings = this.spySettings;
@ -307,20 +395,19 @@ namespace ICSharpCode.ILSpy @@ -307,20 +395,19 @@ namespace ICSharpCode.ILSpy
}
}
void OpenFiles(string[] fileNames, bool focusNode = true)
public void OpenFiles(string[] fileNames)
{
if (focusNode) {
treeView.UnselectAll();
SharpTreeNode lastNode = null;
foreach (string file in fileNames) {
var asm = assemblyList.OpenAssembly(file);
if (asm != null) {
var node = assemblyListTreeNode.FindAssemblyNode(asm);
if (node != null) {
treeView.SelectedItems.Add(node);
lastNode = node;
}
if (fileNames == null)
throw new ArgumentNullException("fileNames");
treeView.UnselectAll();
SharpTreeNode lastNode = null;
foreach (string file in fileNames) {
var asm = assemblyList.OpenAssembly(file);
if (asm != null) {
var node = assemblyListTreeNode.FindAssemblyNode(asm);
if (node != null) {
treeView.SelectedItems.Add(node);
lastNode = node;
}
}
if (lastNode != null)
@ -328,18 +415,9 @@ namespace ICSharpCode.ILSpy @@ -328,18 +415,9 @@ namespace ICSharpCode.ILSpy
}
}
void OpenFromGac_Click(object sender, RoutedEventArgs e)
{
OpenFromGacDialog dlg = new OpenFromGacDialog();
dlg.Owner = this;
if (dlg.ShowDialog() == true) {
OpenFiles(dlg.SelectedFileNames);
}
}
void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (!DebuggerService.CurrentDebugger.IsDebugging) {
if (!System.Diagnostics.Debugger.IsAttached) {
e.Handled = true;
var path = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
ShowAssemblyList(assemblyListManager.LoadList(ILSpySettings.Load(), assemblyList.ListName));
@ -349,197 +427,7 @@ namespace ICSharpCode.ILSpy @@ -349,197 +427,7 @@ namespace ICSharpCode.ILSpy
#endregion
#region Debugger commands
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static void SendWpfWindowPos(Window window, IntPtr place)
{
var hWnd = new WindowInteropHelper(window).Handle;
SetWindowPos(hWnd, place, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
}
IDebugger CurrentDebugger {
get {
return DebuggerService.CurrentDebugger;
}
}
void StartDebugging(Process process)
{
CurrentDebugger.Attach(process);
EnableDebuggerUI(false);
CurrentDebugger.DebugStopped += OnDebugStopped;
CurrentDebugger.IsProcessRunningChanged += CurrentDebugger_IsProcessRunningChanged;
}
void CurrentDebugger_IsProcessRunningChanged(object sender, EventArgs e)
{
if (CurrentDebugger.IsProcessRunning) {
//SendWpfWindowPos(this, HWND_BOTTOM);
return;
}
// breakpoint was hit => bring to front the main window
SendWpfWindowPos(this, HWND_TOP);
this.Activate();
// jump to type & expand folding
if (CurrentLineBookmark.Instance != null) {
if (CurrentLineBookmark.Instance.Type != DebuggedData.CurrentType)
JumpToReference(CurrentLineBookmark.Instance.Type);
decompilerTextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber);
}
}
void DebugExecutableExecuted(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog() {
Filter = ".NET Executable (*.exe) | *.exe",
RestoreDirectory = true,
DefaultExt = "exe"
};
if (dialog.ShowDialog() == true) {
string fileName = dialog.FileName;
// add it to references
OpenFiles(new [] { fileName }, false);
if (!CurrentDebugger.IsDebugging) {
// execute the process
this.StartDebugging(Process.Start(fileName));
}
}
}
void AttachToProcessExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (!CurrentDebugger.IsDebugging) {
var window = new AttachToProcessWindow { Owner = this };
if (window.ShowDialog() == true) {
this.StartDebugging(window.SelectedProcess);
}
}
}
void OnDebugStopped(object sender, EventArgs e)
{
EnableDebuggerUI(true);
CurrentDebugger.DebugStopped -= OnDebugStopped;
CurrentDebugger.IsProcessRunningChanged -= CurrentDebugger_IsProcessRunningChanged;
}
void DetachFromProcessExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (CurrentDebugger.IsDebugging){
CurrentDebugger.Detach();
EnableDebuggerUI(true);
CurrentDebugger.DebugStopped -= OnDebugStopped;
}
}
void ContinueDebuggingExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning)
CurrentDebugger.Continue();
}
void StepIntoExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning)
CurrentDebugger.StepInto();
}
void StepOverExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning)
CurrentDebugger.StepOver();
}
void StepOutExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning)
CurrentDebugger.StepOut();
}
void RemoveAllBreakpointExecuted(object sender, ExecutedRoutedEventArgs e)
{
for (int i = BookmarkManager.Bookmarks.Count - 1; i >= 0; --i) {
var bookmark = BookmarkManager.Bookmarks[i];
if (bookmark is BreakpointBookmark) {
BookmarkManager.RemoveMark(bookmark);
}
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
switch (e.Key) {
case Key.F5:
ContinueDebuggingExecuted(null, null);
e.Handled = true;
break;
case Key.System:
StepOverExecuted(null, null);
e.Handled = true;
break;
case Key.F11:
StepIntoExecuted(null, null);
e.Handled = true;
break;
default:
// do nothing
break;
}
base.OnKeyUp(e);
}
void EnableDebuggerUI(bool enable)
{
AttachMenuItem.IsEnabled = AttachButton.IsEnabled = enable;
DebugExecutableButton.IsEnabled = DebugExecutableItem.IsEnabled = enable;
ContinueDebuggingMenuItem.IsEnabled =
StepIntoMenuItem.IsEnabled =
StepOverMenuItem.IsEnabled =
StepOutMenuItem.IsEnabled =
DetachMenuItem.IsEnabled = !enable;
}
#endregion
#region Exit/About
void ExitClick(object sender, RoutedEventArgs e)
{
Close();
}
void AboutClick(object sender, RoutedEventArgs e)
{
treeView.UnselectAll();
AboutPage.Display(decompilerTextView);
}
#endregion
#region Decompile / Save
#region Decompile (TreeView_SelectionChanged)
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (treeView.SelectedItems.Count == 1) {
@ -547,21 +435,23 @@ namespace ICSharpCode.ILSpy @@ -547,21 +435,23 @@ namespace ICSharpCode.ILSpy
if (node != null && node.View(decompilerTextView))
return;
}
decompilerTextView.Decompile(sessionSettings.FilterSettings.Language,
treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>(),
new DecompilationOptions());
decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions());
}
void saveCode_Click(object sender, RoutedEventArgs e)
{
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
if (node != null && node.Save(decompilerTextView))
return;
public DecompilerTextView TextView {
get { return decompilerTextView; }
}
public Language CurrentLanguage {
get {
return sessionSettings.FilterSettings.Language;
}
}
public IEnumerable<ILSpyTreeNode> SelectedNodes {
get {
return treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>();
}
decompilerTextView.SaveToDisk(sessionSettings.FilterSettings.Language,
treeView.GetTopLevelSelection().OfType<ILSpyTreeNode>(),
new DecompilationOptions() { FullDecompilation = true });
}
#endregion

2
ILSpy/NavigationHistory.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.ILSpy @@ -10,7 +10,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Stores the navigation history.
/// </summary>
public class NavigationHistory
sealed class NavigationHistory
{
List<SharpTreeNode> back = new List<SharpTreeNode>();
List<SharpTreeNode> forward = new List<SharpTreeNode>();

2
ILSpy/Properties/AssemblyInfo.template.cs

@ -14,7 +14,7 @@ using System.Runtime.InteropServices; @@ -14,7 +14,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyDescription(".NET assembly inspector and decompiler")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPara for the SharpDevelop Team")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

11
ILSpy/TextView/AvalonEditTextOutput.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -62,7 +62,7 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>
/// Text output implementation for AvalonEdit.
/// </summary>
sealed class AvalonEditTextOutput : ISmartTextOutput
public sealed class AvalonEditTextOutput : ISmartTextOutput
{
readonly StringBuilder b = new StringBuilder();
@ -78,13 +78,12 @@ namespace ICSharpCode.ILSpy.TextView @@ -78,13 +78,12 @@ namespace ICSharpCode.ILSpy.TextView
Stack<NewFolding> openFoldings = new Stack<NewFolding>();
/// <summary>List of all foldings that were written to the output</summary>
public readonly List<NewFolding> Foldings = new List<NewFolding>();
internal readonly List<NewFolding> Foldings = new List<NewFolding>();
public readonly DefinitionLookup DefinitionLookup = new DefinitionLookup();
internal readonly DefinitionLookup DefinitionLookup = new DefinitionLookup();
/// <summary>Embedded UIElements, see <see cref="UIElementGenerator"/>.</summary>
public readonly List<KeyValuePair<int, Lazy<UIElement>>> UIElements = new List<KeyValuePair<int, Lazy<UIElement>>>();
internal readonly List<KeyValuePair<int, Lazy<UIElement>>> UIElements = new List<KeyValuePair<int, Lazy<UIElement>>>();
public AvalonEditTextOutput()
{
@ -94,7 +93,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -94,7 +93,7 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>
/// Gets the list of references (hyperlinks).
/// </summary>
public TextSegmentCollection<ReferenceSegment> References {
internal TextSegmentCollection<ReferenceSegment> References {
get { return references; }
}

7
ILSpy/TextView/DecompilerTextView.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@ -54,12 +55,12 @@ namespace ICSharpCode.ILSpy.TextView @@ -54,12 +55,12 @@ namespace ICSharpCode.ILSpy.TextView
/// Manages the TextEditor showing the decompiled code.
/// Contains all the threading logic that makes the decompiler work in the background.
/// </summary>
sealed partial class DecompilerTextView : UserControl
[Export, PartCreationPolicy(CreationPolicy.Shared)]
public sealed partial class DecompilerTextView : UserControl
{
readonly ReferenceElementGenerator referenceElementGenerator;
readonly UIElementGenerator uiElementGenerator;
FoldingManager foldingManager;
internal MainWindow mainWindow;
DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource;
@ -515,7 +516,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -515,7 +516,7 @@ namespace ICSharpCode.ILSpy.TextView
return;
}
}
mainWindow.JumpToReference(reference);
MainWindow.Instance.JumpToReference(reference);
}
/// <summary>

2
ILSpy/TextView/DecompilerTextView.xaml

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<UserControl x:Class="ICSharpCode.ILSpy.TextView.DecompilerTextView" x:ClassModifier="internal" x:Name="self"
<UserControl x:Class="ICSharpCode.ILSpy.TextView.DecompilerTextView" x:ClassModifier="public" x:Name="self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit">

2
ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs

@ -22,7 +22,7 @@ using ICSharpCode.TreeView; @@ -22,7 +22,7 @@ using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzerTreeNode : SharpTreeNode
public class AnalyzerTreeNode : SharpTreeNode
{
Language language;

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// Tree node representing an assembly.
/// This class is responsible for loading both namespace and type nodes.
/// </summary>
sealed class AssemblyTreeNode : ILSpyTreeNode
public sealed class AssemblyTreeNode : ILSpyTreeNode
{
readonly LoadedAssembly assembly;
readonly List<TypeTreeNode> classes = new List<TypeTreeNode>();

2
ILSpy/TreeNodes/EventTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Represents an event in the TreeView.
/// </summary>
sealed class EventTreeNode : ILSpyTreeNode
public sealed class EventTreeNode : ILSpyTreeNode
{
readonly EventDefinition ev;

2
ILSpy/TreeNodes/FieldTreeNode.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Represents a field in the TreeView.
/// </summary>
sealed class FieldTreeNode : ILSpyTreeNode
public sealed class FieldTreeNode : ILSpyTreeNode
{
readonly FieldDefinition field;

4
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Base class of all ILSpy tree nodes.
/// </summary>
abstract class ILSpyTreeNode : SharpTreeNode
public abstract class ILSpyTreeNode : SharpTreeNode
{
FilterSettings filterSettings;
bool childrenNeedFiltering;
@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
enum FilterResult
public enum FilterResult
{
/// <summary>
/// Hides the node.

2
ILSpy/TreeNodes/MethodTreeNode.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Tree Node representing a field, method, property, or event.
/// </summary>
sealed class MethodTreeNode : ILSpyTreeNode
public sealed class MethodTreeNode : ILSpyTreeNode
{
MethodDefinition method;

2
ILSpy/TreeNodes/NamespaceTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Namespace node. The loading of the type nodes is handled by the parent AssemblyTreeNode.
/// </summary>
sealed class NamespaceTreeNode : ILSpyTreeNode
public sealed class NamespaceTreeNode : ILSpyTreeNode
{
string name;

2
ILSpy/TreeNodes/PropertyTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Represents a property in the TreeView.
/// </summary>
sealed class PropertyTreeNode : ILSpyTreeNode
public sealed class PropertyTreeNode : ILSpyTreeNode
{
readonly PropertyDefinition property;
readonly bool isIndexer;

149
ILSpy/TreeNodes/ResourceEntryNode.cs

@ -6,20 +6,24 @@ using System.IO; @@ -6,20 +6,24 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.ComponentModel.Composition;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
{
class ResourceEntryNode : ILSpyTreeNode
/// <summary>
/// Entry in a .resources file
/// </summary>
public class ResourceEntryNode : ILSpyTreeNode
{
string key;
Stream value;
protected readonly string key;
protected readonly Stream data;
public override object Text {
get { return key.ToString(); }
@ -29,106 +33,93 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -29,106 +33,93 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return Images.Resource; }
}
public ResourceEntryNode(string key, Stream value)
public ResourceEntryNode(string key, Stream data)
{
if (key == null)
throw new ArgumentNullException("key");
if (data == null)
throw new ArgumentNullException("data");
this.key = key;
this.value = value;
this.data = data;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
public static ILSpyTreeNode Create(string key, Stream data)
{
language.WriteCommentLine(output, string.Format("{0} = {1}", key, value));
ILSpyTreeNode result = null;
foreach (var factory in App.CompositionContainer.GetExportedValues<IResourceNodeFactory>()) {
result = factory.CreateNode(key, data);
if (result != null)
break;
}
return result ?? new ResourceEntryNode(key, data);
}
internal override bool View(DecompilerTextView textView)
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
AvalonEditTextOutput output = new AvalonEditTextOutput();
IHighlightingDefinition highlighting = null;
if (LoadImage(output)) {
textView.Show(output, highlighting);
} else {
textView.RunWithCancellation(
token => Task.Factory.StartNew(
() => {
try {
if (LoadBaml(output))
highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml");
} catch (Exception ex) {
output.Write(ex.ToString());
}
return output;
}),
t => textView.Show(t.Result, highlighting)
);
}
return true;
language.WriteCommentLine(output, string.Format("{0} = {1}", key, data));
}
bool LoadImage(AvalonEditTextOutput output)
public override bool Save(DecompilerTextView textView)
{
try {
value.Position = 0;
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = value;
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(null); });
} catch (Exception) {
return false;
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key));
if (dlg.ShowDialog() == true) {
data.Position = 0;
using (var fs = dlg.OpenFile()) {
data.CopyTo(fs);
}
}
return true;
}
}
[Export(typeof(IResourceNodeFactory))]
sealed class ImageResourceNodeFactory : IResourceNodeFactory
{
static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" };
bool LoadBaml(AvalonEditTextOutput output)
public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource)
{
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
AppDomain bamlDecompilerAppDomain = null;
try {
BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName);
MemoryStream bamlStream = new MemoryStream();
value.Position = 0;
value.CopyTo(bamlStream);
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName));
return true;
} finally {
if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain);
EmbeddedResource er = resource as EmbeddedResource;
if (er != null) {
return CreateNode(er.Name, er.GetResourceStream());
}
return null;
}
public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName)
public ILSpyTreeNode CreateNode(string key, Stream data)
{
if (appDomain == null) {
// Construct and initialize settings for a second AppDomain.
AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup();
bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName);
bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false;
bamlDecompilerAppDomainSetup.DisallowCodeDownload = true;
bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
// Create the second AppDomain.
appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup);
foreach (string fileExt in imageFileExtensions) {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new ImageResourceEntryNode(key, data);
}
return (BamlDecompiler)appDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName);
return null;
}
}
sealed class ImageResourceEntryNode : ResourceEntryNode
{
public ImageResourceEntryNode(string key, Stream data) : base(key, data)
{
}
public override bool Save(DecompilerTextView textView)
internal override bool View(DecompilerTextView textView)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key));
if (dlg.ShowDialog() == true) {
value.Position = 0;
using (var fs = dlg.OpenFile()) {
value.CopyTo(fs);
}
try {
AvalonEditTextOutput output = new AvalonEditTextOutput();
data.Position = 0;
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = data;
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(null); });
textView.Show(output, null);
return true;
} catch (Exception) {
return false;
}
return true;
}
}
}

108
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected override void LoadChildren()
{
foreach (Resource r in module.Resources)
this.Children.Add(new ResourceTreeNode(r));
this.Children.Add(ResourceTreeNode.Create(r));
}
public override FilterResult Filter(FilterSettings settings)
@ -63,110 +63,4 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -63,110 +63,4 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
}
class ResourceTreeNode : ILSpyTreeNode
{
Resource r;
public ResourceTreeNode(Resource r)
{
this.LazyLoading = true;
this.r = r;
}
public Resource Resource {
get { return r; }
}
public override object Text {
get { return r.Name; }
}
public override object Icon {
get { return Images.Resource; }
}
public override FilterResult Filter(FilterSettings settings)
{
if (!settings.ShowInternalApi && (r.Attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private)
return FilterResult.Hidden;
if (settings.SearchTermMatches(r.Name))
return FilterResult.Match;
else
return FilterResult.Hidden;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, string.Format("{0} ({1}, {2})", r.Name, r.ResourceType, r.Attributes));
ISmartTextOutput smartOutput = output as ISmartTextOutput;
if (smartOutput != null && r is EmbeddedResource) {
smartOutput.AddButton(Images.Save, "Save", delegate { Save(null); });
output.WriteLine();
}
}
internal override bool View(DecompilerTextView textView)
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
Stream s = er.GetResourceStream();
if (s != null && s.Length < DecompilerTextView.DefaultOutputLengthLimit) {
s.Position = 0;
FileType type = GuessFileType.DetectFileType(s);
if (type != FileType.Binary) {
s.Position = 0;
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write(FileReader.OpenStream(s, Encoding.UTF8).ReadToEnd());
string ext;
if (type == FileType.Xml)
ext = ".xml";
else
ext = Path.GetExtension(DecompilerTextView.CleanUpName(er.Name));
textView.Show(output, HighlightingManager.Instance.GetDefinitionByExtension(ext));
return true;
}
}
}
return false;
}
public override bool Save(TextView.DecompilerTextView textView)
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = DecompilerTextView.CleanUpName(er.Name);
if (dlg.ShowDialog() == true) {
Stream s = er.GetResourceStream();
s.Position = 0;
using (var fs = dlg.OpenFile()) {
s.CopyTo(fs);
}
}
return true;
}
return false;
}
protected override void LoadChildren()
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
try {
Stream s = er.GetResourceStream();
s.Position = 0;
if (er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) {
ResourceReader reader = new ResourceReader(s);
foreach (DictionaryEntry entry in reader.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) {
if (entry.Value is Stream)
Children.Add(new ResourceEntryNode(entry.Key.ToString(), (Stream)entry.Value));
}
}
} catch (ArgumentException) {
}
}
}
}
}

174
ILSpy/TreeNodes/ResourceTreeNode.cs

@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
// 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;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
{
public class ResourceTreeNode : ILSpyTreeNode
{
Resource r;
public ResourceTreeNode(Resource r)
{
if (r == null)
throw new ArgumentNullException("r");
this.r = r;
}
public Resource Resource {
get { return r; }
}
public override object Text {
get { return r.Name; }
}
public override object Icon {
get { return Images.Resource; }
}
public override FilterResult Filter(FilterSettings settings)
{
if (!settings.ShowInternalApi && (r.Attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private)
return FilterResult.Hidden;
if (settings.SearchTermMatches(r.Name))
return FilterResult.Match;
else
return FilterResult.Hidden;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, string.Format("{0} ({1}, {2})", r.Name, r.ResourceType, r.Attributes));
ISmartTextOutput smartOutput = output as ISmartTextOutput;
if (smartOutput != null && r is EmbeddedResource) {
smartOutput.AddButton(Images.Save, "Save", delegate { Save(null); });
output.WriteLine();
}
}
internal override bool View(DecompilerTextView textView)
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
Stream s = er.GetResourceStream();
if (s != null && s.Length < DecompilerTextView.DefaultOutputLengthLimit) {
s.Position = 0;
FileType type = GuessFileType.DetectFileType(s);
if (type != FileType.Binary) {
s.Position = 0;
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write(FileReader.OpenStream(s, Encoding.UTF8).ReadToEnd());
string ext;
if (type == FileType.Xml)
ext = ".xml";
else
ext = Path.GetExtension(DecompilerTextView.CleanUpName(er.Name));
textView.Show(output, HighlightingManager.Instance.GetDefinitionByExtension(ext));
return true;
}
}
}
return false;
}
public override bool Save(TextView.DecompilerTextView textView)
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = DecompilerTextView.CleanUpName(er.Name);
if (dlg.ShowDialog() == true) {
Stream s = er.GetResourceStream();
s.Position = 0;
using (var fs = dlg.OpenFile()) {
s.CopyTo(fs);
}
}
return true;
}
return false;
}
public static ILSpyTreeNode Create(Resource resource)
{
ILSpyTreeNode result = null;
foreach (var factory in App.CompositionContainer.GetExportedValues<IResourceNodeFactory>()) {
result = factory.CreateNode(resource);
if (result != null)
break;
}
return result ?? new ResourceTreeNode(resource);
}
}
/// <summary>
/// This interface allows plugins to create custom nodes for resources.
/// </summary>
public interface IResourceNodeFactory
{
ILSpyTreeNode CreateNode(Resource resource);
ILSpyTreeNode CreateNode(string key, Stream data);
}
[Export(typeof(IResourceNodeFactory))]
sealed class ResourcesFileTreeNodeFactory : IResourceNodeFactory
{
public ILSpyTreeNode CreateNode(Resource resource)
{
EmbeddedResource er = resource as EmbeddedResource;
if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) {
return new ResourcesFileTreeNode(er);
}
return null;
}
public ILSpyTreeNode CreateNode(string key, Stream data)
{
return null;
}
}
sealed class ResourcesFileTreeNode : ResourceTreeNode
{
public ResourcesFileTreeNode(EmbeddedResource er) : base(er)
{
this.LazyLoading = true;
}
protected override void LoadChildren()
{
EmbeddedResource er = this.Resource as EmbeddedResource;
if (er != null) {
Stream s = er.GetResourceStream();
s.Position = 0;
ResourceReader reader;
try {
reader = new ResourceReader(s);
} catch (ArgumentException) {
return;
}
foreach (DictionaryEntry entry in reader.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) {
if (entry.Value is Stream)
Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value));
}
}
}
}
}

2
ILSpy/TreeNodes/TypeTreeNode.cs

@ -28,7 +28,7 @@ using Mono.Cecil; @@ -28,7 +28,7 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
{
sealed class TypeTreeNode : ILSpyTreeNode
public sealed class TypeTreeNode : ILSpyTreeNode
{
readonly TypeDefinition type;
readonly AssemblyTreeNode parentAssemblyNode;

2
Mono.Cecil/Mono.Cecil/PInvokeAttributes.cs

@ -53,7 +53,7 @@ namespace Mono.Cecil { @@ -53,7 +53,7 @@ namespace Mono.Cecil {
BestFitMask = 0x0030,
BestFitEnabled = 0x0010,
BestFidDisabled = 0x0020,
BestFitDisabled = 0x0020,
ThrowOnUnmappableCharMask = 0x3000,
ThrowOnUnmappableCharEnabled = 0x1000,

8
Mono.Cecil/Mono.Cecil/PInvokeInfo.cs

@ -106,14 +106,14 @@ namespace Mono.Cecil { @@ -106,14 +106,14 @@ namespace Mono.Cecil {
set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.CallConvMask, (ushort) PInvokeAttributes.CallConvFastcall, value); }
}
public bool IsBestFistEnabled {
public bool IsBestFitEnabled {
get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitEnabled); }
set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitEnabled, value); }
}
public bool IsBestFistDisabled {
get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFidDisabled); }
set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFidDisabled, value); }
public bool IsBestFitDisabled {
get { return attributes.GetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitDisabled); }
set { attributes = attributes.SetMaskedAttributes ((ushort) PInvokeAttributes.BestFitMask, (ushort) PInvokeAttributes.BestFitDisabled, value); }
}
public bool IsThrowOnUnmappableCharEnabled {

Loading…
Cancel
Save