Browse Source

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

pull/219/head
Eusebiu Marcu 14 years ago
parent
commit
0459bac40d
  1. 1
      AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
  2. 286
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  3. 17
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  4. 2
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  5. 15
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  6. 56
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  7. 58
      ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs
  8. 15
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  9. 127
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  10. 7
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  11. 1
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  12. 250
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  13. 6
      ICSharpCode.Decompiler/Disassembler/ILStructure.cs
  14. 84
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  15. 692
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  16. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  17. 10
      ICSharpCode.Decompiler/ILAst/GotoRemoval.cs
  18. 46
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  19. 21
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  20. 18
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  21. 32
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  22. 4
      ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs
  23. 75
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  24. 107
      ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
  25. 4
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  26. 75
      ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
  27. 30
      ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
  28. 6
      ICSharpCode.Decompiler/Tests/Generics.cs
  29. 2
      ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
  30. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  31. 6
      ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
  32. 87
      ICSharpCode.Decompiler/Tests/PInvoke.cs
  33. 14
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  34. 61
      ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
  35. 29
      ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
  36. 124
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  37. 31
      ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs
  38. 172
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs
  39. 112
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs
  40. 47
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs
  41. 80
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs
  42. 72
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlRecordType.cs
  43. 58
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs
  44. 14
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IDependencyPropertyDescriptor.cs
  45. 19
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs
  46. 15
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs
  47. 1319
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs
  48. 58
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/PropertyDeclaration.cs
  49. 32
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ResourceName.cs
  50. 137
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
  51. 35
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs
  52. 193
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs
  53. 21
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlNode.cs
  54. 86
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs
  55. 48
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs
  56. 1943
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
  57. 33
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlText.cs
  58. 47
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlNamespace.cs
  59. 63
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs
  60. 12
      ILSpy.sln
  61. 4
      ILSpy/AboutPage.cs
  62. 2
      ILSpy/App.xaml.cs
  63. 445
      ILSpy/BamlDecompiler.cs
  64. 231
      ILSpy/CSharpLanguage.cs
  65. 2
      ILSpy/Commands.cs
  66. 19
      ILSpy/ConnectMethodDecompiler.cs
  67. 93
      ILSpy/DisplaySettings.cs
  68. 64
      ILSpy/DisplaySettingsPanel.xaml
  69. 154
      ILSpy/DisplaySettingsPanel.xaml.cs
  70. 4
      ILSpy/ILAstLanguage.cs
  71. 50
      ILSpy/ILLanguage.cs
  72. 13
      ILSpy/ILSpy.csproj
  73. 21
      ILSpy/ILSpySettings.cs
  74. 5
      ILSpy/Images/Images.cs
  75. BIN
      ILSpy/Images/StaticClass.png
  76. 3
      ILSpy/Images/TypeIcon.cs
  77. 76
      ILSpy/Language.cs
  78. 15
      ILSpy/MainWindow.xaml.cs
  79. 12
      ILSpy/NavigationHistory.cs
  80. 10
      ILSpy/NavigationState.cs
  81. 29
      ILSpy/TextView/DecompilerTextView.cs
  82. 1
      ILSpy/TextView/ILAsm-Mode.xshd
  83. 43
      ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs
  84. 33
      ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
  85. 17
      ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
  86. 34
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
  87. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
  88. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
  89. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
  90. 51
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
  91. 8
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  92. 28
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  93. 43
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs
  94. 40
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
  95. 13
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
  96. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
  97. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
  98. 4
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  99. 151
      ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs
  100. 63
      ILSpy/TreeNodes/Analyzer/Helpers.cs
  101. Some files were not shown because too many files have changed in this diff Show More

1
AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -215,6 +215,7 @@
<Compile Include="Indentation\CSharp\DocumentAccessor.cs" /> <Compile Include="Indentation\CSharp\DocumentAccessor.cs" />
<Compile Include="Indentation\DefaultIndentationStrategy.cs" /> <Compile Include="Indentation\DefaultIndentationStrategy.cs" />
<Compile Include="Indentation\IIndentationStrategy.cs" /> <Compile Include="Indentation\IIndentationStrategy.cs" />
<Compile Include="Properties\GlobalAssemblyInfo.cs" />
<Compile Include="Rendering\BackgroundGeometryBuilder.cs"> <Compile Include="Rendering\BackgroundGeometryBuilder.cs">
<DependentUpon>IBackgroundRenderer.cs</DependentUpon> <DependentUpon>IBackgroundRenderer.cs</DependentUpon>
</Compile> </Compile>

286
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -28,7 +28,8 @@ namespace ICSharpCode.Decompiler.Ast
{ {
None = 0, None = 0,
IncludeNamespace = 1, IncludeNamespace = 1,
IncludeTypeParameterDefinitions = 2 IncludeTypeParameterDefinitions = 2,
DoNotUsePrimitiveTypeNames = 4
} }
public class AstBuilder : BaseCodeMappings public class AstBuilder : BaseCodeMappings
@ -127,8 +128,28 @@ namespace ICSharpCode.Decompiler.Ast
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false) public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
{ {
if (assemblyDefinition.Name.Version != null) {
astCompileUnit.AddChild(
new AttributeSection {
AttributeTarget = "assembly",
Attributes = {
new NRefactory.CSharp.Attribute {
Type = new SimpleType("AssemblyVersion")
.WithAnnotation(new TypeReference(
"System.Reflection", "AssemblyVersionAttribute",
assemblyDefinition.MainModule, assemblyDefinition.MainModule.TypeSystem.Corlib)),
Arguments = {
new PrimitiveExpression(assemblyDefinition.Name.Version.ToString())
}
}
}
}, AttributedNode.AttributeRole);
}
ConvertCustomAttributes(astCompileUnit, assemblyDefinition, "assembly"); ConvertCustomAttributes(astCompileUnit, assemblyDefinition, "assembly");
ConvertSecurityAttributes(astCompileUnit, assemblyDefinition, "assembly");
ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, "module"); ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, "module");
AddTypeForwarderAttributes(astCompileUnit, assemblyDefinition.MainModule, "assembly");
if (!onlyAssemblyLevel) { if (!onlyAssemblyLevel) {
foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
@ -143,6 +164,30 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
void AddTypeForwarderAttributes(CompilationUnit astCompileUnit, ModuleDefinition module, string target)
{
if (!module.HasExportedTypes)
return;
foreach (ExportedType type in module.ExportedTypes) {
if (type.IsForwarder) {
var forwardedType = CreateTypeOfExpression(new TypeReference(type.Namespace, type.Name, module, type.Scope));
astCompileUnit.AddChild(
new AttributeSection {
AttributeTarget = target,
Attributes = {
new NRefactory.CSharp.Attribute {
Type = new SimpleType("TypeForwardedTo")
.WithAnnotation(new TypeReference(
"System.Runtime.CompilerServices", "TypeForwardedToAttribute",
module, module.TypeSystem.Corlib)),
Arguments = { forwardedType }
}
}
}, AttributedNode.AttributeRole);
}
}
}
NamespaceDeclaration GetCodeNamespace(string name) NamespaceDeclaration GetCodeNamespace(string name)
{ {
if (string.IsNullOrEmpty(name)) { if (string.IsNullOrEmpty(name)) {
@ -226,15 +271,6 @@ namespace ICSharpCode.Decompiler.Ast
astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters)); astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters));
astType.Constraints.AddRange(MakeConstraints(genericParameters)); astType.Constraints.AddRange(MakeConstraints(genericParameters));
// Nested types
foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
if (MemberIsHidden(nestedTypeDef, context.Settings))
continue;
var nestedType = CreateType(nestedTypeDef);
SetNewModifier(nestedType);
astType.AddChild(nestedType, TypeDeclaration.MemberRole);
}
AttributedNode result = astType; AttributedNode result = astType;
if (typeDef.IsEnum) { if (typeDef.IsEnum) {
long expectedEnumMemberValue = 0; long expectedEnumMemberValue = 0;
@ -312,6 +348,45 @@ namespace ICSharpCode.Decompiler.Ast
return name; return name;
} }
#region Create TypeOf Expression
/// <summary>
/// Creates a typeof-expression for the specified type.
/// </summary>
public static TypeOfExpression CreateTypeOfExpression(TypeReference type)
{
return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type)));
}
static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type)
{
TypeReference typeRef = type.Annotation<TypeReference>();
if (typeRef == null)
return type;
TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters
if (typeDef == null || !typeDef.HasGenericParameters)
return type;
SimpleType sType = type as SimpleType;
MemberType mType = type as MemberType;
if (sType != null) {
while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) {
sType.TypeArguments.Add(new SimpleType(""));
}
}
if (mType != null) {
AddEmptyTypeArgumentsForUnboundGenerics(mType.Target);
int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count;
while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) {
mType.TypeArguments.Add(new SimpleType(""));
}
}
return type;
}
#endregion
#region Convert Type Reference #region Convert Type Reference
/// <summary> /// <summary>
/// Converts a type reference. /// Converts a type reference.
@ -386,39 +461,42 @@ namespace ICSharpCode.Decompiler.Ast
return new PrimitiveType("dynamic"); return new PrimitiveType("dynamic");
} else { } else {
if (ns == "System") { if (ns == "System") {
switch (name) { if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames)
case "SByte": != ConvertTypeOptions.DoNotUsePrimitiveTypeNames) {
return new PrimitiveType("sbyte"); switch (name) {
case "Int16": case "SByte":
return new PrimitiveType("short"); return new PrimitiveType("sbyte");
case "Int32": case "Int16":
return new PrimitiveType("int"); return new PrimitiveType("short");
case "Int64": case "Int32":
return new PrimitiveType("long"); return new PrimitiveType("int");
case "Byte": case "Int64":
return new PrimitiveType("byte"); return new PrimitiveType("long");
case "UInt16": case "Byte":
return new PrimitiveType("ushort"); return new PrimitiveType("byte");
case "UInt32": case "UInt16":
return new PrimitiveType("uint"); return new PrimitiveType("ushort");
case "UInt64": case "UInt32":
return new PrimitiveType("ulong"); return new PrimitiveType("uint");
case "String": case "UInt64":
return new PrimitiveType("string"); return new PrimitiveType("ulong");
case "Single": case "String":
return new PrimitiveType("float"); return new PrimitiveType("string");
case "Double": case "Single":
return new PrimitiveType("double"); return new PrimitiveType("float");
case "Decimal": case "Double":
return new PrimitiveType("decimal"); return new PrimitiveType("double");
case "Char": case "Decimal":
return new PrimitiveType("char"); return new PrimitiveType("decimal");
case "Boolean": case "Char":
return new PrimitiveType("bool"); return new PrimitiveType("char");
case "Void": case "Boolean":
return new PrimitiveType("void"); return new PrimitiveType("bool");
case "Object": case "Void":
return new PrimitiveType("object"); return new PrimitiveType("void");
case "Object":
return new PrimitiveType("object");
}
} }
} }
@ -595,6 +673,15 @@ namespace ICSharpCode.Decompiler.Ast
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
{ {
// Nested types
foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
if (MemberIsHidden(nestedTypeDef, context.Settings))
continue;
var nestedType = CreateType(nestedTypeDef);
SetNewModifier(nestedType);
astType.AddChild(nestedType, TypeDeclaration.MemberRole);
}
// Add fields // Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) { foreach(FieldDefinition fieldDef in typeDef.Fields) {
if (MemberIsHidden(fieldDef, context.Settings)) continue; if (MemberIsHidden(fieldDef, context.Settings)) continue;
@ -729,6 +816,9 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping); astMethod.WithAnnotation(methodMapping);
if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) {
astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), AstNode.Roles.Comment);
}
return astMethod; return astMethod;
} }
@ -801,7 +891,13 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod); astProp.Setter.AddAnnotation(propDef.SetMethod);
ConvertAttributes(astProp.Setter, propDef.SetMethod); ConvertAttributes(astProp.Setter, propDef.SetMethod);
ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), "param"); ParameterDefinition lastParam = propDef.SetMethod.Parameters.LastOrDefault();
if (lastParam != null) {
ConvertCustomAttributes(astProp.Setter, lastParam, "param");
if (lastParam.HasMarshalInfo) {
astProp.Setter.Attributes.Add(new AttributeSection(ConvertMarshalInfo(lastParam, propDef.Module)) { AttributeTarget = "param" });
}
}
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask)) if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask; astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
@ -989,6 +1085,7 @@ namespace ICSharpCode.Decompiler.Ast
void ConvertAttributes(AttributedNode attributedNode, TypeDefinition typeDefinition) void ConvertAttributes(AttributedNode attributedNode, TypeDefinition typeDefinition)
{ {
ConvertCustomAttributes(attributedNode, typeDefinition); ConvertCustomAttributes(attributedNode, typeDefinition);
ConvertSecurityAttributes(attributedNode, typeDefinition);
// Handle the non-custom attributes: // Handle the non-custom attributes:
#region SerializableAttribute #region SerializableAttribute
@ -1039,6 +1136,7 @@ namespace ICSharpCode.Decompiler.Ast
void ConvertAttributes(AttributedNode attributedNode, MethodDefinition methodDefinition) void ConvertAttributes(AttributedNode attributedNode, MethodDefinition methodDefinition)
{ {
ConvertCustomAttributes(attributedNode, methodDefinition); ConvertCustomAttributes(attributedNode, methodDefinition);
ConvertSecurityAttributes(attributedNode, methodDefinition);
MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask; MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
@ -1175,6 +1273,37 @@ namespace ICSharpCode.Decompiler.Ast
Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module); Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.Corlib); var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.Corlib);
attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType)); attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType));
FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo;
if (fami != null) {
attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fami.Size));
if (fami.ElementType != NativeType.None)
attr.AddNamedArgument("ArraySubType", MakePrimitive((int)fami.ElementType, unmanagedType));
}
SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo;
if (sami != null && sami.ElementType != VariantType.None) {
var varEnum = new TypeReference("System.Runtime.InteropServices", "VarEnum", module, module.TypeSystem.Corlib);
attr.AddNamedArgument("SafeArraySubType", MakePrimitive((int)sami.ElementType, varEnum));
}
ArrayMarshalInfo ami = marshalInfo as ArrayMarshalInfo;
if (ami != null) {
if (ami.ElementType != NativeType.Max)
attr.AddNamedArgument("ArraySubType", MakePrimitive((int)ami.ElementType, unmanagedType));
if (ami.Size >= 0)
attr.AddNamedArgument("SizeConst", new PrimitiveExpression(ami.Size));
if (ami.SizeParameterMultiplier != 0 && ami.SizeParameterIndex >= 0)
attr.AddNamedArgument("SizeParamIndex", new PrimitiveExpression(ami.SizeParameterIndex));
}
CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo;
if (cmi != null) {
attr.AddNamedArgument("MarshalType", new PrimitiveExpression(cmi.ManagedType.FullName));
if (!string.IsNullOrEmpty(cmi.Cookie))
attr.AddNamedArgument("MarshalCookie", new PrimitiveExpression(cmi.Cookie));
}
FixedSysStringMarshalInfo fssmi = marshalInfo as FixedSysStringMarshalInfo;
if (fssmi != null) {
attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fssmi.Size));
}
return attr; return attr;
} }
#endregion #endregion
@ -1264,6 +1393,65 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
static void ConvertSecurityAttributes(AstNode attributedNode, ISecurityDeclarationProvider secDeclProvider, string attributeTarget = null)
{
if (!secDeclProvider.HasSecurityDeclarations)
return;
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var secDecl in secDeclProvider.SecurityDeclarations) {
foreach (var secAttribute in secDecl.SecurityAttributes) {
var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
attribute.AddAnnotation(secAttribute);
attribute.Type = ConvertType(secAttribute.AttributeType);
attributes.Add(attribute);
SimpleType st = attribute.Type as SimpleType;
if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length);
}
var module = secAttribute.AttributeType.Module;
var securityActionType = new TypeReference("System.Security.Permissions", "SecurityAction", module, module.TypeSystem.Corlib);
attribute.Arguments.Add(MakePrimitive((int)secDecl.Action, securityActionType));
if (secAttribute.HasProperties) {
TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
foreach (var propertyNamedArg in secAttribute.Properties) {
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));
}
}
if (secAttribute.HasFields) {
TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
foreach (var fieldNamedArg in secAttribute.Fields) {
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));
}
}
}
}
if (attributeTarget == "module" || attributeTarget == "assembly") {
// use separate section for each attribute
foreach (var attribute in attributes) {
var section = new AttributeSection();
section.AttributeTarget = attributeTarget;
section.Attributes.Add(attribute);
attributedNode.AddChild(section, AttributedNode.AttributeRole);
}
} else if (attributes.Count > 0) {
// use single section for all attributes
var section = new AttributeSection();
section.AttributeTarget = attributeTarget;
section.Attributes.AddRange(attributes);
attributedNode.AddChild(section, AttributedNode.AttributeRole);
}
}
private static Expression ConvertArgumentValue(CustomAttributeArgument argument) private static Expression ConvertArgumentValue(CustomAttributeArgument argument)
{ {
if (argument.Value is CustomAttributeArgument[]) { if (argument.Value is CustomAttributeArgument[]) {
@ -1284,9 +1472,7 @@ namespace ICSharpCode.Decompiler.Ast
if (type != null && type.IsEnum) { if (type != null && type.IsEnum) {
return MakePrimitive(Convert.ToInt64(argument.Value), type); return MakePrimitive(Convert.ToInt64(argument.Value), type);
} else if (argument.Value is TypeReference) { } else if (argument.Value is TypeReference) {
return new TypeOfExpression() { return CreateTypeOfExpression((TypeReference)argument.Value);
Type = ConvertType((TypeReference)argument.Value),
};
} else { } else {
return new PrimitiveExpression(argument.Value); return new PrimitiveExpression(argument.Value);
} }
@ -1441,7 +1627,7 @@ namespace ICSharpCode.Decompiler.Ast
if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member)) if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member))
return true; return true;
if (includeBaseMethods && baseType.HasMethods if (includeBaseMethods && baseType.HasMethods
&& AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName)) && AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName))
return true; return true;
if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member)) if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member))
return true; return true;
@ -1455,8 +1641,8 @@ namespace ICSharpCode.Decompiler.Ast
where T : IMemberDefinition where T : IMemberDefinition
{ {
return members.Any(m => m.Name == derived.Name return members.Any(m => m.Name == derived.Name
&& (condition == null || condition(m)) && (condition == null || condition(m))
&& TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType)); && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
} }
/// <summary> /// <summary>

17
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -485,9 +485,12 @@ namespace ICSharpCode.Decompiler.Ast
return arg1; return arg1;
else else
return arg1.CastTo(operandAsTypeRef); return arg1.CastTo(operandAsTypeRef);
case ILCode.Isinst: return arg1.CastAs(operandAsTypeRef); case ILCode.Isinst:
case ILCode.Box: return arg1; return arg1.CastAs(operandAsTypeRef);
case ILCode.Unbox: return InlineAssembly(byteCode, args); case ILCode.Box:
return arg1;
case ILCode.Unbox:
return MakeRef(arg1.CastTo(operandAsTypeRef));
#endregion #endregion
#region Indirect #region Indirect
case ILCode.Ldind_Ref: case ILCode.Ldind_Ref:
@ -539,11 +542,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Endfilter: return InlineAssembly(byteCode, args); case ILCode.Endfilter: return InlineAssembly(byteCode, args);
case ILCode.Endfinally: return null; case ILCode.Endfinally: return null;
case ILCode.Initblk: return InlineAssembly(byteCode, args); case ILCode.Initblk: return InlineAssembly(byteCode, args);
case ILCode.Initobj: case ILCode.Initobj: return InlineAssembly(byteCode, args);
if (args[0] is DirectionExpression)
return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), MakeDefaultValue((TypeReference)operand));
else
return InlineAssembly(byteCode, args);
case ILCode.DefaultValue: case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand); return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args); case ILCode.Jmp: return InlineAssembly(byteCode, args);
@ -602,7 +601,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand); case ILCode.Ldstr: return new Ast.PrimitiveExpression(operand);
case ILCode.Ldtoken: case ILCode.Ldtoken:
if (operand is Cecil.TypeReference) { if (operand is Cecil.TypeReference) {
return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle"); return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle");
} else { } else {
return InlineAssembly(byteCode, args); return InlineAssembly(byteCode, args);
} }

2
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -279,6 +279,8 @@ namespace ICSharpCode.Decompiler.Ast
name = "array"; name = "array";
} else if (type.IsPointer || type.IsByReference) { } else if (type.IsPointer || type.IsByReference) {
name = "ptr"; name = "ptr";
} else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) {
name = "ex";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) { } else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name; name = type.Name;
// remove the 'I' for interfaces // remove the 'I' for interfaces

15
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.Ast
readonly ITextOutput output; readonly ITextOutput output;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>(); readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1; int braceLevelWithinType = -1;
bool inDocumentationComment = false;
public TextOutputFormatter(ITextOutput output) public TextOutputFormatter(ITextOutput output)
{ {
@ -115,8 +116,17 @@ namespace ICSharpCode.Decompiler.Ast
output.Write("*/"); output.Write("*/");
break; break;
case CommentType.Documentation: case CommentType.Documentation:
if (!inDocumentationComment)
output.MarkFoldStart("///" + content, true);
output.Write("///"); output.Write("///");
output.WriteLine(content); output.Write(content);
inDocumentationComment = true;
bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (isLastLine) {
inDocumentationComment = false;
output.MarkFoldEnd();
}
output.WriteLine();
break; break;
} }
} }
@ -127,7 +137,8 @@ namespace ICSharpCode.Decompiler.Ast
var ranges = node.Annotation<List<ILRange>>(); var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) { if (ranges != null && ranges.Count > 0) {
// find the ancestor that has method mapping as annotation // find the ancestor that has method mapping as annotation
if (node.Ancestors != null && node.Ancestors.Count() > 0) { if (node.Parent != null)
{
var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null); var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null);
if (n != null) { if (n != null) {
MemberMapping mapping = n.Annotation<MemberMapping>(); MemberMapping mapping = n.Annotation<MemberMapping>();

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

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
@ -69,9 +70,29 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{ {
var instanceCtors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); // Handle initializers on instance fields
HandleInstanceFieldInitializers(typeDeclaration.Members);
// Now convert base constructor calls to initializers:
base.VisitTypeDeclaration(typeDeclaration, data);
// Remove single empty constructor:
RemoveSingleEmptyConstructor(typeDeclaration);
// Handle initializers on static fields:
HandleStaticFieldInitializers(typeDeclaration.Members);
return null;
}
void HandleInstanceFieldInitializers(IEnumerable<AstNode> members)
{
var instanceCtors = members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray(); var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();
if (instanceCtorsNotChainingWithThis.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class) { if (instanceCtorsNotChainingWithThis.Length > 0) {
MethodDefinition ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation<MethodDefinition>();
if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsValueType)
return;
// Recognize field initializers: // Recognize field initializers:
// Convert first statement in all ctors (if all ctors have the same statement) into a field initializer. // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
bool allSame; bool allSame;
@ -83,7 +104,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = m.Get<AstNode>("fieldAccess").Single().Annotation<FieldReference>().ResolveWithinSameModule(); FieldDefinition fieldDef = m.Get<AstNode>("fieldAccess").Single().Annotation<FieldReference>().ResolveWithinSameModule();
if (fieldDef == null) if (fieldDef == null)
break; break;
AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef); AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldOrEventDecl == null) if (fieldOrEventDecl == null)
break; break;
@ -99,11 +120,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} while (allSame); } while (allSame);
} }
}
// Now convert base constructor calls to initializers:
base.VisitTypeDeclaration(typeDeclaration, data); void RemoveSingleEmptyConstructor(TypeDeclaration typeDeclaration)
{
// Remove single empty constructor: var instanceCtors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (instanceCtors.Length == 1) { if (instanceCtors.Length == 1) {
ConstructorDeclaration emptyCtor = new ConstructorDeclaration(); ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public); emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
@ -111,12 +132,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (emptyCtor.IsMatch(instanceCtors[0])) if (emptyCtor.IsMatch(instanceCtors[0]))
instanceCtors[0].Remove(); instanceCtors[0].Remove();
} }
}
void HandleStaticFieldInitializers(IEnumerable<AstNode> members)
{
// Convert static constructor into field initializers if the class is BeforeFieldInit // Convert static constructor into field initializers if the class is BeforeFieldInit
var staticCtor = typeDeclaration.Members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static); var staticCtor = members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);
if (staticCtor != null) { if (staticCtor != null) {
TypeDefinition typeDef = typeDeclaration.Annotation<TypeDefinition>(); MethodDefinition ctorMethodDef = staticCtor.Annotation<MethodDefinition>();
if (typeDef != null && typeDef.IsBeforeFieldInit) { if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsBeforeFieldInit) {
while (true) { while (true) {
ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement; ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (es == null) if (es == null)
@ -127,7 +151,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = assignment.Left.Annotation<FieldReference>().ResolveWithinSameModule(); FieldDefinition fieldDef = assignment.Left.Annotation<FieldReference>().ResolveWithinSameModule();
if (fieldDef == null || !fieldDef.IsStatic) if (fieldDef == null || !fieldDef.IsStatic)
break; break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef); FieldDeclaration fieldDecl = members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null) if (fieldDecl == null)
break; break;
fieldDecl.Variables.Single().Initializer = assignment.Right.Detach(); fieldDecl.Variables.Single().Initializer = assignment.Right.Detach();
@ -137,11 +161,15 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
staticCtor.Remove(); staticCtor.Remove();
} }
} }
return null;
} }
void IAstTransform.Run(AstNode node) void IAstTransform.Run(AstNode node)
{ {
// If we're viewing some set of members (fields are direct children of CompilationUnit),
// we also need to handle those:
HandleInstanceFieldInitializers(node.Children);
HandleStaticFieldInitializers(node.Children);
node.AcceptVisitor(this, null); node.AcceptVisitor(this, null);
} }
} }

58
ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs

@ -0,0 +1,58 @@
// 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 ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Transforms decimal constant fields.
/// </summary>
public class DecimalConstantTransform : DepthFirstAstVisitor<object, object>, IAstTransform
{
static readonly PrimitiveType decimalType = new PrimitiveType("decimal");
public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
{
const Modifiers staticReadOnly = Modifiers.Static | Modifiers.Readonly;
if ((fieldDeclaration.Modifiers & staticReadOnly) == staticReadOnly && decimalType.IsMatch(fieldDeclaration.ReturnType)) {
foreach (var attributeSection in fieldDeclaration.Attributes) {
foreach (var attribute in attributeSection.Attributes) {
TypeReference tr = attribute.Type.Annotation<TypeReference>();
if (tr != null && tr.Name == "DecimalConstantAttribute" && tr.Namespace == "System.Runtime.CompilerServices") {
attribute.Remove();
if (attributeSection.Attributes.Count == 0)
attributeSection.Remove();
fieldDeclaration.Modifiers = (fieldDeclaration.Modifiers & ~staticReadOnly) | Modifiers.Const;
return null;
}
}
}
}
return null;
}
public void Run(AstNode compilationUnit)
{
compilationUnit.AcceptVisitor(this, null);
}
}
}

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

@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{ {
if (objectCreateExpression.Arguments.Count() == 2) { if (objectCreateExpression.Arguments.Count == 2) {
Expression obj = objectCreateExpression.Arguments.First(); Expression obj = objectCreateExpression.Arguments.First();
Expression func = objectCreateExpression.Arguments.Last(); Expression func = objectCreateExpression.Arguments.Last();
Annotation annotation = func.Annotation<Annotation>(); Annotation annotation = func.Annotation<Annotation>();
@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method) internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method)
{ {
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal)) if (method == null || !(method.Name.StartsWith("<", StringComparison.Ordinal) || method.Name.Contains("$")))
return false; return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType))) if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType)))
return false; return false;
@ -388,10 +388,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
continue; // skip static fields continue; // skip static fields
if (dict.ContainsKey(field)) // skip field if it already was handled as parameter if (dict.ContainsKey(field)) // skip field if it already was handled as parameter
continue; continue;
EnsureVariableNameIsAvailable(blockStatement, field.Name); string capturedVariableName = field.Name;
currentlyUsedVariableNames.Add(field.Name); if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10)
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name)); capturedVariableName = capturedVariableName.Substring(10);
dict[field] = new IdentifierExpression(field.Name); EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName));
dict[field] = new IdentifierExpression(capturedVariableName);
} }
// Now figure out where the closure was accessed and use the simpler replacement expression there: // Now figure out where the closure was accessed and use the simpler replacement expression there:

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

@ -154,7 +154,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
static readonly AstNode usingTryCatchPattern = new TryCatchStatement { static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body"), TryBlock = new AnyNode(),
FinallyBlock = new BlockStatement { FinallyBlock = new BlockStatement {
new Choice { new Choice {
{ "valueType", { "valueType",
@ -180,44 +180,60 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{ {
Match m1 = variableAssignPattern.Match(node); Match m1 = variableAssignPattern.Match(node);
if (!m1.Success) return null; if (!m1.Success) return null;
AstNode tryCatch = node.NextSibling; TryCatchStatement tryCatch = node.NextSibling as TryCatchStatement;
Match m2 = usingTryCatchPattern.Match(tryCatch); Match m2 = usingTryCatchPattern.Match(tryCatch);
if (!m2.Success) return null; if (!m2.Success) return null;
string variableName = m1.Get<IdentifierExpression>("variable").Single().Identifier; string variableName = m1.Get<IdentifierExpression>("variable").Single().Identifier;
if (variableName == m2.Get<IdentifierExpression>("ident").Single().Identifier) { if (variableName != m2.Get<IdentifierExpression>("ident").Single().Identifier)
if (m2.Has("valueType")) { return null;
// if there's no if(x!=null), then it must be a value type if (m2.Has("valueType")) {
ILVariable v = m1.Get<AstNode>("variable").Single().Annotation<ILVariable>(); // if there's no if(x!=null), then it must be a value type
if (v == null || v.Type == null || !v.Type.IsValueType) ILVariable v = m1.Get<AstNode>("variable").Single().Annotation<ILVariable>();
return null; if (v == null || v.Type == null || !v.Type.IsValueType)
} return null;
node.Remove(); }
BlockStatement body = m2.Get<BlockStatement>("body").Single();
UsingStatement usingStatement = new UsingStatement(); // There are two variants of the using statement:
usingStatement.ResourceAcquisition = node.Expression.Detach(); // "using (var a = init)" and "using (expr)".
usingStatement.EmbeddedStatement = body.Detach(); // The former declares a read-only variable 'a', and the latter declares an unnamed read-only variable
tryCatch.ReplaceWith(usingStatement); // to store the original value of 'expr'.
// Move the variable declaration into the resource acquisition, if possible // This means that in order to introduce a using statement, in both cases we need to detect a read-only
// This is necessary for the foreach-pattern to work on the result of the using-pattern // variable that is used only within that block.
VariableDeclarationStatement varDecl = FindVariableDeclaration(usingStatement, variableName);
if (varDecl != null && varDecl.Parent is BlockStatement) { if (HasAssignment(tryCatch, variableName))
Statement declarationPoint; return null;
if (CanMoveVariableDeclarationIntoStatement(varDecl, usingStatement, out declarationPoint)) {
// Moving the variable into the UsingStatement is allowed: VariableDeclarationStatement varDecl = FindVariableDeclaration(node, variableName);
usingStatement.ResourceAcquisition = new VariableDeclarationStatement { if (varDecl == null || !(varDecl.Parent is BlockStatement))
Type = (AstType)varDecl.Type.Clone(), return null;
Variables = {
new VariableInitializer { // Validate that the variable is not used after the using statement:
Name = variableName, if (!IsVariableValueUnused(varDecl, tryCatch))
Initializer = m1.Get<Expression>("initializer").Single().Detach() return null;
}.CopyAnnotationsFrom(usingStatement.ResourceAcquisition)
} node.Remove();
}.CopyAnnotationsFrom(node);
UsingStatement usingStatement = new UsingStatement();
usingStatement.EmbeddedStatement = tryCatch.TryBlock.Detach();
tryCatch.ReplaceWith(usingStatement);
// If possible, we'll eliminate the variable completely:
if (usingStatement.EmbeddedStatement.Descendants.OfType<IdentifierExpression>().Any(ident => ident.Identifier == variableName)) {
// variable is used, so we'll create a variable declaration
usingStatement.ResourceAcquisition = new VariableDeclarationStatement {
Type = (AstType)varDecl.Type.Clone(),
Variables = {
new VariableInitializer {
Name = variableName,
Initializer = m1.Get<Expression>("initializer").Single().Detach()
}.CopyAnnotationsFrom(node.Expression)
} }
} }.CopyAnnotationsFrom(node);
return usingStatement; } else {
// the variable is never used; eliminate it:
usingStatement.ResourceAcquisition = m1.Get<Expression>("initializer").Single().Detach();
} }
return null; return usingStatement;
} }
internal static VariableDeclarationStatement FindVariableDeclaration(AstNode node, string identifier) internal static VariableDeclarationStatement FindVariableDeclaration(AstNode node, string identifier)
@ -235,6 +251,29 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null; return null;
} }
/// <summary>
/// Gets whether the old variable value (assigned inside 'targetStatement' or earlier)
/// is read anywhere in the remaining scope of the variable declaration.
/// </summary>
bool IsVariableValueUnused(VariableDeclarationStatement varDecl, Statement targetStatement)
{
Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent));
BlockStatement block = (BlockStatement)varDecl.Parent;
DefiniteAssignmentAnalysis daa = new DefiniteAssignmentAnalysis(block, context.CancellationToken);
daa.SetAnalyzedRange(targetStatement, block, startInclusive: false);
daa.Analyze(varDecl.Variables.Single().Name);
return daa.UnassignedVariableUses.Count == 0;
}
// I used this in the first implementation of the using-statement transform, but now no longer
// because there were problems when multiple using statements were using the same variable
// - no single using statement could be transformed without making the C# code invalid,
// but transforming both would work.
// We now use 'IsVariableValueUnused' which will perform the transform
// even if it results in two variables with the same name and overlapping scopes.
// (this issue could be fixed later by renaming one of the variables)
// I'm not sure whether the other consumers of 'CanMoveVariableDeclarationIntoStatement' should be changed the same way.
bool CanMoveVariableDeclarationIntoStatement(VariableDeclarationStatement varDecl, Statement targetStatement, out Statement declarationPoint) bool CanMoveVariableDeclarationIntoStatement(VariableDeclarationStatement varDecl, Statement targetStatement, out Statement declarationPoint)
{ {
Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent)); Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent));
@ -251,6 +290,24 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
return true; return true;
} }
/// <summary>
/// Gets whether there is an assignment to 'variableName' anywhere within the given node.
/// </summary>
bool HasAssignment(AstNode root, string variableName)
{
foreach (AstNode node in root.DescendantsAndSelf) {
IdentifierExpression ident = node as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) {
if (ident.Parent is AssignmentExpression && ident.Role == AssignmentExpression.LeftRole
|| ident.Parent is DirectionExpression)
{
return true;
}
}
}
return false;
}
#endregion #endregion
#region foreach (generic) #region foreach (generic)
@ -648,7 +705,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment // switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment
if (!m.Get("switchVar").Single().IsMatch(m.Get("switchExpr").Single())) { if (!m.Get("switchVar").Single().IsMatch(m.Get("switchExpr").Single())) {
AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression; AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression;
if (!m.Get("switchVar").Single().IsMatch(assign.Left)) if (!(assign != null && m.Get("switchVar").Single().IsMatch(assign.Left)))
return null; return null;
} }
FieldReference cachedDictField = m.Get<AstNode>("cachedDict").Single().Annotation<FieldReference>(); FieldReference cachedDictField = m.Get<AstNode>("cachedDict").Single().Annotation<FieldReference>();

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

@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
var arguments = invocationExpression.Arguments.ToArray(); var arguments = invocationExpression.Arguments.ToArray();
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
if (methodRef != null && methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2) if (methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2)
{ {
invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression
Expression expr = arguments[0]; Expression expr = arguments[0];
@ -97,7 +97,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null; return null;
} }
if (methodRef.Name == "op_Implicit" && arguments.Length == 1) { if (methodRef.Name == "op_Implicit" && arguments.Length == 1) {
arguments[0].Remove(); // detach argument invocationExpression.ReplaceWith(arguments[0]);
return null;
}
if (methodRef.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == AstNode.Roles.Condition) {
invocationExpression.ReplaceWith(arguments[0]); invocationExpression.ReplaceWith(arguments[0]);
return null; return null;
} }

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

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new AddCheckedBlocks(), new AddCheckedBlocks(),
new DeclareVariables(context), // should run after most transforms that modify statements new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
new DecimalConstantTransform(),
new IntroduceUsingDeclarations(context), new IntroduceUsingDeclarations(context),
new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods

250
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -17,11 +17,32 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
namespace ICSharpCode.Decompiler.Disassembler namespace ICSharpCode.Decompiler.Disassembler
{ {
public enum ILNameSyntax
{
/// <summary>
/// class/valuetype + TypeName (built-in types use keyword syntax)
/// </summary>
Signature,
/// <summary>
/// Like signature, but always refers to type parameters using their position
/// </summary>
SignatureNoNamedTypeParameters,
/// <summary>
/// [assembly]Full.Type.Name (even for built-in types)
/// </summary>
TypeName,
/// <summary>
/// Name (but built-in types use keyword syntax)
/// </summary>
ShortTypeName
}
public static class DisassemblerHelpers public static class DisassemblerHelpers
{ {
public static void WriteOffsetReference(ITextOutput writer, Instruction instruction) public static void WriteOffsetReference(ITextOutput writer, Instruction instruction)
@ -35,6 +56,7 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteOffsetReference(writer, exceptionHandler.TryStart); WriteOffsetReference(writer, exceptionHandler.TryStart);
writer.Write('-'); writer.Write('-');
WriteOffsetReference(writer, exceptionHandler.TryEnd); WriteOffsetReference(writer, exceptionHandler.TryEnd);
writer.Write(' ');
writer.Write(exceptionHandler.HandlerType.ToString()); writer.Write(exceptionHandler.HandlerType.ToString());
if (exceptionHandler.FilterStart != null) { if (exceptionHandler.FilterStart != null) {
writer.Write(' '); writer.Write(' ');
@ -56,8 +78,14 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction); writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction);
writer.Write(": "); writer.Write(": ");
writer.WriteReference(instruction.OpCode.Name, instruction.OpCode); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode);
if(null != instruction.Operand) { if (instruction.Operand != null) {
writer.Write(' '); writer.Write(' ');
if (instruction.OpCode == OpCodes.Ldtoken) {
if (instruction.Operand is MethodReference)
writer.Write("method ");
else if (instruction.Operand is FieldReference)
writer.Write("field ");
}
WriteOperand(writer, instruction.Operand); WriteOperand(writer, instruction.Operand);
} }
} }
@ -82,46 +110,131 @@ namespace ICSharpCode.Decompiler.Disassembler
public static void WriteTo(this MethodReference method, ITextOutput writer) public static void WriteTo(this MethodReference method, ITextOutput writer)
{ {
if (method.HasThis) if (method.ExplicitThis) {
writer.Write("instance explicit ");
}
else if (method.HasThis) {
writer.Write("instance "); writer.Write("instance ");
method.ReturnType.WriteTo(writer); }
method.ReturnType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters);
writer.Write(' '); writer.Write(' ');
if (method.DeclaringType != null) { if (method.DeclaringType != null) {
method.DeclaringType.WriteTo(writer, true); method.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write("::"); writer.Write("::");
} }
writer.WriteReference(method.Name, method); MethodDefinition md = method as MethodDefinition;
if (md != null && md.IsCompilerControlled) {
writer.WriteReference(Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8")), method);
} else {
writer.WriteReference(Escape(method.Name), method);
}
GenericInstanceMethod gim = method as GenericInstanceMethod;
if (gim != null) {
writer.Write('<');
for (int i = 0; i < gim.GenericArguments.Count; i++) {
if (i > 0)
writer.Write(", ");
gim.GenericArguments[i].WriteTo(writer);
}
writer.Write('>');
}
writer.Write("("); writer.Write("(");
var parameters = method.Parameters; var parameters = method.Parameters;
for(int i = 0; i < parameters.Count; ++i) { for(int i = 0; i < parameters.Count; ++i) {
if (i > 0) writer.Write(", "); if (i > 0) writer.Write(", ");
parameters[i].ParameterType.WriteTo(writer); parameters[i].ParameterType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters);
} }
writer.Write(")"); writer.Write(")");
} }
static void WriteTo(this FieldReference field, ITextOutput writer) static void WriteTo(this FieldReference field, ITextOutput writer)
{ {
field.FieldType.WriteTo(writer); field.FieldType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters);
writer.Write(' '); writer.Write(' ');
field.DeclaringType.WriteTo(writer); field.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write("::"); writer.Write("::");
writer.WriteReference(field.Name, field); writer.WriteReference(Escape(field.Name), field);
}
static bool IsValidIdentifierCharacter(char c)
{
return c == '_' || c == '$' || c == '@' || c == '?' || c == '`';
}
static bool IsValidIdentifier(string identifier)
{
if (string.IsNullOrEmpty(identifier))
return false;
if (!(char.IsLetter(identifier[0]) || IsValidIdentifierCharacter(identifier[0]))) {
// As a special case, .ctor and .cctor are valid despite starting with a dot
return identifier == ".ctor" || identifier == ".cctor";
}
for (int i = 1; i < identifier.Length; i++) {
if (!(char.IsLetterOrDigit(identifier[i]) || IsValidIdentifierCharacter(identifier[i]) || identifier[i] == '.'))
return false;
}
return true;
}
static readonly HashSet<string> ilKeywords = BuildKeywordList(
"abstract", "algorithm", "alignment", "ansi", "any", "arglist",
"array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit",
"blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr",
"bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf",
"char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal",
"default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern",
"false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime",
"filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref",
"fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal",
"implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init",
"initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall",
"iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr",
"lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested",
"newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand",
"noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable",
"notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out",
"permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6",
"prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected",
"public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval",
"rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname",
"static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct",
"synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref",
"unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype",
"vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper",
// These are not listed as keywords in spec, but ILAsm treats them as such
"property", "type", "flags", "callconv", "strict"
);
static HashSet<string> BuildKeywordList(params string[] keywords)
{
HashSet<string> s = new HashSet<string>(keywords);
foreach (var field in typeof(OpCodes).GetFields()) {
s.Add(((OpCode)field.GetValue(null)).Name);
}
return s;
} }
public static string Escape(string identifier) public static string Escape(string identifier)
{ {
return identifier; if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) {
return identifier;
} else {
// The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence,
// but we follow Microsoft's ILDasm and use \'.
return "'" + NRefactory.CSharp.OutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'";
}
} }
public static void WriteTo(this TypeReference type, ITextOutput writer, bool onlyName = false, bool shortName = false) public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature)
{ {
ILNameSyntax syntaxForElementTypes = syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature;
if (type is PinnedType) { if (type is PinnedType) {
writer.Write("pinned "); ((PinnedType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
((PinnedType)type).ElementType.WriteTo(writer, onlyName, shortName); writer.Write(" pinned");
} else if (type is ArrayType) { } else if (type is ArrayType) {
ArrayType at = (ArrayType)type; ArrayType at = (ArrayType)type;
at.ElementType.WriteTo(writer, onlyName, shortName); at.ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('['); writer.Write('[');
writer.Write(string.Join(", ", at.Dimensions)); writer.Write(string.Join(", ", at.Dimensions));
writer.Write(']'); writer.Write(']');
@ -129,49 +242,57 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write('!'); writer.Write('!');
if (((GenericParameter)type).Owner.GenericParameterType == GenericParameterType.Method) if (((GenericParameter)type).Owner.GenericParameterType == GenericParameterType.Method)
writer.Write('!'); writer.Write('!');
writer.Write(type.Name); if (string.IsNullOrEmpty(type.Name) || type.Name[0] == '!' || syntax == ILNameSyntax.SignatureNoNamedTypeParameters)
writer.Write(((GenericParameter)type).Position.ToString());
else
writer.Write(Escape(type.Name));
} else if (type is ByReferenceType) { } else if (type is ByReferenceType) {
((ByReferenceType)type).ElementType.WriteTo(writer, onlyName, shortName); ((ByReferenceType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('&'); writer.Write('&');
} else if (type is PointerType) { } else if (type is PointerType) {
((PointerType)type).ElementType.WriteTo(writer, onlyName, shortName); ((PointerType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('*'); writer.Write('*');
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
type.GetElementType().WriteTo(writer, onlyName, shortName); type.GetElementType().WriteTo(writer, syntaxForElementTypes);
writer.Write('<'); writer.Write('<');
var arguments = ((GenericInstanceType)type).GenericArguments; var arguments = ((GenericInstanceType)type).GenericArguments;
for (int i = 0; i < arguments.Count; i++) { for (int i = 0; i < arguments.Count; i++) {
if (i > 0) if (i > 0)
writer.Write(", "); writer.Write(", ");
arguments[i].WriteTo(writer, onlyName, shortName); arguments[i].WriteTo(writer, syntaxForElementTypes);
} }
writer.Write('>'); writer.Write('>');
} else if (type is OptionalModifierType) { } else if (type is OptionalModifierType) {
writer.Write("modopt("); ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax);
((OptionalModifierType)type).ModifierType.WriteTo(writer, true, shortName); writer.Write(" modopt(");
((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write(") "); writer.Write(") ");
((OptionalModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else if (type is RequiredModifierType) { } else if (type is RequiredModifierType) {
writer.Write("modreq("); ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax);
((RequiredModifierType)type).ModifierType.WriteTo(writer, true, shortName); writer.Write(" modreq(");
((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write(") "); writer.Write(") ");
((RequiredModifierType)type).ElementType.WriteTo(writer, onlyName, shortName);
} else { } else {
string name = PrimitiveTypeName(type); string name = PrimitiveTypeName(type.FullName);
if (name != null) { if (syntax == ILNameSyntax.ShortTypeName) {
if (name != null)
writer.Write(name);
else
writer.WriteReference(Escape(type.Name), type);
} else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) {
writer.Write(name); writer.Write(name);
} else { } else {
if (!onlyName) if (syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters)
writer.Write(type.IsValueType ? "valuetype " : "class "); writer.Write(type.IsValueType ? "valuetype " : "class ");
if (type.DeclaringType != null) { if (type.DeclaringType != null) {
type.DeclaringType.WriteTo(writer, true, shortName); type.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write('/'); writer.Write('/');
writer.WriteReference(Escape(type.Name), type); writer.WriteReference(Escape(type.Name), type);
} else { } else {
if (!type.IsDefinition && type.Scope != null && !shortName && !(type is TypeSpecification)) if (!type.IsDefinition && type.Scope != null && !(type is TypeSpecification))
writer.Write("[{0}]", Escape(type.Scope.Name)); writer.Write("[{0}]", Escape(type.Scope.Name));
writer.WriteReference(shortName ? type.Name : type.FullName, type); writer.WriteReference(Escape(type.FullName), type);
} }
} }
} }
@ -196,7 +317,19 @@ namespace ICSharpCode.Decompiler.Disassembler
VariableReference variableRef = operand as VariableReference; VariableReference variableRef = operand as VariableReference;
if (variableRef != null) { if (variableRef != null) {
writer.WriteReference(variableRef.Index.ToString(), variableRef); if (string.IsNullOrEmpty(variableRef.Name))
writer.WriteReference(variableRef.Index.ToString(), variableRef);
else
writer.WriteReference(Escape(variableRef.Name), variableRef);
return;
}
ParameterReference paramRef = operand as ParameterReference;
if (paramRef != null) {
if (string.IsNullOrEmpty(paramRef.Name))
writer.WriteReference(paramRef.Index.ToString(), paramRef);
else
writer.WriteReference(Escape(paramRef.Name), paramRef);
return; return;
} }
@ -208,7 +341,7 @@ namespace ICSharpCode.Decompiler.Disassembler
TypeReference typeRef = operand as TypeReference; TypeReference typeRef = operand as TypeReference;
if (typeRef != null) { if (typeRef != null) {
typeRef.WriteTo(writer); typeRef.WriteTo(writer, ILNameSyntax.TypeName);
return; return;
} }
@ -220,17 +353,52 @@ namespace ICSharpCode.Decompiler.Disassembler
string s = operand as string; string s = operand as string;
if (s != null) { if (s != null) {
writer.Write("\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); writer.Write("\"" + NRefactory.CSharp.OutputVisitor.ConvertString(s) + "\"");
return; } else if (operand is char) {
writer.Write(((int)(char)operand).ToString());
} else if (operand is float) {
float val = (float)operand;
if (val == 0) {
writer.Write("0.0");
} else if (float.IsInfinity(val) || float.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);
writer.Write('(');
for (int i = 0; i < data.Length; i++) {
if (i > 0)
writer.Write(' ');
writer.Write(data[i].ToString("X2"));
}
writer.Write(')');
} else {
writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
}
} else if (operand is double) {
double val = (double)operand;
if (val == 0) {
writer.Write("0.0");
} else if (double.IsInfinity(val) || double.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);
writer.Write('(');
for (int i = 0; i < data.Length; i++) {
if (i > 0)
writer.Write(' ');
writer.Write(data[i].ToString("X2"));
}
writer.Write(')');
} else {
writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
}
} else if (operand is bool) {
writer.Write((bool)operand ? "true" : "false");
} else {
s = ToInvariantCultureString(operand);
writer.Write(s);
} }
s = ToInvariantCultureString(operand);
writer.Write(s);
} }
public static string PrimitiveTypeName(this TypeReference type) public static string PrimitiveTypeName(string fullName)
{ {
switch (type.FullName) { switch (fullName) {
case "System.SByte": case "System.SByte":
return "int8"; return "int8";
case "System.Int16": case "System.Int16":
@ -261,6 +429,8 @@ namespace ICSharpCode.Decompiler.Disassembler
return "char"; return "char";
case "System.Object": case "System.Object":
return "object"; return "object";
case "System.IntPtr":
return "native int";
default: default:
return null; return null;
} }

6
ICSharpCode.Decompiler/Disassembler/ILStructure.cs

@ -88,8 +88,10 @@ namespace ICSharpCode.Decompiler.Disassembler
: this(ILStructureType.Root, 0, body.CodeSize) : this(ILStructureType.Root, 0, body.CodeSize)
{ {
// Build the tree of exception structures: // Build the tree of exception structures:
foreach (ExceptionHandler eh in body.ExceptionHandlers) { for (int i = 0; i < body.ExceptionHandlers.Count; i++) {
AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); ExceptionHandler eh = body.ExceptionHandlers[i];
if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd))
AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh));
if (eh.HandlerType == ExceptionHandlerType.Filter) if (eh.HandlerType == ExceptionHandlerType.Filter)
AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh)); AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh));
AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh)); AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh));

84
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -52,9 +52,6 @@ namespace ICSharpCode.Decompiler.Disassembler
// start writing IL code // start writing IL code
MethodDefinition method = body.Method; MethodDefinition method = body.Method;
output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA); output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA);
if (method.HasOverrides)
foreach (var methodOverride in method.Overrides)
output.WriteLine(".override {0}::{1}", methodOverride.DeclaringType.FullName, methodOverride.Name);
output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize); output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize);
output.WriteLine(".maxstack {0}", body.MaxStackSize); output.WriteLine(".maxstack {0}", body.MaxStackSize);
if (method.DeclaringType.Module.Assembly.EntryPoint == method) if (method.DeclaringType.Module.Assembly.EntryPoint == method)
@ -69,8 +66,12 @@ namespace ICSharpCode.Decompiler.Disassembler
foreach (var v in method.Body.Variables) { foreach (var v in method.Body.Variables) {
output.WriteDefinition("[" + v.Index + "] ", v); output.WriteDefinition("[" + v.Index + "] ", v);
v.VariableType.WriteTo(output); v.VariableType.WriteTo(output);
output.Write(' '); if (!string.IsNullOrEmpty(v.Name)) {
output.Write(DisassemblerHelpers.Escape(v.Name)); output.Write(' ');
output.Write(DisassemblerHelpers.Escape(v.Name));
}
if (v.Index + 1 < method.Body.Variables.Count)
output.Write(',');
output.WriteLine(); output.WriteLine();
} }
output.Unindent(); output.Unindent();
@ -80,29 +81,49 @@ namespace ICSharpCode.Decompiler.Disassembler
if (detectControlStructure && body.Instructions.Count > 0) { if (detectControlStructure && body.Instructions.Count > 0) {
Instruction inst = body.Instructions[0]; Instruction inst = body.Instructions[0];
WriteStructureBody(new ILStructure(body), ref inst, methodMapping, method.Body.CodeSize); HashSet<int> branchTargets = GetBranchTargets(body.Instructions);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize);
} else { } else {
foreach (var inst in method.Body.Instructions) { foreach (var inst in method.Body.Instructions) {
inst.WriteTo(output); inst.WriteTo(output);
// add IL code mappings - used in debugger if (methodMapping != null) {
methodMapping.MemberCodeMappings.Add( // add IL code mappings - used in debugger
new SourceCodeMapping() { methodMapping.MemberCodeMappings.Add(
SourceCodeLine = output.CurrentLine, new SourceCodeMapping() {
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset }, SourceCodeLine = output.CurrentLine,
MemberMapping = methodMapping ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset },
}); MemberMapping = methodMapping
});
}
output.WriteLine(); output.WriteLine();
} }
output.WriteLine(); if (method.Body.HasExceptionHandlers) {
foreach (var eh in method.Body.ExceptionHandlers) {
eh.WriteTo(output);
output.WriteLine(); output.WriteLine();
foreach (var eh in method.Body.ExceptionHandlers) {
eh.WriteTo(output);
output.WriteLine();
}
} }
} }
} }
HashSet<int> GetBranchTargets(IEnumerable<Instruction> instructions)
{
HashSet<int> branchTargets = new HashSet<int>();
foreach (var inst in instructions) {
Instruction target = inst.Operand as Instruction;
if (target != null)
branchTargets.Add(target.Offset);
Instruction[] targets = inst.Operand as Instruction[];
if (targets != null)
foreach (Instruction t in targets)
branchTargets.Add(t.Offset);
}
return branchTargets;
}
void WriteStructureHeader(ILStructure s) void WriteStructureHeader(ILStructure s)
{ {
switch (s.Type) { switch (s.Type) {
@ -116,7 +137,8 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine(); output.WriteLine();
break; break;
case ILStructureType.Try: case ILStructureType.Try:
output.WriteLine(".try {"); output.WriteLine(".try");
output.WriteLine("{");
break; break;
case ILStructureType.Handler: case ILStructureType.Handler:
switch (s.ExceptionHandler.HandlerType) { switch (s.ExceptionHandler.HandlerType) {
@ -125,22 +147,24 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("catch"); output.Write("catch");
if (s.ExceptionHandler.CatchType != null) { if (s.ExceptionHandler.CatchType != null) {
output.Write(' '); output.Write(' ');
s.ExceptionHandler.CatchType.WriteTo(output); s.ExceptionHandler.CatchType.WriteTo(output, ILNameSyntax.TypeName);
} }
output.WriteLine(" {"); output.WriteLine();
break; break;
case Mono.Cecil.Cil.ExceptionHandlerType.Finally: case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
output.WriteLine("finally {"); output.WriteLine("finally");
break; break;
case Mono.Cecil.Cil.ExceptionHandlerType.Fault: case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
output.WriteLine("fault {"); output.WriteLine("fault");
break; break;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
output.WriteLine("{");
break; break;
case ILStructureType.Filter: case ILStructureType.Filter:
output.WriteLine("filter {"); output.WriteLine("filter");
output.WriteLine("{");
break; break;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
@ -148,17 +172,22 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent(); output.Indent();
} }
void WriteStructureBody(ILStructure s, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize)
{ {
bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false;
int childIndex = 0; int childIndex = 0;
while (inst != null && inst.Offset < s.EndOffset) { while (inst != null && inst.Offset < s.EndOffset) {
int offset = inst.Offset; int offset = inst.Offset;
if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) {
ILStructure child = s.Children[childIndex++]; ILStructure child = s.Children[childIndex++];
WriteStructureHeader(child); WriteStructureHeader(child);
WriteStructureBody(child, ref inst, currentMethodMapping, codeSize); WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize);
WriteStructureFooter(child); WriteStructureFooter(child);
} else { } else {
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
output.WriteLine(); // put an empty line after branches, and in front of branch targets
}
inst.WriteTo(output); inst.WriteTo(output);
// add IL code mappings - used in debugger // add IL code mappings - used in debugger
@ -172,8 +201,15 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
output.WriteLine(); output.WriteLine();
prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch
|| inst.OpCode.FlowControl == FlowControl.Cond_Branch
|| inst.OpCode.FlowControl == FlowControl.Return
|| inst.OpCode.FlowControl == FlowControl.Throw;
inst = inst.Next; inst = inst.Next;
} }
isFirstInstructionInStructure = false;
} }
} }

692
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -18,8 +18,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using Mono.Cecil; using Mono.Cecil;
using Mono.Collections.Generic; using Mono.Collections.Generic;
@ -32,7 +34,6 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
ITextOutput output; ITextOutput output;
CancellationToken cancellationToken; CancellationToken cancellationToken;
bool detectControlStructure;
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings) bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
MethodBodyDisassembler methodBodyDisassembler; MethodBodyDisassembler methodBodyDisassembler;
MemberReference currentMember; MemberReference currentMember;
@ -43,7 +44,6 @@ namespace ICSharpCode.Decompiler.Disassembler
throw new ArgumentNullException("output"); throw new ArgumentNullException("output");
this.output = output; this.output = output;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.detectControlStructure = detectControlStructure;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<int, List<MemberMapping>>(); this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
@ -52,17 +52,19 @@ namespace ICSharpCode.Decompiler.Disassembler
#region Disassemble Method #region Disassemble Method
EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() { EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() {
{ MethodAttributes.Static, "static" },
{ MethodAttributes.Final, "final" }, { MethodAttributes.Final, "final" },
{ MethodAttributes.Virtual, "virtual" },
{ MethodAttributes.HideBySig, "hidebysig" }, { MethodAttributes.HideBySig, "hidebysig" },
{ MethodAttributes.Abstract, "abstract" },
{ MethodAttributes.SpecialName, "specialname" }, { MethodAttributes.SpecialName, "specialname" },
{ MethodAttributes.PInvokeImpl, "pinvokeimpl" }, { MethodAttributes.PInvokeImpl, null }, // handled separately
{ MethodAttributes.UnmanagedExport, "export" }, { MethodAttributes.UnmanagedExport, "export" },
{ MethodAttributes.RTSpecialName, "rtspecialname" }, { MethodAttributes.RTSpecialName, "rtspecialname" },
{ MethodAttributes.RequireSecObject, "requiresecobj" }, { MethodAttributes.RequireSecObject, "reqsecobj" },
{ MethodAttributes.NewSlot, "newslot" } { MethodAttributes.NewSlot, "newslot" },
{ MethodAttributes.CheckAccessOnOverride, "strict" },
{ MethodAttributes.Abstract, "abstract" },
{ MethodAttributes.Virtual, "virtual" },
{ MethodAttributes.Static, "static" },
{ MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm
}; };
EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() { EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() {
@ -80,7 +82,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodCallingConvention.ThisCall, "unmanaged thiscall" }, { MethodCallingConvention.ThisCall, "unmanaged thiscall" },
{ MethodCallingConvention.FastCall, "unmanaged fastcall" }, { MethodCallingConvention.FastCall, "unmanaged fastcall" },
{ MethodCallingConvention.VarArg, "vararg" }, { MethodCallingConvention.VarArg, "vararg" },
{ MethodCallingConvention.Generic, "generic" }, { MethodCallingConvention.Generic, null },
}; };
EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() { EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() {
@ -94,6 +96,9 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodImplAttributes.Synchronized, "synchronized" }, { MethodImplAttributes.Synchronized, "synchronized" },
{ MethodImplAttributes.NoInlining, "noinlining" }, { MethodImplAttributes.NoInlining, "noinlining" },
{ MethodImplAttributes.NoOptimization, "nooptimization" }, { MethodImplAttributes.NoOptimization, "nooptimization" },
{ MethodImplAttributes.PreserveSig, "preservesig" },
{ MethodImplAttributes.InternalCall, "internalcall" },
{ MethodImplAttributes.ForwardRef, "forwardref" },
}; };
public void DisassembleMethod(MethodDefinition method) public void DisassembleMethod(MethodDefinition method)
@ -115,12 +120,53 @@ namespace ICSharpCode.Decompiler.Disassembler
//emit flags //emit flags
WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility);
WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags);
if(method.IsCompilerControlled) output.Write("privatescope ");
if ((method.Attributes & MethodAttributes.PInvokeImpl) == MethodAttributes.PInvokeImpl) {
output.Write("pinvokeimpl");
if (method.HasPInvokeInfo) {
PInvokeInfo info = method.PInvokeInfo;
output.Write("(\"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.Module.Name) + "\"");
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name)
output.Write(" as \"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.EntryPoint) + "\"");
if (info.IsNoMangle)
output.Write(" nomangle");
if (info.IsCharSetAnsi)
output.Write(" ansi");
else if (info.IsCharSetAuto)
output.Write(" autochar");
else if (info.IsCharSetUnicode)
output.Write(" unicode");
if (info.SupportsLastError)
output.Write(" lasterr");
if (info.IsCallConvCdecl)
output.Write(" cdecl");
else if (info.IsCallConvFastcall)
output.Write(" fastcall");
else if (info.IsCallConvStdCall)
output.Write(" stdcall");
else if (info.IsCallConvThiscall)
output.Write(" thiscall");
else if (info.IsCallConvWinapi)
output.Write(" winapi");
output.Write(')');
}
output.Write(' ');
}
output.WriteLine(); output.WriteLine();
output.Indent(); output.Indent();
if (method.ExplicitThis) {
if (method.HasThis) output.Write("instance explicit ");
} else if (method.HasThis) {
output.Write("instance "); output.Write("instance ");
}
//call convention //call convention
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention);
@ -128,7 +174,16 @@ namespace ICSharpCode.Decompiler.Disassembler
//return type //return type
method.ReturnType.WriteTo(output); method.ReturnType.WriteTo(output);
output.Write(' '); output.Write(' ');
output.Write(DisassemblerHelpers.Escape(method.Name)); if (method.MethodReturnType.HasMarshalInfo) {
WriteMarshalInfo(method.MethodReturnType.MarshalInfo);
}
if (method.IsCompilerControlled) {
output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8")));
} else {
output.Write(DisassemblerHelpers.Escape(method.Name));
}
WriteTypeParameters(output, method); WriteTypeParameters(output, method);
//( params ) //( params )
@ -149,36 +204,455 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl);
output.Unindent(); output.Unindent();
if (method.HasBody || method.HasCustomAttributes) { OpenBlock(defaultCollapsed: isInType);
OpenBlock(defaultCollapsed: isInType); WriteAttributes(method.CustomAttributes);
WriteAttributes(method.CustomAttributes); if (method.HasOverrides) {
foreach (var methodOverride in method.Overrides) {
if (method.HasBody) { output.Write(".override method ");
// create IL code mappings - used in debugger methodOverride.WriteTo(output);
CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember); output.WriteLine();
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember); }
}
foreach (var p in method.Parameters) {
WriteParameterAttributes(p);
}
WriteSecurityDeclarations(method);
if (method.HasBody) {
// create IL code mappings - used in debugger
CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember);
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember);
methodBodyDisassembler.Disassemble(method.Body, methodMapping);
}
CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));
}
#region Write Security Declarations
void WriteSecurityDeclarations(ISecurityDeclarationProvider secDeclProvider)
{
if (!secDeclProvider.HasSecurityDeclarations)
return;
foreach (var secdecl in secDeclProvider.SecurityDeclarations) {
output.Write(".permissionset ");
switch (secdecl.Action) {
case SecurityAction.Request:
output.Write("request");
break;
case SecurityAction.Demand:
output.Write("demand");
break;
case SecurityAction.Assert:
output.Write("assert");
break;
case SecurityAction.Deny:
output.Write("deny");
break;
case SecurityAction.PermitOnly:
output.Write("permitonly");
break;
case SecurityAction.LinkDemand:
output.Write("linkcheck");
break;
case SecurityAction.InheritDemand:
output.Write("inheritcheck");
break;
case SecurityAction.RequestMinimum:
output.Write("reqmin");
break;
case SecurityAction.RequestOptional:
output.Write("reqopt");
break;
case SecurityAction.RequestRefuse:
output.Write("reqrefuse");
break;
case SecurityAction.PreJitGrant:
output.Write("prejitgrant");
break;
case SecurityAction.PreJitDeny:
output.Write("prejitdeny");
break;
case SecurityAction.NonCasDemand:
output.Write("noncasdemand");
break;
case SecurityAction.NonCasLinkDemand:
output.Write("noncaslinkdemand");
break;
case SecurityAction.NonCasInheritance:
output.Write("noncasinheritance");
break;
default:
output.Write(secdecl.Action.ToString());
break;
}
output.WriteLine(" = {");
output.Indent();
for (int i = 0; i < secdecl.SecurityAttributes.Count; i++) {
SecurityAttribute sa = secdecl.SecurityAttributes[i];
if (sa.AttributeType.Scope == sa.AttributeType.Module) {
output.Write("class ");
output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(sa.AttributeType)));
} else {
sa.AttributeType.WriteTo(output, ILNameSyntax.TypeName);
}
output.Write(" = {");
if (sa.HasFields || sa.HasProperties) {
output.WriteLine();
output.Indent();
foreach (CustomAttributeNamedArgument na in sa.Fields) {
output.Write("field ");
WriteSecurityDeclarationArgument(na);
output.WriteLine();
}
foreach (CustomAttributeNamedArgument na in sa.Properties) {
output.Write("property ");
WriteSecurityDeclarationArgument(na);
output.WriteLine();
}
output.Unindent();
}
output.Write('}');
methodBodyDisassembler.Disassemble(method.Body, methodMapping); if (i + 1< secdecl.SecurityAttributes.Count)
output.Write(',');
output.WriteLine();
}
output.Unindent();
output.WriteLine("}");
}
}
void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na)
{
TypeReference type = na.Argument.Type;
if (type.MetadataType == MetadataType.Class || type.MetadataType == MetadataType.ValueType) {
output.Write("enum ");
if (type.Scope != type.Module) {
output.Write("class ");
output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(type)));
} else {
type.WriteTo(output, ILNameSyntax.TypeName);
} }
CloseBlock("End of method " + method.DeclaringType.Name + "." + method.Name);
} else { } else {
output.WriteLine(); type.WriteTo(output);
}
output.Write(' ');
output.Write(DisassemblerHelpers.Escape(na.Name));
output.Write(" = ");
if (na.Argument.Value is string) {
// secdecls use special syntax for strings
output.Write("string('{0}')", NRefactory.CSharp.OutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'"));
} else {
WriteConstant(na.Argument.Value);
}
}
string GetAssemblyQualifiedName(TypeReference type)
{
AssemblyNameReference anr = type.Scope as AssemblyNameReference;
if (anr == null) {
ModuleDefinition md = type.Scope as ModuleDefinition;
if (md != null) {
anr = md.Assembly.Name;
}
}
if (anr != null) {
return type.FullName + ", " + anr.FullName;
} else {
return type.FullName;
}
}
#endregion
#region WriteMarshalInfo
void WriteMarshalInfo(MarshalInfo marshalInfo)
{
output.Write("marshal(");
WriteNativeType(marshalInfo.NativeType, marshalInfo);
output.Write(") ");
}
void WriteNativeType(NativeType nativeType, MarshalInfo marshalInfo = null)
{
switch (nativeType) {
case NativeType.None:
break;
case NativeType.Boolean:
output.Write("bool");
break;
case NativeType.I1:
output.Write("int8");
break;
case NativeType.U1:
output.Write("unsigned int8");
break;
case NativeType.I2:
output.Write("int16");
break;
case NativeType.U2:
output.Write("unsigned int16");
break;
case NativeType.I4:
output.Write("int32");
break;
case NativeType.U4:
output.Write("unsigned int32");
break;
case NativeType.I8:
output.Write("int64");
break;
case NativeType.U8:
output.Write("unsigned int64");
break;
case NativeType.R4:
output.Write("float32");
break;
case NativeType.R8:
output.Write("float64");
break;
case NativeType.LPStr:
output.Write("lpstr");
break;
case NativeType.Int:
output.Write("int");
break;
case NativeType.UInt:
output.Write("unsigned int");
break;
case NativeType.Func:
goto default; // ??
case NativeType.Array:
ArrayMarshalInfo ami = (ArrayMarshalInfo)marshalInfo;
if (ami == null)
goto default;
if (ami.ElementType != NativeType.Max)
WriteNativeType(ami.ElementType);
output.Write('[');
if (ami.SizeParameterMultiplier == 0) {
output.Write(ami.Size.ToString());
} else {
if (ami.Size >= 0)
output.Write(ami.Size.ToString());
output.Write(" + ");
output.Write(ami.SizeParameterIndex.ToString());
}
output.Write(']');
break;
case NativeType.Currency:
output.Write("currency");
break;
case NativeType.BStr:
output.Write("bstr");
break;
case NativeType.LPWStr:
output.Write("lpwstr");
break;
case NativeType.LPTStr:
output.Write("lptstr");
break;
case NativeType.FixedSysString:
output.Write("fixed sysstring[{0}]", ((FixedSysStringMarshalInfo)marshalInfo).Size);
break;
case NativeType.IUnknown:
output.Write("iunknown");
break;
case NativeType.IDispatch:
output.Write("idispatch");
break;
case NativeType.Struct:
output.Write("struct");
break;
case NativeType.IntF:
output.Write("interface");
break;
case NativeType.SafeArray:
output.Write("safearray ");
SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo;
if (sami != null) {
switch (sami.ElementType) {
case VariantType.None:
break;
case VariantType.I2:
output.Write("int16");
break;
case VariantType.I4:
output.Write("int32");
break;
case VariantType.R4:
output.Write("float32");
break;
case VariantType.R8:
output.Write("float64");
break;
case VariantType.CY:
output.Write("currency");
break;
case VariantType.Date:
output.Write("date");
break;
case VariantType.BStr:
output.Write("bstr");
break;
case VariantType.Dispatch:
output.Write("idispatch");
break;
case VariantType.Error:
output.Write("error");
break;
case VariantType.Bool:
output.Write("bool");
break;
case VariantType.Variant:
output.Write("variant");
break;
case VariantType.Unknown:
output.Write("iunknown");
break;
case VariantType.Decimal:
output.Write("decimal");
break;
case VariantType.I1:
output.Write("int8");
break;
case VariantType.UI1:
output.Write("unsigned int8");
break;
case VariantType.UI2:
output.Write("unsigned int16");
break;
case VariantType.UI4:
output.Write("unsigned int32");
break;
case VariantType.Int:
output.Write("int");
break;
case VariantType.UInt:
output.Write("unsigned int");
break;
default:
output.Write(sami.ElementType.ToString());
break;
}
}
break;
case NativeType.FixedArray:
output.Write("fixed array");
FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo;
if (fami != null) {
output.Write("[{0}]", fami.Size);
if (fami.ElementType != NativeType.None) {
output.Write(' ');
WriteNativeType(fami.ElementType);
}
}
break;
case NativeType.ByValStr:
output.Write("byvalstr");
break;
case NativeType.ANSIBStr:
output.Write("ansi bstr");
break;
case NativeType.TBStr:
output.Write("tbstr");
break;
case NativeType.VariantBool:
output.Write("variant bool");
break;
case NativeType.ASAny:
output.Write("as any");
break;
case NativeType.LPStruct:
output.Write("lpstruct");
break;
case NativeType.CustomMarshaler:
CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo;
if (cmi == null)
goto default;
output.Write("custom(\"{0}\", \"{1}\"",
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.ManagedType.FullName),
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.Cookie));
if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) {
output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.OutputVisitor.ConvertString(cmi.UnmanagedType));
}
output.Write(')');
break;
case NativeType.Error:
output.Write("error");
break;
default:
output.Write(nativeType.ToString());
break;
} }
} }
#endregion
void WriteParameters(Collection<ParameterDefinition> parameters) void WriteParameters(Collection<ParameterDefinition> parameters)
{ {
for (int i = 0; i < parameters.Count; i++) { for (int i = 0; i < parameters.Count; i++) {
var p = parameters[i]; var p = parameters[i];
if (p.IsIn)
output.Write("[in] ");
if (p.IsOut)
output.Write("[out] ");
if (p.IsOptional)
output.Write("[opt] ");
p.ParameterType.WriteTo(output); p.ParameterType.WriteTo(output);
output.Write(' '); output.Write(' ');
if (p.HasMarshalInfo) {
WriteMarshalInfo(p.MarshalInfo);
}
output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p); output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p);
if (i < parameters.Count - 1) if (i < parameters.Count - 1)
output.Write(','); output.Write(',');
output.WriteLine(); output.WriteLine();
} }
} }
bool HasParameterAttributes(ParameterDefinition p)
{
return p.HasConstant || p.HasCustomAttributes;
}
void WriteParameterAttributes(ParameterDefinition p)
{
if (!HasParameterAttributes(p))
return;
output.Write(".param [{0}]", p.Index + 1);
if (p.HasConstant) {
output.Write(" = ");
WriteConstant(p.Constant);
}
output.WriteLine();
WriteAttributes(p.CustomAttributes);
}
void WriteConstant(object constant)
{
if (constant == null) {
output.Write("nullref");
} else {
string typeName = DisassemblerHelpers.PrimitiveTypeName(constant.GetType().FullName);
if (typeName != null && typeName != "string") {
output.Write(typeName);
output.Write('(');
float? cf = constant as float?;
double? cd = constant as double?;
if (cf.HasValue && (float.IsNaN(cf.Value) || float.IsInfinity(cf.Value))) {
output.Write("0x{0:x8}", BitConverter.ToInt32(BitConverter.GetBytes(cf.Value), 0));
} else if (cd.HasValue && (double.IsNaN(cd.Value) || double.IsInfinity(cd.Value))) {
output.Write("0x{0:x16}", BitConverter.DoubleToInt64Bits(cd.Value));
} else {
DisassemblerHelpers.WriteOperand(output, constant);
}
output.Write(')');
} else {
DisassemblerHelpers.WriteOperand(output, constant);
}
}
}
#endregion #endregion
#region Disassemble Field #region Disassemble Field
@ -207,20 +681,26 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteDefinition(".field ", field); output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes); const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes);
if (field.HasMarshalInfo) {
WriteMarshalInfo(field.MarshalInfo);
}
field.FieldType.WriteTo(output); field.FieldType.WriteTo(output);
output.Write(' '); output.Write(' ');
output.Write(DisassemblerHelpers.Escape(field.Name)); output.Write(DisassemblerHelpers.Escape(field.Name));
if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA) {
output.Write(" at I_{0:x8}", field.RVA);
}
if (field.HasConstant) { if (field.HasConstant) {
output.Write(" = "); output.Write(" = ");
DisassemblerHelpers.WriteOperand(output, field.Constant); WriteConstant(field.Constant);
} }
output.WriteLine();
if (field.HasCustomAttributes) { if (field.HasCustomAttributes) {
OpenBlock(false); output.MarkFoldStart();
WriteAttributes(field.CustomAttributes); WriteAttributes(field.CustomAttributes);
CloseBlock(); output.MarkFoldEnd();
} else {
output.WriteLine();
} }
} }
#endregion #endregion
@ -239,16 +719,28 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteDefinition(".property ", property); output.WriteDefinition(".property ", property);
WriteFlags(property.Attributes, propertyAttributes); WriteFlags(property.Attributes, propertyAttributes);
if (property.HasThis)
output.Write("instance ");
property.PropertyType.WriteTo(output); property.PropertyType.WriteTo(output);
output.Write(' '); output.Write(' ');
output.Write(DisassemblerHelpers.Escape(property.Name)); output.Write(DisassemblerHelpers.Escape(property.Name));
output.Write("(");
if (property.HasParameters) {
output.WriteLine();
output.Indent();
WriteParameters(property.Parameters);
output.Unindent();
}
output.Write(")");
OpenBlock(false); OpenBlock(false);
WriteAttributes(property.CustomAttributes); WriteAttributes(property.CustomAttributes);
WriteNestedMethod(".get", property.GetMethod); WriteNestedMethod(".get", property.GetMethod);
WriteNestedMethod(".set", property.SetMethod); WriteNestedMethod(".set", property.SetMethod);
foreach (var method in property.OtherMethods) { foreach (var method in property.OtherMethods) {
WriteNestedMethod(".method", method); WriteNestedMethod(".other", method);
} }
CloseBlock(); CloseBlock();
} }
@ -257,16 +749,10 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
if (method == null) if (method == null)
return; return;
if (detectControlStructure) { output.Write(keyword);
output.WriteDefinition(keyword, method); output.Write(' ');
output.Write(' '); method.WriteTo(output);
DisassembleMethodInternal(method); output.WriteLine();
} else {
output.Write(keyword);
output.Write(' ');
method.WriteTo(output);
output.WriteLine();
}
} }
#endregion #endregion
@ -283,16 +769,16 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteDefinition(".event ", ev); output.WriteDefinition(".event ", ev);
WriteFlags(ev.Attributes, eventAttributes); WriteFlags(ev.Attributes, eventAttributes);
ev.EventType.WriteTo(output); ev.EventType.WriteTo(output, ILNameSyntax.TypeName);
output.Write(' '); output.Write(' ');
output.Write(DisassemblerHelpers.Escape(ev.Name)); output.Write(DisassemblerHelpers.Escape(ev.Name));
OpenBlock(false); OpenBlock(false);
WriteAttributes(ev.CustomAttributes); WriteAttributes(ev.CustomAttributes);
WriteNestedMethod(".add", ev.AddMethod); WriteNestedMethod(".addon", ev.AddMethod);
WriteNestedMethod(".remove", ev.RemoveMethod); WriteNestedMethod(".removeon", ev.RemoveMethod);
WriteNestedMethod(".invoke", ev.InvokeMethod); WriteNestedMethod(".fire", ev.InvokeMethod);
foreach (var method in ev.OtherMethods) { foreach (var method in ev.OtherMethods) {
WriteNestedMethod(".method", method); WriteNestedMethod(".other", method);
} }
CloseBlock(); CloseBlock();
} }
@ -345,7 +831,7 @@ namespace ICSharpCode.Decompiler.Disassembler
const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;
WriteFlags(type.Attributes & ~masks, typeAttributes); WriteFlags(type.Attributes & ~masks, typeAttributes);
output.Write(DisassemblerHelpers.Escape(type.Name)); output.Write(DisassemblerHelpers.Escape(type.DeclaringType != null ? type.Name : type.FullName));
WriteTypeParameters(output, type); WriteTypeParameters(output, type);
output.MarkFoldStart(defaultCollapsed: isInType); output.MarkFoldStart(defaultCollapsed: isInType);
output.WriteLine(); output.WriteLine();
@ -353,7 +839,7 @@ namespace ICSharpCode.Decompiler.Disassembler
if (type.BaseType != null) { if (type.BaseType != null) {
output.Indent(); output.Indent();
output.Write("extends "); output.Write("extends ");
type.BaseType.WriteTo(output, true); type.BaseType.WriteTo(output, ILNameSyntax.TypeName);
output.WriteLine(); output.WriteLine();
output.Unindent(); output.Unindent();
} }
@ -366,9 +852,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("implements "); output.Write("implements ");
else else
output.Write(" "); output.Write(" ");
if (type.Interfaces[index].Namespace != null) type.Interfaces[index].WriteTo(output, ILNameSyntax.TypeName);
output.Write("{0}.", type.Interfaces[index].Namespace);
output.Write(type.Interfaces[index].Name);
} }
output.WriteLine(); output.WriteLine();
output.Unindent(); output.Unindent();
@ -379,6 +863,7 @@ namespace ICSharpCode.Decompiler.Disassembler
bool oldIsInType = isInType; bool oldIsInType = isInType;
isInType = true; isInType = true;
WriteAttributes(type.CustomAttributes); WriteAttributes(type.CustomAttributes);
WriteSecurityDeclarations(type);
if (type.HasLayoutInfo) { if (type.HasLayoutInfo) {
output.WriteLine(".pack {0}", type.PackingSize); output.WriteLine(".pack {0}", type.PackingSize);
output.WriteLine(".size {0}", type.ClassSize); output.WriteLine(".size {0}", type.ClassSize);
@ -401,13 +886,13 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
output.WriteLine(); output.WriteLine();
} }
if (type.HasProperties) { if (type.HasMethods) {
output.WriteLine("// Properties"); output.WriteLine("// Methods");
foreach (var prop in type.Properties) { foreach (var m in type.Methods) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop); DisassembleMethod(m);
output.WriteLine();
} }
output.WriteLine();
} }
if (type.HasEvents) { if (type.HasEvents) {
output.WriteLine("// Events"); output.WriteLine("// Events");
@ -418,18 +903,15 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
output.WriteLine(); output.WriteLine();
} }
if (type.HasMethods) { if (type.HasProperties) {
output.WriteLine("// Methods"); output.WriteLine("// Properties");
var accessorMethods = type.GetAccessorMethods(); foreach (var prop in type.Properties) {
foreach (var m in type.Methods) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
if (!(detectControlStructure && accessorMethods.Contains(m))) { DisassembleProperty(prop);
DisassembleMethod(m);
output.WriteLine();
}
} }
output.WriteLine();
} }
CloseBlock("End of class " + type.FullName); CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName));
isInType = oldIsInType; isInType = oldIsInType;
} }
@ -446,18 +928,18 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (gp.HasNotNullableValueTypeConstraint) { } else if (gp.HasNotNullableValueTypeConstraint) {
output.Write("valuetype "); output.Write("valuetype ");
} }
if (gp.HasDefaultConstructorConstraint) {
output.Write(".ctor ");
}
if (gp.HasConstraints) { if (gp.HasConstraints) {
output.Write('('); output.Write('(');
for (int j = 0; j < gp.Constraints.Count; j++) { for (int j = 0; j < gp.Constraints.Count; j++) {
if (j > 0) if (j > 0)
output.Write(", "); output.Write(", ");
gp.Constraints[j].WriteTo(output, true); gp.Constraints[j].WriteTo(output, ILNameSyntax.TypeName);
} }
output.Write(") "); output.Write(") ");
} }
if (gp.HasDefaultConstructorConstraint) {
output.Write(".ctor ");
}
if (gp.IsContravariant) { if (gp.IsContravariant) {
output.Write('-'); output.Write('-');
} else if (gp.IsCovariant) { } else if (gp.IsCovariant) {
@ -600,9 +1082,12 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
output.Write(".assembly " + DisassemblerHelpers.Escape(asm.Name.Name)); output.Write(".assembly " + DisassemblerHelpers.Escape(asm.Name.Name));
OpenBlock(false); OpenBlock(false);
Version v = asm.Name.Version; WriteAttributes(asm.CustomAttributes);
if (v != null) { WriteSecurityDeclarations(asm);
output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision); if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0) {
output.Write(".publickey = ");
WriteBlob(asm.Name.PublicKey);
output.WriteLine();
} }
if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None) { if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None) {
output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm); output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm);
@ -610,13 +1095,64 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(" // SHA1"); output.Write(" // SHA1");
output.WriteLine(); output.WriteLine();
} }
if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0) { Version v = asm.Name.Version;
output.Write(".publickey = "); if (v != null) {
WriteBlob(asm.Name.PublicKey); output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision);
output.WriteLine();
} }
WriteAttributes(asm.CustomAttributes);
CloseBlock(); CloseBlock();
} }
public void WriteAssemblyReferences(ModuleDefinition module)
{
foreach (var mref in module.ModuleReferences) {
output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(mref.Name));
}
foreach (var aref in module.AssemblyReferences) {
output.Write(".assembly extern {0}", DisassemblerHelpers.Escape(aref.Name));
OpenBlock(false);
if (aref.PublicKeyToken != null) {
output.Write(".publickeytoken = ");
WriteBlob(aref.PublicKeyToken);
output.WriteLine();
}
if (aref.Version != null) {
output.WriteLine(".ver {0}:{1}:{2}:{3}", aref.Version.Major, aref.Version.Minor, aref.Version.Build, aref.Version.Revision);
}
CloseBlock();
}
}
public void WriteModuleHeader(ModuleDefinition module)
{
if (module.HasExportedTypes) {
foreach (ExportedType exportedType in module.ExportedTypes) {
output.Write(".class extern ");
if (exportedType.IsForwarder)
output.Write("forwarder ");
output.Write(exportedType.DeclaringType != null ? exportedType.Name : exportedType.FullName);
OpenBlock(false);
if (exportedType.DeclaringType != null)
output.WriteLine(".class extern {0}", DisassemblerHelpers.Escape(exportedType.DeclaringType.FullName));
else
output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name));
CloseBlock();
}
}
output.WriteLine(".module {0}", module.Name);
output.WriteLine("// MVID: {0}", module.Mvid.ToString("B").ToUpperInvariant());
// TODO: imagebase, file alignment, stackreserve, subsystem
output.WriteLine(".corflags 0x{0:x} // {1}", module.Attributes, module.Attributes.ToString());
WriteAttributes(module.CustomAttributes);
}
public void WriteModuleContents(ModuleDefinition module)
{
foreach (TypeDefinition td in module.Types) {
DisassembleType(td);
output.WriteLine();
}
}
} }
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -61,6 +61,7 @@
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" /> <Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" /> <Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DecimalConstantTransform.cs" />
<Compile Include="Ast\Transforms\DeclareVariables.cs" /> <Compile Include="Ast\Transforms\DeclareVariables.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" /> <Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceExtensionMethods.cs" /> <Compile Include="Ast\Transforms\IntroduceExtensionMethods.cs" />

10
ICSharpCode.Decompiler/ILAst/GotoRemoval.cs

@ -91,7 +91,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
var defaultCase = ilSwitch.CaseBlocks.Where(cb => cb.Values == null).SingleOrDefault(); var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null);
// If there is no default block, remove empty case blocks // If there is no default block, remove empty case blocks
if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak))) { if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak))) {
ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak)); ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak));
@ -140,14 +140,14 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
ILNode breakBlock = GetParents(gotoExpr).Where(n => n is ILWhileLoop || n is ILSwitch).FirstOrDefault(); ILNode breakBlock = GetParents(gotoExpr).FirstOrDefault(n => n is ILWhileLoop || n is ILSwitch);
if (breakBlock != null && target == Exit(breakBlock, new HashSet<ILNode>() { gotoExpr })) { if (breakBlock != null && target == Exit(breakBlock, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopOrSwitchBreak; gotoExpr.Code = ILCode.LoopOrSwitchBreak;
gotoExpr.Operand = null; gotoExpr.Operand = null;
return true; return true;
} }
ILNode continueBlock = GetParents(gotoExpr).Where(n => n is ILWhileLoop).FirstOrDefault(); ILNode continueBlock = GetParents(gotoExpr).FirstOrDefault(n => n is ILWhileLoop);
if (continueBlock != null && target == Enter(continueBlock, new HashSet<ILNode>() { gotoExpr })) { if (continueBlock != null && target == Enter(continueBlock, new HashSet<ILNode>() { gotoExpr })) {
gotoExpr.Code = ILCode.LoopContinue; gotoExpr.Code = ILCode.LoopContinue;
gotoExpr.Operand = null; gotoExpr.Operand = null;
@ -209,10 +209,10 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (expr.Code == ILCode.Nop) { } else if (expr.Code == ILCode.Nop) {
return Exit(expr, visitedNodes); return Exit(expr, visitedNodes);
} else if (expr.Code == ILCode.LoopOrSwitchBreak) { } else if (expr.Code == ILCode.LoopOrSwitchBreak) {
ILNode breakBlock = GetParents(expr).Where(n => n is ILWhileLoop || n is ILSwitch).First(); ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch);
return Exit(breakBlock, new HashSet<ILNode>() { expr }); return Exit(breakBlock, new HashSet<ILNode>() { expr });
} else if (expr.Code == ILCode.LoopContinue) { } else if (expr.Code == ILCode.LoopContinue) {
ILNode continueBlock = GetParents(expr).Where(n => n is ILWhileLoop).First(); ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop);
return Enter(continueBlock, new HashSet<ILNode>() { expr }); return Enter(continueBlock, new HashSet<ILNode>() { expr });
} else { } else {
return expr; return expr;

46
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -426,13 +426,12 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
// Occasionally the compiler generates unreachable code - it can be usually just ignored // Occasionally the compilers or obfuscators generate unreachable code (which migt be intentonally invalid)
var reachableBody = body.Where(b => b.StackBefore != null); // I belive it is safe to just remove it
var unreachableBody = body.Where(b => b.StackBefore == null); body.RemoveAll(b => b.StackBefore == null);
// Genertate temporary variables to replace stack // Genertate temporary variables to replace stack
// Unrachable code does not need temporary variables - the values are never pushed on the stack for consuption foreach(ByteCode byteCode in body) {
foreach(ByteCode byteCode in reachableBody) {
int argIdx = 0; int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count; int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) { for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
@ -450,19 +449,18 @@ namespace ICSharpCode.Decompiler.ILAst
// Try to use single temporary variable insted of several if possilbe (especially useful for dup) // Try to use single temporary variable insted of several if possilbe (especially useful for dup)
// This has to be done after all temporary variables are assigned so we know about all loads // This has to be done after all temporary variables are assigned so we know about all loads
// Unrachable code will not have any StoreTo foreach(ByteCode byteCode in body) {
foreach(ByteCode byteCode in reachableBody) {
if (byteCode.StoreTo != null && byteCode.StoreTo.Count > 1) { if (byteCode.StoreTo != null && byteCode.StoreTo.Count > 1) {
var locVars = byteCode.StoreTo; var locVars = byteCode.StoreTo;
// For each of the variables, find the location where it is loaded - there should be preciesly one // For each of the variables, find the location where it is loaded - there should be preciesly one
var loadedBy = locVars.Select(locVar => reachableBody.SelectMany(bc => bc.StackBefore).Where(s => s.LoadFrom == locVar).Single()).ToList(); var loadedBy = locVars.Select(locVar => body.SelectMany(bc => bc.StackBefore).Single(s => s.LoadFrom == locVar)).ToList();
// We now know that all the variables have a single load, // We now know that all the variables have a single load,
// Let's make sure that they have also a single store - us // Let's make sure that they have also a single store - us
if (loadedBy.All(slot => slot.PushedBy.Length == 1 && slot.PushedBy[0] == byteCode)) { if (loadedBy.All(slot => slot.PushedBy.Length == 1 && slot.PushedBy[0] == byteCode)) {
// Great - we can reduce everything into single variable // Great - we can reduce everything into single variable
ILVariable tmpVar = new ILVariable() { Name = string.Format("expr_{0:X2}", byteCode.Offset), IsGenerated = true }; ILVariable tmpVar = new ILVariable() { Name = string.Format("expr_{0:X2}", byteCode.Offset), IsGenerated = true };
byteCode.StoreTo = new List<ILVariable>() { tmpVar }; byteCode.StoreTo = new List<ILVariable>() { tmpVar };
foreach(ByteCode bc in reachableBody) { foreach(ByteCode bc in body) {
for (int i = 0; i < bc.StackBefore.Count; i++) { for (int i = 0; i < bc.StackBefore.Count; i++) {
// Is it one of the variable to be merged? // Is it one of the variable to be merged?
if (locVars.Contains(bc.StackBefore[i].LoadFrom)) { if (locVars.Contains(bc.StackBefore[i].LoadFrom)) {
@ -572,7 +570,7 @@ namespace ICSharpCode.Decompiler.ILAst
Loads = new List<ByteCode>() { load } Loads = new List<ByteCode>() { load }
}); });
} else if (storedBy.Length == 1) { } else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Where(v => v.Stores.Contains(storedBy[0])).Single(); VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
newVar.Loads.Add(load); newVar.Loads.Add(load);
} else { } else {
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Union(storedBy).Any()).ToList(); List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Union(storedBy).Any()).ToList();
@ -658,12 +656,14 @@ namespace ICSharpCode.Decompiler.ILAst
// Find the first and widest scope // Find the first and widest scope
int tryStart = ehs.Min(eh => eh.TryStart.Offset); int tryStart = ehs.Min(eh => eh.TryStart.Offset);
int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();
// Remember that any part of the body migt have been removed due to unreachability
// Cut all instructions up to the try block // Cut all instructions up to the try block
{ {
int tryStartIdx; int tryStartIdx = 0;
for (tryStartIdx = 0; body[tryStartIdx].Offset != tryStart; tryStartIdx++); while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart) tryStartIdx++;
ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx)));
} }
@ -671,24 +671,22 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
HashSet<ExceptionHandler> nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd))); HashSet<ExceptionHandler> nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)));
ehs.ExceptWith(nestedEHs); ehs.ExceptWith(nestedEHs);
int tryEndIdx; int tryEndIdx = 0;
for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd) tryEndIdx++;
tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs)); tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs));
} }
// Cut all handlers // Cut all handlers
tryCatchBlock.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>(); tryCatchBlock.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>();
foreach(ExceptionHandler eh in handlers) { foreach(ExceptionHandler eh in handlers) {
int startIndex; int handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset;
for (startIndex = 0; body[startIndex].Offset != eh.HandlerStart.Offset; startIndex++); int startIdx = 0;
int endInclusiveIndex; while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset) startIdx++;
if (eh.HandlerEnd == null) endInclusiveIndex = body.Count - 1; int endIdx = 0;
// Note that the end(exclusive) instruction may not necessarly be in our body while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset) endIdx++;
else for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++); HashSet<ExceptionHandler> nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset)));
int count = 1 + endInclusiveIndex - startIndex;
HashSet<ExceptionHandler> nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < eh.HandlerEnd.Offset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= eh.HandlerEnd.Offset)));
ehs.ExceptWith(nestedEHs); ehs.ExceptWith(nestedEHs);
List<ILNode> handlerAst = ConvertToAst(body.CutRange(startIndex, count), nestedEHs); List<ILNode> handlerAst = ConvertToAst(body.CutRange(startIdx, endIdx - startIdx), nestedEHs);
if (eh.HandlerType == ExceptionHandlerType.Catch) { if (eh.HandlerType == ExceptionHandlerType.Catch) {
ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() { ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() {
ExceptionType = eh.CatchType, ExceptionType = eh.CatchType,

21
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -44,6 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst
JoinBasicBlocks, JoinBasicBlocks,
TransformDecimalCtorToConstant, TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj, SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit,
TransformArrayInitializers, TransformArrayInitializers,
TransformObjectInitializers, TransformObjectInitializers,
MakeAssignmentExpression, MakeAssignmentExpression,
@ -136,6 +137,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return; if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return;
modified |= block.RunOptimization(SimplifyLdObjAndStObj); modified |= block.RunOptimization(SimplifyLdObjAndStObj);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return; if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
modified |= block.RunOptimization(TransformArrayInitializers); modified |= block.RunOptimization(TransformArrayInitializers);
@ -308,6 +312,8 @@ namespace ICSharpCode.Decompiler.ILAst
/// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions. /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions.
/// ///
/// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)". /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)".
///
/// Also simplifies 'newobj(SomeDelegate, target, ldvirtftn(F, target))' to 'newobj(SomeDelegate, target, ldvirtftn(F))'
/// </summary> /// </summary>
void IntroducePropertyAccessInstructions(ILNode node) void IntroducePropertyAccessInstructions(ILNode node)
{ {
@ -365,6 +371,19 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter; expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter;
} }
} }
} else if (expr.Code == ILCode.Newobj && expr.Arguments.Count == 2) {
// Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'.
ILVariable target;
if (expr.Arguments[0].Match(ILCode.Ldloc, out target)
&& expr.Arguments[1].Code == ILCode.Ldvirtftn
&& expr.Arguments[1].Arguments.Count == 1
&& expr.Arguments[1].Arguments[0].MatchLdloc(target))
{
// Remove the 'target' argument from the ldvirtftn instruction.
// It's not needed in the translation to C#, and needs to be eliminated so that the target expression
// can be inlined.
expr.Arguments[1].Arguments.Clear();
}
} }
} }
@ -398,7 +417,7 @@ namespace ICSharpCode.Decompiler.ILAst
lastNode.IsUnconditionalControlFlow()) lastNode.IsUnconditionalControlFlow())
{ {
// Try to reuse the label // Try to reuse the label
ILLabel label = currNode is ILLabel ? ((ILLabel)currNode) : new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() };
// Terminate the last block // Terminate the last block
if (!lastNode.IsUnconditionalControlFlow()) { if (!lastNode.IsUnconditionalControlFlow()) {

18
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -141,6 +141,10 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
output.Write("catch "); output.Write("catch ");
output.WriteReference(ExceptionType.FullName, ExceptionType); output.WriteReference(ExceptionType.FullName, ExceptionType);
if (ExceptionVariable != null) {
output.Write(' ');
output.Write(ExceptionVariable.Name);
}
output.WriteLine(" {"); output.WriteLine(" {");
output.Indent(); output.Indent();
base.WriteTo(output); base.WriteTo(output);
@ -378,10 +382,10 @@ namespace ICSharpCode.Decompiler.ILAst
output.Write(((ILVariable)Operand).Name); output.Write(((ILVariable)Operand).Name);
if (this.InferredType != null) { if (this.InferredType != null) {
output.Write(':'); output.Write(':');
this.InferredType.WriteTo(output, true, true); this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) { if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:"); output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true); this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']'); output.Write(']');
} }
} }
@ -399,15 +403,15 @@ namespace ICSharpCode.Decompiler.ILAst
output.Write(Code.GetName()); output.Write(Code.GetName());
if (this.InferredType != null) { if (this.InferredType != null) {
output.Write(':'); output.Write(':');
this.InferredType.WriteTo(output, true, true); this.InferredType.WriteTo(output, ILNameSyntax.ShortTypeName);
if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) { if (this.ExpectedType != null && this.ExpectedType.FullName != this.InferredType.FullName) {
output.Write("[exp:"); output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true); this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']'); output.Write(']');
} }
} else if (this.ExpectedType != null) { } else if (this.ExpectedType != null) {
output.Write("[exp:"); output.Write("[exp:");
this.ExpectedType.WriteTo(output, true, true); this.ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write(']'); output.Write(']');
} }
output.Write('('); output.Write('(');
@ -425,13 +429,13 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (Operand is MethodReference) { } else if (Operand is MethodReference) {
MethodReference method = (MethodReference)Operand; MethodReference method = (MethodReference)Operand;
if (method.DeclaringType != null) { if (method.DeclaringType != null) {
method.DeclaringType.WriteTo(output, true, true); method.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write("::"); output.Write("::");
} }
output.WriteReference(method.Name, method); output.WriteReference(method.Name, method);
} else if (Operand is FieldReference) { } else if (Operand is FieldReference) {
FieldReference field = (FieldReference)Operand; FieldReference field = (FieldReference)Operand;
field.DeclaringType.WriteTo(output, true, true); field.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName);
output.Write("::"); output.Write("::");
output.WriteReference(field.Name, field); output.WriteReference(field.Name, field);
} else { } else {

32
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -47,7 +47,13 @@ namespace ICSharpCode.Decompiler.ILAst
numLdloca.Clear(); numLdloca.Clear();
// Analyse the whole method // Analyse the whole method
foreach(ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { AnalyzeNode(method);
}
void AnalyzeNode(ILNode node)
{
ILExpression expr = node as ILExpression;
if (expr != null) {
ILVariable locVar = expr.Operand as ILVariable; ILVariable locVar = expr.Operand as ILVariable;
if (locVar != null) { if (locVar != null) {
if (expr.Code == ILCode.Stloc) { if (expr.Code == ILCode.Stloc) {
@ -60,6 +66,16 @@ namespace ICSharpCode.Decompiler.ILAst
throw new NotSupportedException(expr.Code.ToString()); throw new NotSupportedException(expr.Code.ToString());
} }
} }
foreach (ILExpression child in expr.Arguments)
AnalyzeNode(child);
} else {
var catchBlock = node as ILTryCatchBlock.CatchBlock;
if (catchBlock != null && catchBlock.ExceptionVariable != null) {
numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + 1;
}
foreach (ILNode child in node.GetChildren())
AnalyzeNode(child);
} }
} }
@ -76,6 +92,20 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
bool modified = false; bool modified = false;
List<ILNode> body = block.Body; List<ILNode> body = block.Body;
if (block is ILTryCatchBlock.CatchBlock && body.Count > 1) {
ILVariable v = ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable;
if (v != null && v.IsGenerated) {
if (numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1) {
ILVariable v2;
ILExpression ldException;
if (body[0].Match(ILCode.Stloc, out v2, out ldException) && ldException.MatchLdloc(v)) {
body.RemoveAt(0);
((ILTryCatchBlock.CatchBlock)block).ExceptionVariable = v2;
modified = true;
}
}
}
}
for(int i = 0; i < body.Count - 1;) { for(int i = 0; i < body.Count - 1;) {
ILVariable locVar; ILVariable locVar;
ILExpression expr; ILExpression expr;

4
ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>(); Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
DecompilerContext context; readonly DecompilerContext context;
uint nextLabelIndex = 0; uint nextLabelIndex = 0;
@ -286,7 +286,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILLabel condLabel = caseLabels[i]; ILLabel condLabel = caseLabels[i];
// Find or create new case block // Find or create new case block
ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.Where(b => b.EntryGoto.Operand == condLabel).FirstOrDefault(); ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
if (caseBlock == null) { if (caseBlock == null) {
caseBlock = new ILSwitch.CaseBlock() { caseBlock = new ILSwitch.CaseBlock() {
Values = new List<int>(), Values = new List<int>(),

75
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -90,6 +90,10 @@ namespace ICSharpCode.Decompiler.ILAst
expr.Code = ILCode.Stobj; expr.Code = ILCode.Stobj;
expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
modified = true; modified = true;
} else if (expr.Code == ILCode.Cpobj) {
expr.Code = ILCode.Stobj;
expr.Arguments[1] = new ILExpression(ILCode.Ldobj, expr.Operand, expr.Arguments[1]);
modified = true;
} }
ILExpression arg, arg2; ILExpression arg, arg2;
TypeReference type; TypeReference type;
@ -440,6 +444,7 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion #endregion
#region IntroducePostIncrement #region IntroducePostIncrement
bool IntroducePostIncrement(List<ILNode> body, ILExpression expr, int pos) bool IntroducePostIncrement(List<ILNode> body, ILExpression expr, int pos)
{ {
bool modified = IntroducePostIncrementForVariables(body, expr, pos); bool modified = IntroducePostIncrementForVariables(body, expr, pos);
@ -452,7 +457,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return modified; return modified;
} }
bool IntroducePostIncrementForVariables(List<ILNode> body, ILExpression expr, int pos) bool IntroducePostIncrementForVariables(List<ILNode> body, ILExpression expr, int pos)
{ {
// Works for variables and static fields/properties // Works for variables and static fields/properties
@ -465,19 +470,50 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression exprInit; ILExpression exprInit;
if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated)) if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
return false; return false;
if (!(exprInit.Code == ILCode.Ldloc || exprInit.Code == ILCode.Ldsfld || (exprInit.Code == ILCode.CallGetter && exprInit.Arguments.Count == 0)))
return false;
//The next expression
ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
if (nextExpr == null) if (nextExpr == null)
return false; return false;
if (exprInit.Code == ILCode.CallGetter) {
if (!(nextExpr.Code == ILCode.CallSetter && IsGetterSetterPair(exprInit.Operand, nextExpr.Operand))) ILCode loadInstruction = exprInit.Code;
return false; ILCode storeInstruction = nextExpr.Code;
} else { bool recombineVariable = false;
if (!(nextExpr.Code == (exprInit.Code == ILCode.Ldloc ? ILCode.Stloc : ILCode.Stsfld) && nextExpr.Operand == exprInit.Operand))
// We only recognise local variables, static fields, and static getters with no arguments
switch (loadInstruction) {
case ILCode.Ldloc:
//Must be a matching store type
if (storeInstruction != ILCode.Stloc)
return false;
ILVariable loadVar = (ILVariable)exprInit.Operand;
ILVariable storeVar = (ILVariable)nextExpr.Operand;
if (loadVar != storeVar) {
if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable)
recombineVariable = true;
else
return false;
}
break;
case ILCode.Ldsfld:
if (storeInstruction != ILCode.Stsfld)
return false;
if (exprInit.Operand != nextExpr.Operand)
return false;
break;
case ILCode.CallGetter:
// non-static getters would have the 'this' argument
if (exprInit.Arguments.Count != 0)
return false;
if (storeInstruction != ILCode.CallSetter)
return false;
if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand))
return false;
break;
default:
return false; return false;
} }
ILExpression addExpr = nextExpr.Arguments[0]; ILExpression addExpr = nextExpr.Arguments[0];
int incrementAmount; int incrementAmount;
@ -485,12 +521,23 @@ namespace ICSharpCode.Decompiler.ILAst
if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar))) if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
return false; return false;
if (exprInit.Code == ILCode.Ldloc) if (recombineVariable) {
exprInit.Code = ILCode.Ldloca; // Split local variable, unsplit these two instances
else if (exprInit.Code == ILCode.CallGetter) foreach (var ilExpression in method.GetSelfAndChildrenRecursive<ILExpression>(expression => expression.Operand == nextExpr.Operand))
exprInit = new ILExpression(ILCode.AddressOf, null, exprInit); ilExpression.Operand = exprInit.Operand;
else }
exprInit.Code = ILCode.Ldsflda;
switch (loadInstruction) {
case ILCode.Ldloc:
exprInit.Code = ILCode.Ldloca;
break;
case ILCode.Ldsfld:
exprInit.Code = ILCode.Ldsflda;
break;
case ILCode.CallGetter:
exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
break;
}
expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit); expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
body.RemoveAt(pos + 1); // TODO ILRanges body.RemoveAt(pos + 1); // TODO ILRanges
return true; return true;

107
ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.ILAst
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr);
} }
} else { } else {
// Ternary operator tends to create long complicated return statements // Ternary operator tends to create long complicated return statements
if (opCode == ILCode.Ret) if (opCode == ILCode.Ret)
return false; return false;
@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst
// ... // ...
// v = NullCoalescing(ldloc(leftVar), rightExpr) // v = NullCoalescing(ldloc(leftVar), rightExpr)
// br(endBBLabel) // br(endBBLabel)
ILVariable v, v2; ILVariable v, v2;
ILExpression leftExpr, leftExpr2; ILExpression leftExpr, leftExpr2;
ILVariable leftVar; ILVariable leftVar;
@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILBasicBlock rightBB; ILBasicBlock rightBB;
ILExpression rightExpr; ILExpression rightExpr;
if (head.Body.Count >= 3 && if (head.Body.Count >= 3 &&
head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) && head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) && leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) && head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.MatchLdloc(leftVar) && leftExpr2.MatchLdloc(leftVar) &&
@ -234,6 +234,107 @@ namespace ICSharpCode.Decompiler.ILAst
return false; return false;
} }
public bool SimplifyCustomShortCircuit(List<ILNode> body, ILBasicBlock head, int pos)
{
Debug.Assert(body.Contains(head));
// --- looking for the following pattern ---
// stloc(targetVar, leftVar)
// brtrue(exitLabel, call(op_False, leftVar)
// br(followingBlock)
//
// FollowingBlock:
// stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
// br(exitLabel)
// ---
if (head.Body.Count < 3)
return false;
// looking for:
// stloc(targetVar, leftVar)
ILVariable targetVar;
ILExpression targetVarInitExpr;
if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr))
return false;
ILVariable leftVar;
if (!targetVarInitExpr.Match(ILCode.Ldloc, out leftVar))
return false;
// looking for:
// brtrue(exitLabel, call(op_False, leftVar)
// br(followingBlock)
ILExpression callExpr;
ILLabel exitLabel;
ILLabel followingBlock;
if(!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock))
return false;
if (labelGlobalRefCount[followingBlock] > 1)
return false;
MethodReference opFalse;
ILExpression opFalseArg;
if (!callExpr.Match(ILCode.Call, out opFalse, out opFalseArg))
return false;
// ignore operators other than op_False and op_True
if (opFalse.Name != "op_False" && opFalse.Name != "op_True")
return false;
if (!opFalseArg.MatchLdloc(leftVar))
return false;
ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock];
// FollowingBlock:
// stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
// br(exitLabel)
ILVariable _targetVar;
ILExpression opBitwiseCallExpr;
ILLabel _exitLabel;
if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel))
return false;
if (_targetVar != targetVar || exitLabel != _exitLabel)
return false;
MethodReference opBitwise;
ILExpression leftVarExpression;
ILExpression rightExpression;
if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression))
return false;
if (!opFalseArg.MatchLdloc(leftVarExpression.Operand as ILVariable))
return false;
// ignore operators other than op_BitwiseAnd and op_BitwiseOr
if (opBitwise.Name != "op_BitwiseAnd" && opBitwise.Name != "op_BitwiseOr")
return false;
// insert:
// stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression)
// br(exitLabel)
ILCode op = opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr;
if (op == ILCode.LogicAnd && opFalse.Name != "op_False")
return false;
if (op == ILCode.LogicOr && opFalse.Name != "op_True")
return false;
ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(op, opFalseArg, rightExpression);
shortCircuitExpr.Operand = opBitwise;
head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr));
head.Body.Add(new ILExpression(ILCode.Br, exitLabel));
body.Remove(followingBasicBlock);
return true;
}
ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right) ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right)
{ {
// Assuming that the inputs are already left associative // Assuming that the inputs are already left associative

4
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -267,6 +267,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.LogicAnd: case ILCode.LogicAnd:
case ILCode.LogicOr: case ILCode.LogicOr:
// if Operand is set the logic and/or expression is a custom operator
// we can deal with it the same as a normal invocation.
if (expr.Operand != null)
goto case ILCode.Call;
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);

75
ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs

@ -0,0 +1,75 @@
// 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;
public static class CustomShortCircuitOperators
{
private class B
{
public static bool operator true(CustomShortCircuitOperators.B x)
{
return true;
}
public static bool operator false(CustomShortCircuitOperators.B x)
{
return false;
}
}
private class C : CustomShortCircuitOperators.B
{
public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;
}
public static CustomShortCircuitOperators.C operator |(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;
}
public static bool operator !(CustomShortCircuitOperators.C x)
{
return false;
}
private static void Main()
{
CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
CustomShortCircuitOperators.C c2 = new CustomShortCircuitOperators.C();
CustomShortCircuitOperators.C c3 = c && c2;
CustomShortCircuitOperators.C c4 = c || c2;
Console.WriteLine(c3.ToString());
Console.WriteLine(c4.ToString());
}
private static void Test2()
{
CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
if (c && c)
{
Console.WriteLine(c.ToString());
}
if (!(c && c))
{
Console.WriteLine(c.ToString());
}
}
private static void Test3()
{
CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
if (c)
{
Console.WriteLine(c.ToString());
}
if (!c)
{
Console.WriteLine(c.ToString());
}
}
}
}

30
ICSharpCode.Decompiler/Tests/ExceptionHandling.cs

@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
using System.Threading;
public class ExceptionHandling public class ExceptionHandling
{ {
@ -55,13 +56,38 @@ public class ExceptionHandling
{ {
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message);
} }
catch (Exception ex) catch (Exception ex2)
{ {
Console.WriteLine(ex.Message); Console.WriteLine(ex2.Message);
} }
catch catch
{ {
Console.WriteLine("other"); Console.WriteLine("other");
} }
} }
public void NoUsingStatementBecauseTheVariableIsAssignedTo()
{
CancellationTokenSource cancellationTokenSource = null;
try
{
cancellationTokenSource = new CancellationTokenSource();
}
finally
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Dispose();
}
}
}
public void UsingStatementThatChangesTheVariable()
{
CancellationTokenSource cancellationTokenSource = null;
using (cancellationTokenSource)
{
cancellationTokenSource = new CancellationTokenSource();
}
}
} }

6
ICSharpCode.Decompiler/Tests/Generics.cs

@ -60,6 +60,12 @@ public static class Generics
} }
} }
private static Type type1 = typeof(List<>);
private static Type type2 = typeof(Generics.MyArray<>);
private static Type type3 = typeof(List<>.Enumerator);
private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>);
private static Type type5 = typeof(List<int>[]);
public static void MethodWithConstraint<T, S>() where T : class, S where S : ICloneable, new() public static void MethodWithConstraint<T, S>() where T : class, S where S : ICloneable, new()
{ {
} }

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

@ -15,7 +15,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var section = (AttributeSection)attribute.Parent; var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType; SimpleType type = attribute.Type as SimpleType;
if (section.AttributeTarget == "assembly" && if (section.AttributeTarget == "assembly" &&
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility")) (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "AssemblyVersion"))
{ {
attribute.Remove(); attribute.Remove();
if (section.Attributes.Count == 0) if (section.Attributes.Count == 0)

2
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -57,8 +57,10 @@
<ItemGroup> <ItemGroup>
<Compile Include="CallOverloadedMethod.cs" /> <Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" /> <Compile Include="CheckedUnchecked.cs" />
<Compile Include="CustomShortCircuitOperators.cs" />
<Compile Include="Helpers\CodeAssert.cs" /> <Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="IncrementDecrement.cs" /> <Compile Include="IncrementDecrement.cs" />
<Compile Include="PInvoke.cs" />
<Compile Include="QueryExpressions.cs" /> <Compile Include="QueryExpressions.cs" />
<Compile Include="Switch.cs" /> <Compile Include="Switch.cs" />
<Compile Include="UndocumentedExpressions.cs" /> <Compile Include="UndocumentedExpressions.cs" />

6
ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

@ -176,6 +176,12 @@ public class IncrementDecrement
return i++ + j; return i++ + j;
} }
public void PostIncrementInlineLocalVariable(Func<int, int> f)
{
int num = 0;
f(num++);
}
public int PostIncrementArrayElement(int[] array, int pos) public int PostIncrementArrayElement(int[] array, int pos)
{ {
return array[pos]--; return array[pos]--;

87
ICSharpCode.Decompiler/Tests/PInvoke.cs

@ -0,0 +1,87 @@
// 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.Runtime.InteropServices;
// P/Invoke and marshalling attribute tests
public class PInvoke
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 2)]
public struct MarshalAsTest
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] FixedArray;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.Bool)]
public int[] FixedBoolArray;
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public string[] SafeBStrArray;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string FixedString;
}
[StructLayout(LayoutKind.Explicit)]
public struct Rect
{
[FieldOffset(0)]
public int left;
[FieldOffset(4)]
public int top;
[FieldOffset(8)]
public int right;
[FieldOffset(12)]
public int bottom;
}
public static decimal MarshalAttributesOnPropertyAccessors
{
[return: MarshalAs(UnmanagedType.Currency)]
get
{
return 0m;
}
[param: MarshalAs(UnmanagedType.Currency)]
set
{
}
}
[DllImport("xyz.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Method([MarshalAs(UnmanagedType.LPStr)] string input);
[DllImport("xyz.dll")]
private static extern void New1(int ElemCnt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] ar);
[DllImport("xyz.dll")]
private static extern void New2([MarshalAs(UnmanagedType.LPArray, SizeConst = 128)] int[] ar);
[DllImport("xyz.dll")]
private static extern void New3([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Bool, SizeConst = 64, SizeParamIndex = 1)] int[] ar);
public void CustomMarshal1([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler")] object o)
{
}
public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler", MarshalCookie = "Cookie")] object o)
{
}
}

14
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\DelegateConstruction.cs"); TestFile(@"..\..\Tests\DelegateConstruction.cs");
} }
[Test, Ignore("arg-Variables in catch clauses")] [Test]
public void ExceptionHandling() public void ExceptionHandling()
{ {
TestFile(@"..\..\Tests\ExceptionHandling.cs"); TestFile(@"..\..\Tests\ExceptionHandling.cs");
@ -49,6 +49,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\Generics.cs"); TestFile(@"..\..\Tests\Generics.cs");
} }
[Test]
public void CustomShortCircuitOperators()
{
TestFile(@"..\..\Tests\CustomShortCircuitOperators.cs");
}
[Test] [Test]
public void IncrementDecrement() public void IncrementDecrement()
{ {
@ -73,6 +79,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\MultidimensionalArray.cs"); TestFile(@"..\..\Tests\MultidimensionalArray.cs");
} }
[Test]
public void PInvoke()
{
TestFile(@"..\..\Tests\PInvoke.cs");
}
[Test] [Test]
public void PropertiesAndEvents() public void PropertiesAndEvents()
{ {

61
ILSpy.BamlDecompiler/BamlResourceEntryNode.cs

@ -0,0 +1,61 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using Ricciolo.StylesExplorer.MarkupReflection;
namespace ILSpy.BamlDecompiler
{
public sealed class BamlResourceEntryNode : ResourceEntryNode
{
public BamlResourceEntryNode(string key, Stream data) : base(key, data)
{
}
public 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.ShowNode(t.Result, this, highlighting)
);
return true;
}
bool LoadBaml(AvalonEditTextOutput output)
{
var asm = this.Ancestors().OfType<AssemblyTreeNode>().FirstOrDefault().LoadedAssembly;
MemoryStream bamlStream = new MemoryStream();
Data.Position = 0;
Data.CopyTo(bamlStream);
bamlStream.Position = 0;
XDocument xamlDocument;
using (XmlBamlReader reader = new XmlBamlReader(bamlStream))
xamlDocument = XDocument.Load(reader);
output.Write(xamlDocument.ToString());
return true;
}
}
}

29
ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs

@ -0,0 +1,29 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using ICSharpCode.ILSpy.TreeNodes;
namespace ILSpy.BamlDecompiler
{
[Export(typeof(IResourceNodeFactory))]
public 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;
}
}
}

124
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{A6BAD2BA-76BA-461C-8B6D-418607591247}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ILSpy.BamlDecompiler</RootNamespace>
<AssemblyName>ILSpy.BamlDecompiler.Plugin</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\ILSpy\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>..\ILSpy\bin\Release\</OutputPath>
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="PresentationFramework">
<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>
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BamlResourceNodeFactory.cs" />
<Compile Include="BamlResourceEntryNode.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\AppDomainTypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlAssembly.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlFile.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlRecordType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\DotNetType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ITypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KnownInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\PropertyDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ResourceName.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\TypeDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\WpfDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlElement.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlNode.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlProperty.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlPropertyElement.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlReader.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlText.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlNamespace.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlPIMapping.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Ricciolo.StylesExplorer.MarkupReflection" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
<Name>ICSharpCode.AvalonEdit</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj">
<Project>{984CC812-9470-4A13-AFF9-CC44068D666C}</Project>
<Name>ICSharpCode.Decompiler</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\ILSpy\ILSpy.csproj">
<Project>{1E85EFF9-E370-4683-83E4-8A3D063FF791}</Project>
<Name>ILSpy</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj">
<Project>{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}</Project>
<Name>ICSharpCode.TreeView</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

31
ILSpy.BamlDecompiler/Properties/AssemblyInfo.cs

@ -0,0 +1,31 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ILSpy.BamlDecompiler.Plugin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ILSpy.BamlDecompiler.Plugin")]
[assembly: AssemblyCopyright("Copyright 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]

172
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs

@ -0,0 +1,172 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Threading;
using System.Security.Permissions;
using System.Security;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public delegate void AssemblyResolveEventHandler(object s, AssemblyResolveEventArgs e);
public class AppDomainTypeResolver : MarshalByRefObject, ITypeResolver
{
private readonly AppDomain _domain;
private string baseDir;
public event AssemblyResolveEventHandler AssemblyResolve;
public static AppDomainTypeResolver GetIntoNewAppDomain(string baseDir)
{
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = Environment.CurrentDirectory;
AppDomain domain = AppDomain.CreateDomain("AppDomainTypeResolver", null, info, new PermissionSet(PermissionState.Unrestricted));
AppDomainTypeResolver resolver = (AppDomainTypeResolver)domain.CreateInstanceAndUnwrap(typeof(AppDomainTypeResolver).Assembly.FullName,
typeof(AppDomainTypeResolver).FullName, false, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { domain, baseDir }, null, null, null);
return resolver;
}
Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Cerco di risolvere automaticamente
AssemblyName name = new AssemblyName(args.Name);
string fileName = Path.Combine(this.baseDir, name.Name + ".exe");
if (!File.Exists(fileName))
fileName = Path.Combine(this.baseDir, name.Name + ".dll");
// Carico il percorso autocalcolato
if (File.Exists(fileName))
return Assembly.LoadFile(fileName);
if (AssemblyResolve != null)
{
AssemblyResolveEventArgs e = new AssemblyResolveEventArgs(args.Name, this.baseDir);
AssemblyResolve(this, e);
if (!String.IsNullOrEmpty(e.Location) && File.Exists(e.Location))
return Assembly.LoadFile(e.Location);
}
return null;
}
public static void DestroyResolver(AppDomainTypeResolver resolver)
{
if (resolver == null) throw new ArgumentNullException("resolver");
ThreadPool.QueueUserWorkItem(delegate
{
AppDomain.Unload(resolver.Domain);
});
}
protected AppDomainTypeResolver(AppDomain domain, string baseDir)
{
_domain = domain;
this.baseDir = baseDir;
domain.AssemblyResolve += new ResolveEventHandler(domain_AssemblyResolve);
}
public BamlAssembly LoadAssembly(AssemblyName asm)
{
//return new BamlAssembly(Assembly.Load(asm));
return new BamlAssembly(_domain.Load(asm));
}
public BamlAssembly LoadAssembly(string location)
{
Assembly asm = Assembly.LoadFile(location);
return new BamlAssembly(asm);
//return _domain.Load(System.IO.File.ReadAllBytes(location));
//return Assembly.LoadFrom(location);
}
public BamlAssembly[] GetReferencedAssemblies(BamlAssembly asm)
{
AssemblyName[] list = asm.Assembly.GetReferencedAssemblies();
return (from an in list
select this.LoadAssembly(an)).ToArray();
}
public AppDomain Domain
{
get { return _domain; }
}
#region ITypeResolver Members
public IType GetTypeByAssemblyQualifiedName(string name)
{
return new DotNetType(name);
}
public IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType)
{
if (name == null) throw new ArgumentNullException("name");
if (ownerType == null) throw new ArgumentNullException("ownerType");
if (targetType == null) throw new ArgumentNullException("targetType");
Type dOwnerType = ((DotNetType)ownerType).Type;
Type dTargetType = ((DotNetType)targetType).Type;
try
{
DependencyPropertyDescriptor propertyDescriptor = DependencyPropertyDescriptor.FromName(name, dOwnerType, dTargetType);
if (propertyDescriptor != null)
return new WpfDependencyPropertyDescriptor(propertyDescriptor);
return null;
}
catch (Exception)
{
return null;
}
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
public class AssemblyResolveEventArgs : MarshalByRefObject
{
private string _location;
private string _name;
private string _baseDir;
public AssemblyResolveEventArgs(string name, string baseDir)
{
_name = name;
_baseDir = baseDir;
}
public string Location
{
get { return _location; }
set { _location = value; }
}
public string Name
{
get { return _name; }
}
public string BaseDir
{
get { return _baseDir; }
}
}
}

112
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs

@ -0,0 +1,112 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class BamlAssembly : MarshalByRefObject
{
private readonly string _filePath;
private Assembly _assembly;
private BamlFileList _bamlFile;
public BamlAssembly(Assembly assembly)
{
_assembly = assembly;
_filePath = assembly.CodeBase;
ReadBaml();
}
public BamlAssembly(string filePath)
{
this._filePath = Path.GetFullPath(filePath);
this._assembly = Assembly.LoadFile(this.FilePath);
if (String.Compare(this.Assembly.CodeBase, this.FilePath, true) != 0)
throw new ArgumentException("Cannot load filePath because Assembly is already loaded", "filePath");
ReadBaml();
}
private void ReadBaml()
{
// Get available names
string[] resources = this.Assembly.GetManifestResourceNames();
foreach (string res in resources)
{
// Solo le risorse
if (String.Compare(Path.GetExtension(res), ".resources", true) != 0) continue;
// Get stream
using (Stream stream = this.Assembly.GetManifestResourceStream(res))
{
try
{
ResourceReader reader = new ResourceReader(stream);
foreach (DictionaryEntry entry in reader)
{
if (String.Compare(Path.GetExtension(entry.Key.ToString()), ".baml", true) == 0 && entry.Value is Stream)
{
BamlFile bm = new BamlFile(GetAssemblyResourceUri(entry.Key.ToString()), (Stream)entry.Value);
this.BamlFiles.Add(bm);
}
}
}
catch (ArgumentException)
{}
}
}
}
private Uri GetAssemblyResourceUri(string resourceName)
{
AssemblyName asm = this.Assembly.GetName();
byte[] data = asm.GetPublicKeyToken();
StringBuilder token = new StringBuilder(data.Length * 2);
for (int x = 0; x < data.Length; x++)
{
token.Append(data[x].ToString("x", System.Globalization.CultureInfo.InvariantCulture));
}
return new Uri(String.Format(@"{0};V{1};{2};component\{3}", asm.Name, asm.Version, token, Path.ChangeExtension(resourceName, ".xaml")), UriKind.RelativeOrAbsolute);
}
public string FilePath
{
get { return _filePath; }
}
public Assembly Assembly
{
get { return _assembly; }
}
public BamlFileList BamlFiles
{
get
{
if (_bamlFile == null)
_bamlFile = new BamlFileList();
return _bamlFile;
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
[Serializable()]
public class BamlFileList : Collection<BamlFile>
{}
}

47
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlBinaryReader.cs

@ -0,0 +1,47 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.IO;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class BamlBinaryReader : BinaryReader
{
// Methods
public BamlBinaryReader(Stream stream)
: base(stream)
{
}
public virtual double ReadCompressedDouble()
{
switch (this.ReadByte())
{
case 1:
return 0;
case 2:
return 1;
case 3:
return -1;
case 4:
{
double num = this.ReadInt32();
return (num * 1E-06);
}
case 5:
return this.ReadDouble();
}
throw new NotSupportedException();
}
public int ReadCompressedInt32()
{
return base.Read7BitEncodedInt();
}
}
}

80
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs

@ -0,0 +1,80 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Resources;
using System.Text;
using System.Windows;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Rappresenta un singole file Baml all'interno di un assembly
/// </summary>
public class BamlFile : Component
{
private Uri _uri;
private readonly Stream _stream;
public BamlFile(Uri uri, Stream stream)
{
if (uri == null)
new ArgumentNullException("uri");
if (stream == null)
throw new ArgumentNullException("stream");
_uri = uri;
_stream = stream;
}
/// <summary>
/// Carica il Baml attraverso il motore di WPF con Application.LoadComponent
/// </summary>
/// <returns></returns>
public object LoadContent()
{
try
{
return Application.LoadComponent(this.Uri);
}
catch (Exception e)
{
throw new InvalidOperationException("Invalid baml file.", e);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
this.Stream.Dispose();
}
public override object InitializeLifetimeService()
{
return null;
}
/// <summary>
/// Restituisce lo stream originale contenente il Baml
/// </summary>
public Stream Stream
{
get { return _stream; }
}
/// <summary>
/// Restituisce l'indirizzo secondo lo schema pack://
/// </summary>
public Uri Uri
{
get { return _uri; }
}
}
}

72
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlRecordType.cs

@ -0,0 +1,72 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal enum BamlRecordType : byte
{
AssemblyInfo = 0x1c,
AttributeInfo = 0x1f,
ClrEvent = 0x13,
Comment = 0x17,
ConnectionId = 0x2d,
ConstructorParametersEnd = 0x2b,
ConstructorParametersStart = 0x2a,
ConstructorParameterType = 0x2c,
ContentProperty = 0x2e,
DefAttribute = 0x19,
DefAttributeKeyString = 0x26,
DefAttributeKeyType = 0x27,
DeferableContentStart = 0x25,
DefTag = 0x18,
DocumentEnd = 2,
DocumentStart = 1,
ElementEnd = 4,
ElementStart = 3,
EndAttributes = 0x1a,
KeyElementEnd = 0x29,
KeyElementStart = 40,
LastRecordType = 0x39,
LineNumberAndPosition = 0x35,
LinePosition = 0x36,
LiteralContent = 15,
NamedElementStart = 0x2f,
OptimizedStaticResource = 0x37,
PIMapping = 0x1b,
PresentationOptionsAttribute = 0x34,
ProcessingInstruction = 0x16,
Property = 5,
PropertyArrayEnd = 10,
PropertyArrayStart = 9,
PropertyComplexEnd = 8,
PropertyComplexStart = 7,
PropertyCustom = 6,
PropertyDictionaryEnd = 14,
PropertyDictionaryStart = 13,
PropertyListEnd = 12,
PropertyListStart = 11,
PropertyStringReference = 0x21,
PropertyTypeReference = 0x22,
PropertyWithConverter = 0x24,
PropertyWithExtension = 0x23,
PropertyWithStaticResourceId = 0x38,
RoutedEvent = 0x12,
StaticResourceEnd = 0x31,
StaticResourceId = 50,
StaticResourceStart = 0x30,
StringInfo = 0x20,
Text = 0x10,
TextWithConverter = 0x11,
TextWithId = 0x33,
TypeInfo = 0x1d,
TypeSerializerInfo = 30,
Unknown = 0,
XmlAttribute = 0x15,
XmlnsProperty = 20
}
}

58
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs

@ -0,0 +1,58 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class DotNetType : MarshalByRefObject, IType
{
private readonly string _assemblyQualifiedName;
private Type _type;
public DotNetType(string assemblyQualifiedName)
{
if (assemblyQualifiedName == null) throw new ArgumentNullException("assemblyQualifiedName");
_assemblyQualifiedName = assemblyQualifiedName;
_type = Type.GetType(assemblyQualifiedName, false, true);
}
#region IType Members
public string AssemblyQualifiedName
{
get { return _assemblyQualifiedName; }
}
public bool IsSubclassOf(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.IsSubclassOf(((DotNetType)type).Type);
}
public bool Equals(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.Equals(((DotNetType)type).Type);
}
#endregion
public Type Type
{
get { return _type; }
}
public override object InitializeLifetimeService()
{
return null;
}
}
}

14
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IDependencyPropertyDescriptor.cs

@ -0,0 +1,14 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public interface IDependencyPropertyDescriptor
{
bool IsAttached { get; }
}
}

19
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/IType.cs

@ -0,0 +1,19 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Interface rappresenting a DotNet type
/// </summary>
public interface IType
{
string AssemblyQualifiedName { get; }
bool IsSubclassOf(IType type);
bool Equals(IType type);
}
}

15
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ITypeResolver.cs

@ -0,0 +1,15 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public interface ITypeResolver
{
IType GetTypeByAssemblyQualifiedName(string name);
IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType);
}
}

1319
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs

File diff suppressed because it is too large Load Diff

58
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/PropertyDeclaration.cs

@ -0,0 +1,58 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class PropertyDeclaration
{
private TypeDeclaration declaringType;
private string name;
// Methods
public PropertyDeclaration(string name)
{
this.name = name;
this.declaringType = null;
}
public PropertyDeclaration(string name, TypeDeclaration declaringType)
{
this.name = name;
this.declaringType = declaringType;
}
public override string ToString()
{
if (((this.DeclaringType != null) && (this.DeclaringType.Name == "XmlNamespace")) && ((this.DeclaringType.Namespace == null) && (this.DeclaringType.Assembly == null)))
{
if ((this.Name == null) || (this.Name.Length == 0))
{
return "xmlns";
}
return ("xmlns:" + this.Name);
}
return this.Name;
}
// Properties
public TypeDeclaration DeclaringType
{
get
{
return this.declaringType;
}
}
public string Name
{
get
{
return this.name;
}
}
}
}

32
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/ResourceName.cs

@ -0,0 +1,32 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class ResourceName
{
private string name;
public ResourceName(string name)
{
this.name = name;
}
public override string ToString()
{
return this.Name;
}
public string Name
{
get
{
return this.name;
}
}
}
}

137
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs

@ -0,0 +1,137 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class TypeDeclaration
{
private readonly XmlBamlReader reader;
private readonly short _assemblyId;
private readonly bool _isKnown;
private readonly string _name;
private readonly string _namespaceName;
private readonly bool _isExtension;
private IType _type;
private bool _typeLoaded;
private readonly ITypeResolver resolver;
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId)
: this(null, resolver, name, namespaceName, assemblyId, true)
{
}
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension)
: this(null, resolver, name, namespaceName, assemblyId, true)
{
_isExtension = isExtension;
}
public TypeDeclaration(XmlBamlReader reader, ITypeResolver resolver, string name, string namespaceName, short assemblyId)
: this(reader, resolver, name, namespaceName, assemblyId, true)
{
}
public TypeDeclaration(XmlBamlReader reader, ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isKnown)
{
this.reader = reader;
this.resolver = resolver;
this._name = name;
this._namespaceName = namespaceName;
this._assemblyId = assemblyId;
this._isKnown = isKnown;
if (!_isExtension)
_isExtension = name.EndsWith("Extension");
}
public override string ToString()
{
return this._name;
}
public bool IsExtension
{
get { return _isExtension; }
}
public string Assembly
{
get
{
if (reader != null)
return this.reader.GetAssembly(this.AssemblyId);
else
return KnownInfo.KnownAssemblyTable[this.AssemblyId];
}
}
public short AssemblyId
{
get { return _assemblyId; }
}
public string Name
{
get
{
return this._name;
}
}
public bool IsKnown
{
get { return _isKnown; }
}
//public Type DotNetType
//{
// get
// {
// if (!_typeLoaded)
// {
// _type = Type.GetType(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly), false, true);
// _typeLoaded = true;
// }
// return _type;
// }
//}
public IType Type
{
get
{
if (!_typeLoaded)
{
if (this.Name.Length > 0)
_type = resolver.GetTypeByAssemblyQualifiedName(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly));
_typeLoaded = true;
}
return _type;
}
}
public string Namespace
{
get
{
return this._namespaceName;
}
}
public override bool Equals(object obj)
{
TypeDeclaration td = obj as TypeDeclaration;
if (td != null)
return (this.Name == td.Name && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId);
else
return false;
}
}
}

35
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs

@ -0,0 +1,35 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class WpfDependencyPropertyDescriptor : MarshalByRefObject, IDependencyPropertyDescriptor
{
private readonly DependencyPropertyDescriptor _propertyDescriptor;
public WpfDependencyPropertyDescriptor(DependencyPropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor == null) throw new ArgumentNullException("propertyDescriptor");
_propertyDescriptor = propertyDescriptor;
}
#region IDependencyPropertyDescriptor Members
public bool IsAttached
{
get { return _propertyDescriptor.IsAttached; }
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
}

193
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs

@ -0,0 +1,193 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlBamlElement : XmlBamlNode
{
private ArrayList _arguments = new ArrayList();
private XmlNamespaceCollection _namespaces = new XmlNamespaceCollection();
private TypeDeclaration _typeDeclaration;
private KeysResourcesCollection _keysResources = new KeysResourcesCollection();
private long _position;
public XmlBamlElement()
{
}
public XmlBamlElement(XmlBamlElement parent)
{
this.Namespaces.AddRange(parent.Namespaces);
}
public XmlNamespaceCollection Namespaces
{
get { return _namespaces; }
}
public TypeDeclaration TypeDeclaration
{
get
{
return this._typeDeclaration;
}
set
{
this._typeDeclaration = value;
}
}
public override XmlNodeType NodeType
{
get
{
return XmlNodeType.Element;
}
}
public long Position
{
get { return _position; }
set { _position = value; }
}
public override string ToString()
{
return String.Format("Element: {0}", TypeDeclaration.Name);
}
}
internal class XmlBamlEndElement : XmlBamlElement
{
public XmlBamlEndElement(XmlBamlElement start)
{
this.TypeDeclaration = start.TypeDeclaration;
this.Namespaces.AddRange(start.Namespaces);
}
public override XmlNodeType NodeType
{
get
{
return XmlNodeType.EndElement;
}
}
public override string ToString()
{
return String.Format("EndElement: {0}", TypeDeclaration.Name);
}
}
internal class KeyMapping
{
private string _key;
private TypeDeclaration _declaration;
private string _trueKey;
public KeyMapping(string key, TypeDeclaration declaration, string trueKey)
{
_key = key;
_declaration = declaration;
_trueKey = trueKey;
}
public string Key
{
get { return _key; }
}
public TypeDeclaration Declaration
{
get { return _declaration; }
}
public string TrueKey
{
get { return _trueKey; }
}
public override string ToString()
{
return String.Format("{0} - {1} - {2}", Key, Declaration, TrueKey);
}
}
internal class KeysResourcesCollection : List<KeysResource>
{
public KeysResource Last
{
get
{
if (this.Count == 0)
return null;
return this[this.Count - 1];
}
}
public KeysResource First
{
get
{
if (this.Count == 0)
return null;
return this[0];
}
}
}
internal class KeysResource
{
private KeysTable _keys = new KeysTable();
private ArrayList _staticResources = new ArrayList();
public KeysTable Keys
{
get { return _keys; }
}
public ArrayList StaticResources
{
get { return _staticResources; }
}
}
internal class KeysTable
{
private Hashtable table = new Hashtable();
public String this[long position]
{
get
{
return (string)this.table[position];
}
set
{
this.table[position] = value;
}
}
public int Count
{
get { return this.table.Count; }
}
public void Remove(long position)
{
this.table.Remove(position);
}
public bool HasKey(long position)
{
return this.table.ContainsKey(position);
}
}
}

21
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlNode.cs

@ -0,0 +1,21 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlBamlNode
{
public virtual XmlNodeType NodeType
{
get { return XmlNodeType.None;}
}
}
internal class XmlBamlNodeCollection : List<XmlBamlNode>
{}
}

86
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlProperty.cs

@ -0,0 +1,86 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlBamlProperty : XmlBamlNode
{
private PropertyDeclaration propertyDeclaration;
private PropertyType propertyType;
private object value;
public XmlBamlProperty(PropertyType propertyType)
{
this.propertyType = propertyType;
}
public XmlBamlProperty(PropertyType propertyType, PropertyDeclaration propertyDeclaration)
{
this.propertyDeclaration = propertyDeclaration;
this.propertyType = propertyType;
}
public override string ToString()
{
return this.PropertyDeclaration.Name;
}
public PropertyDeclaration PropertyDeclaration
{
get
{
return this.propertyDeclaration;
}
set
{
this.propertyDeclaration = value;
}
}
public PropertyType PropertyType
{
get
{
return this.propertyType;
}
}
public object Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public override XmlNodeType NodeType
{
get
{
return XmlNodeType.Attribute;
}
}
}
internal enum PropertyType
{
Key,
Value,
Content,
List,
Dictionary,
Complex
}
internal class XmlBamlPropertyCollection : List<XmlBamlNode>
{ }
}

48
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs

@ -0,0 +1,48 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlBamlPropertyElement : XmlBamlElement
{
private readonly PropertyType _propertyType;
private PropertyDeclaration propertyDeclaration;
public XmlBamlPropertyElement(PropertyType propertyType, PropertyDeclaration propertyDeclaration)
{
_propertyType = propertyType;
this.propertyDeclaration = propertyDeclaration;
}
public XmlBamlPropertyElement(XmlBamlElement parent, PropertyType propertyType, PropertyDeclaration propertyDeclaration)
: base(parent)
{
_propertyType = propertyType;
this.propertyDeclaration = propertyDeclaration;
this.TypeDeclaration = propertyDeclaration.DeclaringType;
}
public PropertyDeclaration PropertyDeclaration
{
get
{
return this.propertyDeclaration;
}
}
public PropertyType PropertyType
{
get { return _propertyType; }
}
public override string ToString()
{
return String.Format("PropertyElement: {0}.{1}", TypeDeclaration.Name, PropertyDeclaration.Name);
}
}
}

1943
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs

File diff suppressed because it is too large Load Diff

33
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlText.cs

@ -0,0 +1,33 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlBamlText : XmlBamlNode
{
private string _text;
public XmlBamlText(string text)
{
_text = text;
}
public string Text
{
get { return _text; }
}
public override System.Xml.XmlNodeType NodeType
{
get
{
return XmlNodeType.Text;
}
}
}
}

47
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlNamespace.cs

@ -0,0 +1,47 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System.Collections.Generic;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlNamespace
{
private string _prefix;
private string _namespace;
public XmlNamespace(string prefix, string ns)
{
_prefix = prefix;
_namespace = ns;
}
public string Prefix
{
get { return _prefix; }
}
public string Namespace
{
get { return _namespace; }
}
public override bool Equals(object obj)
{
if (obj is XmlNamespace)
{
XmlNamespace o = (XmlNamespace)obj;
return (o.Prefix.Equals(this.Prefix) && o.Namespace.Equals(this.Namespace));
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return _prefix.GetHashCode() + _namespace.GetHashCode() >> 20;
}
}
internal class XmlNamespaceCollection : List<XmlNamespace>
{}
}

63
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs

@ -0,0 +1,63 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Rappresenta la mappatura tra namespace XML e namespace CLR con relativo assembly
/// </summary>
public class XmlPIMapping
{
private string _xmlNamespace;
private short _assemblyId;
private string _clrNamespace;
private static XmlPIMapping _default = new XmlPIMapping(PresentationNamespace, 0, String.Empty);
public const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
public const string PresentationNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
public const string PresentationOptionsNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation/options";
public const string McNamespace = "http://schemas.openxmlformats.org/markup-compatibility/2006";
public XmlPIMapping(string xmlNamespace, short assemblyId, string clrNamespace)
{
_xmlNamespace = xmlNamespace;
_assemblyId = assemblyId;
_clrNamespace = clrNamespace;
}
/// <summary>
/// Restituisce o imposta il namespace XML
/// </summary>
public string XmlNamespace
{
get { return _xmlNamespace; }
set { _xmlNamespace = value;}
}
/// <summary>
/// Restituisce l'id dell'assembly
/// </summary>
public short AssemblyId
{
get { return _assemblyId; }
}
/// <summary>
/// Restituisce il namespace clr
/// </summary>
public string ClrNamespace
{
get { return _clrNamespace; }
}
/// <summary>
/// Restituisce il mapping di default di WPF
/// </summary>
public static XmlPIMapping Presentation
{
get { return _default; }
}
}
}

12
ILSpy.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.1.0.7384-alpha # SharpDevelop 4.1.0.7466-alpha
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
doc\Command Line.txt = doc\Command Line.txt doc\Command Line.txt = doc\Command Line.txt
@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\Te
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "Mono.Cecil\symbols\pdb\Mono.Cecil.Pdb.csproj", "{63E6915C-7EA4-4D76-AB28-0D7191EEA626}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "Mono.Cecil\symbols\pdb\Mono.Cecil.Pdb.csproj", "{63E6915C-7EA4-4D76-AB28-0D7191EEA626}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.BamlDecompiler", "ILSpy.BamlDecompiler\ILSpy.BamlDecompiler.csproj", "{A6BAD2BA-76BA-461C-8B6D-418607591247}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -105,6 +107,14 @@ Global
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.Build.0 = net_4_0_Debug|Any CPU {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU {63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|Any CPU.Build.0 = Debug|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|Any CPU.ActiveCfg = Debug|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|x86.Build.0 = Debug|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Debug|x86.ActiveCfg = Debug|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.Build.0 = Release|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|Any CPU.ActiveCfg = Release|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.Build.0 = Release|x86
{A6BAD2BA-76BA-461C-8B6D-418607591247}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

4
ILSpy/AboutPage.cs

@ -93,7 +93,7 @@ namespace ICSharpCode.ILSpy
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("SharpDevelop", "http://www.icsharpcode.net/opensource/sd/")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("SharpDevelop", "http://www.icsharpcode.net/opensource/sd/"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt"));
output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt")); output.AddVisualLineElementGenerator(new MyLinkElementGenerator("LGPL", "resource:LGPL.txt"));
textView.Show(output); textView.ShowText(output);
} }
sealed class MyLinkElementGenerator : LinkElementGenerator sealed class MyLinkElementGenerator : LinkElementGenerator
@ -130,7 +130,7 @@ namespace ICSharpCode.ILSpy
} catch (Exception ex) { } catch (Exception ex) {
AvalonEditTextOutput exceptionOutput = new AvalonEditTextOutput(); AvalonEditTextOutput exceptionOutput = new AvalonEditTextOutput();
exceptionOutput.WriteLine(ex.ToString()); exceptionOutput.WriteLine(ex.ToString());
textView.Show(exceptionOutput); textView.ShowText(exceptionOutput);
} }
}, TaskScheduler.FromCurrentSynchronizationContext()); }, TaskScheduler.FromCurrentSynchronizationContext());
}; };

2
ILSpy/App.xaml.cs

@ -165,7 +165,7 @@ namespace ICSharpCode.ILSpy
} }
} }
} }
ILSpy.MainWindow.Instance.TextView.Show(output); ILSpy.MainWindow.Instance.TextView.ShowText(output);
} else { } else {
Process.Start(e.Uri.ToString()); Process.Start(e.Uri.ToString());
} }

445
ILSpy/BamlDecompiler.cs

@ -1,445 +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.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Baml2006;
using System.Xaml;
using System.Xaml.Schema;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.ILSpy.Baml
{
/// <remarks>Caution: use in separate AppDomain only!</remarks>
sealed class BamlDecompiler : MarshalByRefObject
{
public BamlDecompiler()
{
}
abstract class XamlNode
{
public readonly List<XamlNode> Children = new List<XamlNode>();
public abstract void WriteTo(XamlWriter writer);
}
[Conditional("DEBUG")]
static void Log(string format, params object[] args)
{
Debug.WriteLine(format, args);
}
sealed class XamlObjectNode : XamlNode
{
public readonly XamlType Type;
public XamlObjectNode(XamlType type)
{
this.Type = type;
}
public override void WriteTo(XamlWriter writer)
{
Log("StartObject {0}", this.Type);
writer.WriteStartObject(this.Type);
Debug.Indent();
foreach (XamlNode node in this.Children)
node.WriteTo(writer);
Debug.Unindent();
Log("EndObject");
writer.WriteEndObject();
}
}
sealed class XamlGetObjectNode : XamlNode
{
public override void WriteTo(XamlWriter writer)
{
Log("GetObject");
writer.WriteGetObject();
Debug.Indent();
foreach (XamlNode node in this.Children)
node.WriteTo(writer);
Debug.Unindent();
Log("EndObject");
writer.WriteEndObject();
}
}
sealed class XamlMemberNode : XamlNode
{
public XamlMember Member;
public XamlMemberNode(XamlMember member)
{
this.Member = member;
}
public override void WriteTo(XamlWriter writer)
{
Log("StartMember {0}", this.Member);
writer.WriteStartMember(this.Member);
Debug.Indent();
foreach (XamlNode node in this.Children)
node.WriteTo(writer);
Debug.Unindent();
Log("EndMember");
writer.WriteEndMember();
}
}
sealed class XamlValueNode : XamlNode
{
public readonly object Value;
public XamlValueNode(object value)
{
this.Value = value;
}
public override void WriteTo(XamlWriter writer)
{
Log("Value {0}", this.Value);
Debug.Assert(this.Children.Count == 0);
// requires XamlReaderSettings.ValuesMustBeString = true to work properly
writer.WriteValue(this.Value);
}
}
sealed class XamlNamespaceDeclarationNode : XamlNode
{
public readonly NamespaceDeclaration Namespace;
public XamlNamespaceDeclarationNode(NamespaceDeclaration @namespace)
{
this.Namespace = @namespace;
}
public override void WriteTo(XamlWriter writer)
{
Log("NamespaceDeclaration {0}", this.Namespace);
Debug.Assert(this.Children.Count == 0);
writer.WriteNamespace(this.Namespace);
}
}
static List<XamlNode> Parse(XamlReader reader)
{
List<XamlNode> currentList = new List<XamlNode>();
Stack<List<XamlNode>> stack = new Stack<List<XamlNode>>();
while (reader.Read()) {
switch (reader.NodeType) {
case XamlNodeType.None:
break;
case XamlNodeType.StartObject:
XamlObjectNode obj = new XamlObjectNode(reader.Type);
currentList.Add(obj);
stack.Push(currentList);
currentList = obj.Children;
break;
case XamlNodeType.GetObject:
XamlGetObjectNode getObject = new XamlGetObjectNode();
currentList.Add(getObject);
stack.Push(currentList);
currentList = getObject.Children;
break;
case XamlNodeType.StartMember:
XamlMemberNode member = new XamlMemberNode(reader.Member);
currentList.Add(member);
stack.Push(currentList);
currentList = member.Children;
break;
case XamlNodeType.Value:
currentList.Add(new XamlValueNode(reader.Value));
break;
case XamlNodeType.NamespaceDeclaration:
currentList.Add(new XamlNamespaceDeclarationNode(reader.Namespace));
break;
case XamlNodeType.EndObject:
case XamlNodeType.EndMember:
currentList = stack.Pop();
break;
default:
throw new InvalidOperationException("Invalid value for XamlNodeType");
}
}
if (stack.Count != 0)
throw new InvalidOperationException("Imbalanced stack");
return currentList;
}
void AvoidContentProperties(XamlNode node)
{
foreach (XamlNode child in node.Children)
AvoidContentProperties(child);
XamlObjectNode obj = node as XamlObjectNode;
if (obj != null) {
// Visit all except for the last child:
for (int i = 0; i < obj.Children.Count - 1; i++) {
// Avoids using content property syntax for simple string values, if the content property is not the last member.
// Without this, we cannot decompile &lt;GridViewColumn Header="Culture" DisplayMemberBinding="{Binding Culture}" /&gt;,
// because the Header property is the content property, but there is no way to represent the Binding as an element.
XamlMemberNode memberNode = obj.Children[i] as XamlMemberNode;
if (memberNode != null && memberNode.Member == obj.Type.ContentProperty) {
if (memberNode.Children.Count == 1 && memberNode.Children[0] is XamlValueNode) {
// By creating a clone of the XamlMember, we prevent WPF from knowing that it's the content property.
XamlMember member = memberNode.Member;
memberNode.Member = new XamlMember(member.Name, member.DeclaringType, member.IsAttachable);
}
}
}
// We also need to avoid using content properties that have a markup extension as value, as the XamlXmlWriter would always expand those:
for (int i = 0; i < obj.Children.Count; i++) {
XamlMemberNode memberNode = obj.Children[i] as XamlMemberNode;
if (memberNode != null && memberNode.Member == obj.Type.ContentProperty && memberNode.Children.Count == 1) {
XamlObjectNode me = memberNode.Children[0] as XamlObjectNode;
if (me != null && me.Type.IsMarkupExtension) {
// By creating a clone of the XamlMember, we prevent WPF from knowing that it's the content property.
XamlMember member = memberNode.Member;
memberNode.Member = new XamlMember(member.Name, member.DeclaringType, member.IsAttachable);
}
}
}
}
}
/// <summary>
/// It seems like BamlReader will always output 'x:Key' as last property. However, it must be specified as attribute in valid .xaml, so we move it to the front
/// of the attribute list.
/// </summary>
void MoveXKeyToFront(XamlNode node)
{
foreach (XamlNode child in node.Children)
MoveXKeyToFront(child);
XamlObjectNode obj = node as XamlObjectNode;
if (obj != null && obj.Children.Count > 0) {
XamlMemberNode memberNode = obj.Children[obj.Children.Count - 1] as XamlMemberNode;
if (memberNode != null && memberNode.Member == XamlLanguage.Key) {
// move memberNode in front of the first member node:
for (int i = 0; i < obj.Children.Count; i++) {
if (obj.Children[i] is XamlMemberNode) {
obj.Children.Insert(i, memberNode);
obj.Children.RemoveAt(obj.Children.Count - 1);
break;
}
}
}
}
}
AssemblyResolver asmResolver;
Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = asmResolver.FindAssembly(args.Name);
if (path == null)
return null;
return Assembly.LoadFile(path);
}
public string DecompileBaml(MemoryStream bamlCode, string containingAssemblyFile, ConnectMethodDecompiler connectMethodDecompiler, AssemblyResolver asmResolver)
{
this.asmResolver = asmResolver;
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
bamlCode.Position = 0;
TextWriter w = new StringWriter();
Assembly assembly = Assembly.LoadFile(containingAssemblyFile);
Baml2006Reader reader = new Baml2006Reader(bamlCode, new XamlReaderSettings() { ValuesMustBeString = true, LocalAssembly = assembly });
var xamlDocument = Parse(reader);
string bamlTypeName = xamlDocument.OfType<XamlObjectNode>().First().Type.UnderlyingType.FullName;
var eventMappings = connectMethodDecompiler.DecompileEventMappings(bamlTypeName);
foreach (var xamlNode in xamlDocument) {
RemoveConnectionIds(xamlNode, eventMappings, reader.SchemaContext);
AvoidContentProperties(xamlNode);
MoveXKeyToFront(xamlNode);
}
XDocument doc = new XDocument();
XamlXmlWriter writer = new XamlXmlWriter(doc.CreateWriter(), reader.SchemaContext, new XamlXmlWriterSettings { AssumeValidInput = true });
foreach (var xamlNode in xamlDocument)
xamlNode.WriteTo(writer);
writer.Close();
// Fix namespace references
string suffixToRemove = ";assembly=" + assembly.GetName().Name;
foreach (XAttribute attrib in doc.Root.Attributes()) {
if (attrib.Name.Namespace == XNamespace.Xmlns) {
if (attrib.Value.EndsWith(suffixToRemove, StringComparison.Ordinal)) {
string newNamespace = attrib.Value.Substring(0, attrib.Value.Length - suffixToRemove.Length);
ChangeXmlNamespace(doc, attrib.Value, newNamespace);
attrib.Value = newNamespace;
}
}
}
return doc.ToString();
}
void RemoveConnectionIds(XamlNode node, Dictionary<int, EventRegistration[]> eventMappings, XamlSchemaContext context)
{
foreach (XamlNode child in node.Children)
RemoveConnectionIds(child, eventMappings, context);
XamlObjectNode obj = node as XamlObjectNode;
if (obj != null && obj.Children.Count > 0) {
var removableNodes = new List<XamlMemberNode>();
var addableNodes = new List<XamlMemberNode>();
foreach (XamlMemberNode memberNode in obj.Children.OfType<XamlMemberNode>()) {
if (memberNode.Member == XamlLanguage.ConnectionId && memberNode.Children.Single() is XamlValueNode) {
var value = memberNode.Children.Single() as XamlValueNode;
int id;
if (value.Value is string && int.TryParse(value.Value as string, out id) && eventMappings.ContainsKey(id)) {
var map = eventMappings[id];
foreach (var entry in map) {
if (entry.IsAttached) {
var type = context.GetXamlType(Type.GetType(entry.AttachSourceType));
var member = new XamlMemberNode(new XamlMember(entry.EventName, type, true));
member.Children.Add(new XamlValueNode(entry.MethodName));
addableNodes.Add(member);
} else {
var member = new XamlMemberNode(obj.Type.GetMember(entry.EventName));
member.Children.Add(new XamlValueNode(entry.MethodName));
addableNodes.Add(member);
}
}
removableNodes.Add(memberNode);
}
}
}
foreach (var rnode in removableNodes)
node.Children.Remove(rnode);
node.Children.InsertRange(node.Children.Count > 1 ? node.Children.Count - 1 : 0, addableNodes);
}
}
/// <summary>
/// Changes all references from oldNamespace to newNamespace in the document.
/// </summary>
void ChangeXmlNamespace(XDocument doc, XNamespace oldNamespace, XNamespace newNamespace)
{
foreach (XElement e in doc.Descendants()) {
if (e.Name.Namespace == oldNamespace)
e.Name = newNamespace + e.Name.LocalName;
}
}
}
[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, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm)));
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.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName);
}
}
}

231
ILSpy/CSharpLanguage.cs

@ -47,11 +47,11 @@ namespace ICSharpCode.ILSpy
string name = "C#"; string name = "C#";
bool showAllMembers = false; bool showAllMembers = false;
Predicate<IAstTransform> transformAbortCondition = null; Predicate<IAstTransform> transformAbortCondition = null;
public CSharpLanguage() public CSharpLanguage()
{ {
} }
#if DEBUG #if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages() internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{ {
@ -72,28 +72,73 @@ namespace ICSharpCode.ILSpy
}; };
} }
#endif #endif
public override string Name { public override string Name
{
get { return name; } get { return name; }
} }
public override string FileExtension { public override string FileExtension
{
get { return ".cs"; } get { return ".cs"; }
} }
public override string ProjectFileExtension { public override string ProjectFileExtension
{
get { return ".csproj"; } get { return ".csproj"; }
} }
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
codeDomBuilder.AddMethod(method); if (method.IsConstructor && !method.IsStatic && !method.DeclaringType.IsValueType) {
RunTransformsAndGenerateCode(codeDomBuilder, output, options); // also fields and other ctors so that the field initializers can be shown as such
AddFieldsAndCtors(codeDomBuilder, method.DeclaringType, method.IsStatic);
RunTransformsAndGenerateCode(codeDomBuilder, output, options, new SelectCtorTransform(method));
} else {
codeDomBuilder.AddMethod(method);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
NotifyDecompilationFinished(codeDomBuilder); NotifyDecompilationFinished(codeDomBuilder);
} }
class SelectCtorTransform : IAstTransform
{
readonly MethodDefinition ctorDef;
public SelectCtorTransform(MethodDefinition ctorDef)
{
this.ctorDef = ctorDef;
}
public void Run(AstNode compilationUnit)
{
ConstructorDeclaration ctorDecl = null;
foreach (var node in compilationUnit.Children) {
ConstructorDeclaration ctor = node as ConstructorDeclaration;
if (ctor != null) {
if (ctor.Annotation<MethodDefinition>() == ctorDef) {
ctorDecl = ctor;
} else {
// remove other ctors
ctor.Remove();
}
}
// Remove any fields without initializers
FieldDeclaration fd = node as FieldDeclaration;
if (fd != null && fd.Variables.All(v => v.Initializer.IsNull))
fd.Remove();
}
if (ctorDecl.Initializer.ConstructorInitializerType == ConstructorInitializerType.This) {
// remove all fields
foreach (var node in compilationUnit.Children)
if (node is FieldDeclaration)
node.Remove();
}
}
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
@ -102,16 +147,56 @@ namespace ICSharpCode.ILSpy
RunTransformsAndGenerateCode(codeDomBuilder, output, options); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
NotifyDecompilationFinished(codeDomBuilder); NotifyDecompilationFinished(codeDomBuilder);
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
codeDomBuilder.AddField(field); if (field.IsLiteral) {
RunTransformsAndGenerateCode(codeDomBuilder, output, options); codeDomBuilder.AddField(field);
} else {
// also decompile ctors so that the field initializer can be shown
AddFieldsAndCtors(codeDomBuilder, field.DeclaringType, field.IsStatic);
}
RunTransformsAndGenerateCode(codeDomBuilder, output, options, new SelectFieldTransform(field));
NotifyDecompilationFinished(codeDomBuilder); NotifyDecompilationFinished(codeDomBuilder);
} }
/// <summary>
/// Removes all top-level members except for the specified fields.
/// </summary>
sealed class SelectFieldTransform : IAstTransform
{
readonly FieldDefinition field;
public SelectFieldTransform(FieldDefinition field)
{
this.field = field;
}
public void Run(AstNode compilationUnit)
{
foreach (var child in compilationUnit.Children) {
if (child is AttributedNode) {
if (child.Annotation<FieldDefinition>() != field)
child.Remove();
}
}
}
}
void AddFieldsAndCtors(AstBuilder codeDomBuilder, TypeDefinition declaringType, bool isStatic)
{
foreach (var field in declaringType.Fields) {
if (field.IsStatic == isStatic)
codeDomBuilder.AddField(field);
}
foreach (var ctor in declaringType.Methods) {
if (ctor.IsConstructor && ctor.IsStatic == isStatic)
codeDomBuilder.AddMethod(ctor);
}
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
@ -120,7 +205,7 @@ namespace ICSharpCode.ILSpy
RunTransformsAndGenerateCode(codeDomBuilder, output, options); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
NotifyDecompilationFinished(codeDomBuilder); NotifyDecompilationFinished(codeDomBuilder);
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
@ -129,14 +214,18 @@ namespace ICSharpCode.ILSpy
NotifyDecompilationFinished(codeDomBuilder); NotifyDecompilationFinished(codeDomBuilder);
} }
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options) void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, IAstTransform additionalTransform = null)
{ {
astBuilder.RunTransformations(transformAbortCondition); astBuilder.RunTransformations(transformAbortCondition);
if (options.DecompilerSettings.ShowXmlDocumentation) if (additionalTransform != null) {
additionalTransform.Run(astBuilder.CompilationUnit);
}
if (options.DecompilerSettings.ShowXmlDocumentation) {
AddXmlDocTransform.Run(astBuilder.CompilationUnit); AddXmlDocTransform.Run(astBuilder.CompilationUnit);
}
astBuilder.GenerateCode(output); astBuilder.GenerateCode(output);
} }
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{ {
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) { if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
@ -156,7 +245,7 @@ namespace ICSharpCode.ILSpy
} }
OnDecompilationFinished(null); OnDecompilationFinished(null);
} }
#region WriteProjectFile #region WriteProjectFile
void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, ModuleDefinition module) void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, ModuleDefinition module)
{ {
@ -184,20 +273,20 @@ namespace ICSharpCode.ILSpy
w.WriteStartElement("Project", ns); w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0"); w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build"); w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup"); w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString().ToUpperInvariant()); w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString().ToUpperInvariant());
w.WriteStartElement("Configuration"); w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' "); w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug"); w.WriteValue("Debug");
w.WriteEndElement(); // </Configuration> w.WriteEndElement(); // </Configuration>
w.WriteStartElement("Platform"); w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' "); w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName); w.WriteValue(platformName);
w.WriteEndElement(); // </Platform> w.WriteEndElement(); // </Platform>
switch (module.Kind) { switch (module.Kind) {
case ModuleKind.Windows: case ModuleKind.Windows:
w.WriteElementString("OutputType", "WinExe"); w.WriteElementString("OutputType", "WinExe");
@ -209,7 +298,7 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("OutputType", "Library"); w.WriteElementString("OutputType", "Library");
break; break;
} }
w.WriteElementString("AssemblyName", module.Assembly.Name.Name); w.WriteElementString("AssemblyName", module.Assembly.Name.Name);
switch (module.Runtime) { switch (module.Runtime) {
case TargetRuntime.Net_1_0: case TargetRuntime.Net_1_0:
@ -228,14 +317,14 @@ namespace ICSharpCode.ILSpy
break; break;
} }
w.WriteElementString("WarningLevel", "4"); w.WriteElementString("WarningLevel", "4");
w.WriteEndElement(); // </PropertyGroup> w.WriteEndElement(); // </PropertyGroup>
w.WriteStartElement("PropertyGroup"); // platform-specific w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' "); w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName); w.WriteElementString("PlatformTarget", platformName);
w.WriteEndElement(); // </PropertyGroup> (platform-specific) w.WriteEndElement(); // </PropertyGroup> (platform-specific)
w.WriteStartElement("PropertyGroup"); // Debug w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' "); w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\"); w.WriteElementString("OutputPath", "bin\\Debug\\");
@ -243,7 +332,7 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("DebugType", "full"); w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false"); w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // </PropertyGroup> (Debug) w.WriteEndElement(); // </PropertyGroup> (Debug)
w.WriteStartElement("PropertyGroup"); // Release w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' "); w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\"); w.WriteElementString("OutputPath", "bin\\Release\\");
@ -251,8 +340,8 @@ namespace ICSharpCode.ILSpy
w.WriteElementString("DebugType", "pdbonly"); w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true"); w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // </PropertyGroup> (Release) w.WriteEndElement(); // </PropertyGroup> (Release)
w.WriteStartElement("ItemGroup"); // References w.WriteStartElement("ItemGroup"); // References
foreach (AssemblyNameReference r in module.AssemblyReferences) { foreach (AssemblyNameReference r in module.AssemblyReferences) {
if (r.Name != "mscorlib") { if (r.Name != "mscorlib") {
@ -263,7 +352,7 @@ namespace ICSharpCode.ILSpy
} }
} }
w.WriteEndElement(); // </ItemGroup> (References) w.WriteEndElement(); // </ItemGroup> (References)
foreach (IGrouping<string, string> gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) { foreach (IGrouping<string, string> gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) {
w.WriteStartElement("ItemGroup"); w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) { foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
@ -273,16 +362,16 @@ namespace ICSharpCode.ILSpy
} }
w.WriteEndElement(); w.WriteEndElement();
} }
w.WriteStartElement("Import"); w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"); w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement(); w.WriteEndElement();
w.WriteEndDocument(); w.WriteEndDocument();
} }
} }
#endregion #endregion
#region WriteCodeFilesInProject #region WriteCodeFilesInProject
bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions options) bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions options)
{ {
@ -292,11 +381,11 @@ namespace ICSharpCode.ILSpy
return false; return false;
return true; return true;
} }
IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet<string> directories) IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet<string> directories)
{ {
var files = assembly.MainModule.Types.Where(t => IncludeTypeWhenDecompilingProject(t, options)).GroupBy( var files = assembly.MainModule.Types.Where(t => IncludeTypeWhenDecompilingProject(t, options)).GroupBy(
delegate (TypeDefinition type) { delegate(TypeDefinition type) {
string file = TextView.DecompilerTextView.CleanUpName(type.Name) + this.FileExtension; string file = TextView.DecompilerTextView.CleanUpName(type.Name) + this.FileExtension;
if (string.IsNullOrEmpty(type.Namespace)) { if (string.IsNullOrEmpty(type.Namespace)) {
return file; return file;
@ -311,7 +400,7 @@ namespace ICSharpCode.ILSpy
Parallel.ForEach( Parallel.ForEach(
files, files,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
delegate (IGrouping<string, TypeDefinition> file) { delegate(IGrouping<string, TypeDefinition> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) { using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
foreach (TypeDefinition type in file) { foreach (TypeDefinition type in file) {
@ -325,7 +414,7 @@ namespace ICSharpCode.ILSpy
return files.Select(f => Tuple.Create("Compile", f.Key)); return files.Select(f => Tuple.Create("Compile", f.Key));
} }
#endregion #endregion
#region WriteResourceFilesInProject #region WriteResourceFilesInProject
IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet<string> directories) IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet<string> directories)
{ {
@ -339,7 +428,8 @@ namespace ICSharpCode.ILSpy
IEnumerable<DictionaryEntry> rs = null; IEnumerable<DictionaryEntry> rs = null;
try { try {
rs = new ResourceSet(s).Cast<DictionaryEntry>(); rs = new ResourceSet(s).Cast<DictionaryEntry>();
} catch (ArgumentException) { }
catch (ArgumentException) {
} }
if (rs != null && rs.All(e => e.Value is Stream)) { if (rs != null && rs.All(e => e.Value is Stream)) {
foreach (var pair in rs) { foreach (var pair in rs) {
@ -353,16 +443,18 @@ namespace ICSharpCode.ILSpy
if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) { if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) {
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
entryStream.CopyTo(ms); entryStream.CopyTo(ms);
var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assembly.FileName); // TODO implement extension point
string xaml = null; // var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assembly.FileName);
try { // string xaml = null;
xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly)); // try {
} catch (XamlXmlWriterException) {} // ignore XAML writer exceptions // xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly));
if (xaml != null) { // }
File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml); // catch (XamlXmlWriterException) { } // ignore XAML writer exceptions
yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml")); // if (xaml != null) {
continue; // File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml);
} // yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml"));
// continue;
// }
} }
using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) {
entryStream.CopyTo(fs); entryStream.CopyTo(fs);
@ -378,12 +470,13 @@ namespace ICSharpCode.ILSpy
} }
yield return Tuple.Create("EmbeddedResource", fileName); yield return Tuple.Create("EmbeddedResource", fileName);
} }
} finally { }
finally {
if (bamlDecompilerAppDomain != null) if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain); AppDomain.Unload(bamlDecompilerAppDomain);
} }
} }
string GetFileNameForResource(string fullName, HashSet<string> directories) string GetFileNameForResource(string fullName, HashSet<string> directories)
{ {
string[] splitName = fullName.Split('.'); string[] splitName = fullName.Split('.');
@ -399,7 +492,7 @@ namespace ICSharpCode.ILSpy
return fileName; return fileName;
} }
#endregion #endregion
AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false) AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false)
{ {
if (currentModule == null) if (currentModule == null)
@ -422,8 +515,14 @@ namespace ICSharpCode.ILSpy
ConvertTypeOptions options = ConvertTypeOptions.IncludeTypeParameterDefinitions; ConvertTypeOptions options = ConvertTypeOptions.IncludeTypeParameterDefinitions;
if (includeNamespace) if (includeNamespace)
options |= ConvertTypeOptions.IncludeNamespace; options |= ConvertTypeOptions.IncludeNamespace;
return TypeToString(options, type, typeAttributes);
}
string TypeToString(ConvertTypeOptions options, TypeReference type, ICustomAttributeProvider typeAttributes = null)
{
AstType astType = AstBuilder.ConvertType(type, typeAttributes, options); AstType astType = AstBuilder.ConvertType(type, typeAttributes, options);
StringWriter w = new StringWriter(); StringWriter w = new StringWriter();
if (type.IsByReference) { if (type.IsByReference) {
ParameterDefinition pd = typeAttributes as ParameterDefinition; ParameterDefinition pd = typeAttributes as ParameterDefinition;
@ -431,11 +530,11 @@ namespace ICSharpCode.ILSpy
w.Write("out "); w.Write("out ");
else else
w.Write("ref "); w.Write("ref ");
if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0) if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0)
((ComposedType)astType).PointerRank--; ((ComposedType)astType).PointerRank--;
} }
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null); astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null);
return w.ToString(); return w.ToString();
} }
@ -471,11 +570,27 @@ namespace ICSharpCode.ILSpy
return property.Name; return property.Name;
} }
public override string FormatTypeName(TypeDefinition type)
{
if (type == null)
throw new ArgumentNullException("type");
return TypeToString(ConvertTypeOptions.DoNotUsePrimitiveTypeNames | ConvertTypeOptions.IncludeTypeParameterDefinitions, type);
}
public override bool ShowMember(MemberReference member) public override bool ShowMember(MemberReference member)
{ {
return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings); return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);
} }
public override MemberReference GetOriginalCodeLocation(MemberReference member)
{
if (showAllMembers || !DecompilerSettingsPanel.CurrentDecompilerSettings.AnonymousMethods)
return member;
else
return ICSharpCode.ILSpy.TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member);
}
public override string GetTooltip(MemberReference member) public override string GetTooltip(MemberReference member)
{ {
MethodDefinition md = member as MethodDefinition; MethodDefinition md = member as MethodDefinition;
@ -496,12 +611,12 @@ namespace ICSharpCode.ILSpy
b.RunTransformations(); b.RunTransformations();
foreach (var attribute in b.CompilationUnit.Descendants.OfType<AttributeSection>()) foreach (var attribute in b.CompilationUnit.Descendants.OfType<AttributeSection>())
attribute.Remove(); attribute.Remove();
StringWriter w = new StringWriter(); StringWriter w = new StringWriter();
b.GenerateCode(new PlainTextOutput(w)); b.GenerateCode(new PlainTextOutput(w));
return Regex.Replace(w.ToString(), @"\s+", " ").TrimEnd(); return Regex.Replace(w.ToString(), @"\s+", " ").TrimEnd();
} }
return base.GetTooltip(member); return base.GetTooltip(member);
} }
} }

2
ILSpy/Commands.cs

@ -122,7 +122,7 @@ namespace ICSharpCode.ILSpy
return output; return output;
} }
), ),
task => MainWindow.Instance.TextView.Show(task.Result)); task => MainWindow.Instance.TextView.ShowText(task.Result));
} }
} }
#endif #endif

19
ILSpy/ConnectMethodDecompiler.cs

@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) //
// 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;
using System.Collections.Generic; using System.Collections.Generic;

93
ILSpy/DisplaySettings.cs

@ -0,0 +1,93 @@
// 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.ComponentModel;
using System.Windows.Media;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Description of DisplaySettings.
/// </summary>
public class DisplaySettings : INotifyPropertyChanged
{
public DisplaySettings()
{
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) {
PropertyChanged(this, e);
}
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
#endregion
FontFamily selectedFont;
public FontFamily SelectedFont {
get { return selectedFont; }
set {
if (selectedFont != value) {
selectedFont = value;
OnPropertyChanged("SelectedFont");
}
}
}
double selectedFontSize;
public double SelectedFontSize {
get { return selectedFontSize; }
set {
if (selectedFontSize != value) {
selectedFontSize = value;
OnPropertyChanged("SelectedFontSize");
}
}
}
bool showLineNumbers;
public bool ShowLineNumbers {
get { return showLineNumbers; }
set {
if (showLineNumbers != value) {
showLineNumbers = value;
OnPropertyChanged("ShowLineNumbers");
}
}
}
public void CopyValues(DisplaySettings s)
{
this.SelectedFont = s.selectedFont;
this.SelectedFontSize = s.selectedFontSize;
this.ShowLineNumbers = s.showLineNumbers;
}
}
}

64
ILSpy/DisplaySettingsPanel.xaml

@ -0,0 +1,64 @@
<UserControl x:Class="ICSharpCode.ILSpy.DisplaySettingsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ICSharpCode.ILSpy">
<UserControl.Resources>
<local:FontSizeConverter x:Key="fontSizeConv" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<GroupBox Header="Font">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Label Margin="3,0">Font:</Label>
<ComboBox x:Name="fontSelector" VerticalContentAlignment="Center" SelectedItem="{Binding SelectedFont}" Grid.Column="1">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Source}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Column="2" Margin="3,0">Size:</Label>
<ComboBox Grid.Column="3" Text="{Binding SelectedFontSize, Converter={StaticResource fontSizeConv}}" IsEditable="True" Margin="3,0">
<ComboBoxItem>6</ComboBoxItem>
<ComboBoxItem>7</ComboBoxItem>
<ComboBoxItem>8</ComboBoxItem>
<ComboBoxItem>9</ComboBoxItem>
<ComboBoxItem>10</ComboBoxItem>
<ComboBoxItem>11</ComboBoxItem>
<ComboBoxItem>12</ComboBoxItem>
<ComboBoxItem>13</ComboBoxItem>
<ComboBoxItem>14</ComboBoxItem>
<ComboBoxItem>15</ComboBoxItem>
<ComboBoxItem>16</ComboBoxItem>
<ComboBoxItem>17</ComboBoxItem>
<ComboBoxItem>18</ComboBoxItem>
<ComboBoxItem>19</ComboBoxItem>
<ComboBoxItem>20</ComboBoxItem>
<ComboBoxItem>21</ComboBoxItem>
<ComboBoxItem>22</ComboBoxItem>
<ComboBoxItem>23</ComboBoxItem>
<ComboBoxItem>24</ComboBoxItem>
</ComboBox>
<Border Grid.Row="1" Grid.ColumnSpan="4" BorderBrush="Black" BorderThickness="1" Background="White" Margin="3,5">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="AaBbCcXxYyZz" FontFamily="{Binding SelectedFont}" FontSize="{Binding SelectedFontSize}" />
</Border>
</Grid>
</GroupBox>
<GroupBox Header="Other options" Grid.Row="1">
<CheckBox Margin="3,3" IsChecked="{Binding ShowLineNumbers}">Show line numbers</CheckBox>
</GroupBox>
</Grid>
</UserControl>

154
ILSpy/DisplaySettingsPanel.xaml.cs

@ -0,0 +1,154 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Xml.Linq;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interaction logic for DisplaySettingsPanel.xaml
/// </summary>
[ExportOptionPage("Display")]
public partial class DisplaySettingsPanel : UserControl, IOptionPage
{
public DisplaySettingsPanel()
{
InitializeComponent();
Task<FontFamily[]> task = new Task<FontFamily[]>(FontLoader);
task.Start();
task.ContinueWith(
delegate(Task continuation) {
App.Current.Dispatcher.Invoke(
DispatcherPriority.Normal,
(Action)(
() => {
fontSelector.ItemsSource = task.Result;
if (continuation.Exception != null) {
foreach (var ex in continuation.Exception.InnerExceptions) {
MessageBox.Show(ex.ToString());
}
}
})
);
}
);
}
public void Load(ILSpySettings settings)
{
this.DataContext = LoadDisplaySettings(settings);
}
static DisplaySettings currentDisplaySettings;
public static DisplaySettings CurrentDisplaySettings {
get {
return currentDisplaySettings ?? (currentDisplaySettings = LoadDisplaySettings(ILSpySettings.Load()));
}
}
static bool IsSymbolFont(FontFamily fontFamily)
{
foreach (var tf in fontFamily.GetTypefaces()) {
GlyphTypeface glyph;
try {
if (tf.TryGetGlyphTypeface(out glyph))
return glyph.Symbol;
} catch (Exception) {
return true;
}
}
return false;
}
static FontFamily[] FontLoader()
{
return Fonts.SystemFontFamilies
.Where(ff => !IsSymbolFont(ff))
.OrderBy(ff => ff.Source)
.ToArray();
}
public static DisplaySettings LoadDisplaySettings(ILSpySettings settings)
{
XElement e = settings["DisplaySettings"];
DisplaySettings s = new DisplaySettings();
s.SelectedFont = new FontFamily((string)e.Attribute("Font") ?? "Consolas");
s.SelectedFontSize = (double?)e.Attribute("FontSize") ?? 10.0 * 4 / 3;
s.ShowLineNumbers = (bool?)e.Attribute("ShowLineNumbers") ?? false;
return s;
}
public void Save(XElement root)
{
DisplaySettings s = (DisplaySettings)this.DataContext;
currentDisplaySettings.CopyValues(s);
XElement section = new XElement("DisplaySettings");
section.SetAttributeValue("Font", s.SelectedFont.Source);
section.SetAttributeValue("FontSize", s.SelectedFontSize);
section.SetAttributeValue("ShowLineNumbers", s.ShowLineNumbers);
XElement existingElement = root.Element("DisplaySettings");
if (existingElement != null)
existingElement.ReplaceWith(section);
else
root.Add(section);
}
}
public class FontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double) {
return Math.Round((double)value / 4 * 3);
}
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string) {
double d;
if (double.TryParse((string)value, out d))
return d * 4 / 3;
return 11 * 4 / 3;
}
throw new NotImplementedException();
}
}
}

4
ILSpy/ILAstLanguage.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.ILSpy
output.Write(" : "); output.Write(" : ");
if (v.IsPinned) if (v.IsPinned)
output.Write("pinned "); output.Write("pinned ");
v.Type.WriteTo(output, true, true); v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
} }
output.WriteLine(); output.WriteLine();
} }
@ -100,7 +100,7 @@ namespace ICSharpCode.ILSpy
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider) public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)
{ {
PlainTextOutput output = new PlainTextOutput(); PlainTextOutput output = new PlainTextOutput();
t.WriteTo(output, true, shortName: !includeNamespace); t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
return output.ToString(); return output.ToString();
} }
} }

50
ILSpy/ILLanguage.cs

@ -64,16 +64,40 @@ namespace ICSharpCode.ILSpy
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleProperty(property); rd.DisassembleProperty(property);
NotifyDecompilationFinished(dis); if (property.GetMethod != null) {
output.WriteLine();
rd.DisassembleMethod(property.GetMethod);
}
if (property.SetMethod != null) {
output.WriteLine();
rd.DisassembleMethod(property.SetMethod);
}
foreach (var m in property.OtherMethods) {
output.WriteLine();
rd.DisassembleMethod(m);
}
NotifyDecompilationFinished(rd);
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleEvent(ev); rd.DisassembleEvent(ev);
NotifyDecompilationFinished(dis); if (ev.AddMethod != null) {
output.WriteLine();
rd.DisassembleMethod(ev.AddMethod);
}
if (ev.RemoveMethod != null) {
output.WriteLine();
rd.DisassembleMethod(ev.RemoveMethod);
}
foreach (var m in ev.OtherMethods) {
output.WriteLine();
rd.DisassembleMethod(m);
}
NotifyDecompilationFinished(rd);
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
@ -94,14 +118,24 @@ namespace ICSharpCode.ILSpy
output.WriteLine("// " + assembly.FileName); output.WriteLine("// " + assembly.FileName);
output.WriteLine(); output.WriteLine();
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).WriteAssemblyHeader(assembly.AssemblyDefinition); ReflectionDisassembler rd = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
if (options.FullDecompilation)
rd.WriteAssemblyReferences(assembly.AssemblyDefinition.MainModule);
rd.WriteAssemblyHeader(assembly.AssemblyDefinition);
output.WriteLine();
rd.WriteModuleHeader(assembly.AssemblyDefinition.MainModule);
if (options.FullDecompilation) {
output.WriteLine();
output.WriteLine();
rd.WriteModuleContents(assembly.AssemblyDefinition.MainModule);
}
OnDecompilationFinished(null); OnDecompilationFinished(null);
} }
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider) public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)
{ {
PlainTextOutput output = new PlainTextOutput(); PlainTextOutput output = new PlainTextOutput();
t.WriteTo(output, true, shortName: !includeNamespace); t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
return output.ToString(); return output.ToString();
} }
} }

13
ILSpy/ILSpy.csproj

@ -99,7 +99,6 @@
<Compile Include="AvalonEdit\TextMarkerService.cs" /> <Compile Include="AvalonEdit\TextMarkerService.cs" />
<Compile Include="AvalonEdit\TextEditorWeakEventManager.cs" /> <Compile Include="AvalonEdit\TextEditorWeakEventManager.cs" />
<Compile Include="AvalonEdit\ITextMarker.cs" /> <Compile Include="AvalonEdit\ITextMarker.cs" />
<Compile Include="BamlDecompiler.cs" />
<Compile Include="Bookmarks\BookmarkBase.cs" /> <Compile Include="Bookmarks\BookmarkBase.cs" />
<Compile Include="Bookmarks\BookmarkEventHandler.cs" /> <Compile Include="Bookmarks\BookmarkEventHandler.cs" />
<Compile Include="Bookmarks\BookmarkManager.cs" /> <Compile Include="Bookmarks\BookmarkManager.cs" />
@ -115,6 +114,7 @@
<DependentUpon>DecompilerSettingsPanel.xaml</DependentUpon> <DependentUpon>DecompilerSettingsPanel.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="DisplaySettings.cs" />
<Compile Include="ExportCommandAttribute.cs" /> <Compile Include="ExportCommandAttribute.cs" />
<Compile Include="Controls\SearchBox.cs" /> <Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" /> <Compile Include="Controls\SortableGridViewColumn.cs" />
@ -151,22 +151,27 @@
<Compile Include="SearchPane.cs"> <Compile Include="SearchPane.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="DisplaySettingsPanel.xaml.cs">
<DependentUpon>DisplaySettingsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfacePropertyImplementedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedInterfacePropertyImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceMethodImplementedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceMethodImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceEventImplementedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceEventImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExposedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeExposedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExtensionMethodsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeExtensionMethodsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedVirtualMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Helpers.cs" /> <Compile Include="TreeNodes\Analyzer\Helpers.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" /> <Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" /> <Compile Include="TreeNodes\IMemberTreeNode.cs" />
<Compile Include="TreeNodes\XamlResourceNode.cs" /> <Compile Include="TreeNodes\XamlResourceNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="XmlDoc\AddXmlDocTransform.cs" /> <Compile Include="XmlDoc\AddXmlDocTransform.cs" />
@ -243,6 +248,7 @@
<Page Include="SearchPane.xaml"> <Page Include="SearchPane.xaml">
<DependentUpon>SearchPane.cs</DependentUpon> <DependentUpon>SearchPane.cs</DependentUpon>
</Page> </Page>
<Page Include="DisplaySettingsPanel.xaml" />
<Page Include="TextView\DecompilerTextView.xaml"> <Page Include="TextView\DecompilerTextView.xaml">
<DependentUpon>DecompilerTextView.cs</DependentUpon> <DependentUpon>DecompilerTextView.cs</DependentUpon>
</Page> </Page>
@ -250,6 +256,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Resource Include="Images\Class.png" /> <Resource Include="Images\Class.png" />
<Resource Include="Images\StaticClass.png" />
<Resource Include="Images\Delegate.png" /> <Resource Include="Images\Delegate.png" />
<Resource Include="Images\Enum.png" /> <Resource Include="Images\Enum.png" />
<Resource Include="Images\Field.png" /> <Resource Include="Images\Field.png" />

21
ILSpy/ILSpySettings.cs

@ -19,6 +19,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
@ -58,7 +59,7 @@ namespace ICSharpCode.ILSpy
{ {
using (new MutexProtector(ConfigFileMutex)) { using (new MutexProtector(ConfigFileMutex)) {
try { try {
XDocument doc = XDocument.Load(GetConfigFile()); XDocument doc = LoadWithoutCheckingCharacters(GetConfigFile());
return new ILSpySettings(doc.Root); return new ILSpySettings(doc.Root);
} catch (IOException) { } catch (IOException) {
return new ILSpySettings(); return new ILSpySettings();
@ -68,6 +69,15 @@ namespace ICSharpCode.ILSpy
} }
} }
static XDocument LoadWithoutCheckingCharacters(string fileName)
{
// XDocument.Load(fileName) validates that no invalid characters appear (not even in escaped form),
// but we need those characters for some obfuscated assemblies.
using (XmlTextReader r = new XmlTextReader(fileName)) {
return XDocument.Load(r);
}
}
/// <summary> /// <summary>
/// Saves a setting section. /// Saves a setting section.
/// </summary> /// </summary>
@ -94,7 +104,7 @@ namespace ICSharpCode.ILSpy
string config = GetConfigFile(); string config = GetConfigFile();
XDocument doc; XDocument doc;
try { try {
doc = XDocument.Load(config); doc = LoadWithoutCheckingCharacters(config);
} catch (IOException) { } catch (IOException) {
// ensure the directory exists // ensure the directory exists
Directory.CreateDirectory(Path.GetDirectoryName(config)); Directory.CreateDirectory(Path.GetDirectoryName(config));
@ -104,7 +114,12 @@ namespace ICSharpCode.ILSpy
} }
doc.Root.SetAttributeValue("version", RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision); doc.Root.SetAttributeValue("version", RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision);
action(doc.Root); action(doc.Root);
doc.Save(config); // We can't use XDocument.Save(filename) because that checks for invalid characters, but those can appear
// in obfuscated assemblies.
using (XmlTextWriter writer = new XmlTextWriter(config, Encoding.UTF8)) {
writer.Formatting = Formatting.Indented;
doc.Save(writer);
}
} }
} }

5
ILSpy/Images/Images.cs

@ -65,6 +65,7 @@ namespace ICSharpCode.ILSpy
public static readonly BitmapImage Interface = LoadBitmap("Interface"); public static readonly BitmapImage Interface = LoadBitmap("Interface");
public static readonly BitmapImage Delegate = LoadBitmap("Delegate"); public static readonly BitmapImage Delegate = LoadBitmap("Delegate");
public static readonly BitmapImage Enum = LoadBitmap("Enum"); public static readonly BitmapImage Enum = LoadBitmap("Enum");
public static readonly BitmapImage StaticClass = LoadBitmap("StaticClass");
public static readonly BitmapImage Field = LoadBitmap("Field"); public static readonly BitmapImage Field = LoadBitmap("Field");
@ -133,6 +134,7 @@ namespace ICSharpCode.ILSpy
PreloadPublicIconToCache(TypeIcon.Struct, Images.Struct); PreloadPublicIconToCache(TypeIcon.Struct, Images.Struct);
PreloadPublicIconToCache(TypeIcon.Interface, Images.Interface); PreloadPublicIconToCache(TypeIcon.Interface, Images.Interface);
PreloadPublicIconToCache(TypeIcon.Delegate, Images.Delegate); PreloadPublicIconToCache(TypeIcon.Delegate, Images.Delegate);
PreloadPublicIconToCache(TypeIcon.StaticClass, Images.StaticClass);
} }
protected override ImageSource GetBaseImage(TypeIcon icon) protected override ImageSource GetBaseImage(TypeIcon icon)
@ -154,6 +156,9 @@ namespace ICSharpCode.ILSpy
case TypeIcon.Delegate: case TypeIcon.Delegate:
baseImage = Images.Delegate; baseImage = Images.Delegate;
break; break;
case TypeIcon.StaticClass:
baseImage = Images.StaticClass;
break;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }

BIN
ILSpy/Images/StaticClass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

3
ILSpy/Images/TypeIcon.cs

@ -26,6 +26,7 @@ namespace ICSharpCode.ILSpy
Enum, Enum,
Struct, Struct,
Interface, Interface,
Delegate Delegate,
StaticClass
} }
} }

76
ILSpy/Language.cs

@ -73,67 +73,70 @@ namespace ICSharpCode.ILSpy
/// Gets the name of the language (as shown in the UI) /// Gets the name of the language (as shown in the UI)
/// </summary> /// </summary>
public abstract string Name { get; } public abstract string Name { get; }
/// <summary> /// <summary>
/// Gets the file extension used by source code files in this language. /// Gets the file extension used by source code files in this language.
/// </summary> /// </summary>
public abstract string FileExtension { get; } public abstract string FileExtension { get; }
public virtual string ProjectFileExtension { public virtual string ProjectFileExtension
{
get { return null; } get { return null; }
} }
/// <summary> /// <summary>
/// Gets the syntax highlighting used for this language. /// Gets the syntax highlighting used for this language.
/// </summary> /// </summary>
public virtual ICSharpCode.AvalonEdit.Highlighting.IHighlightingDefinition SyntaxHighlighting { public virtual ICSharpCode.AvalonEdit.Highlighting.IHighlightingDefinition SyntaxHighlighting
get { {
get
{
return ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.GetDefinitionByExtension(this.FileExtension); return ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance.GetDefinitionByExtension(this.FileExtension);
} }
} }
public virtual void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public virtual void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(method.DeclaringType, true) + "." + method.Name); WriteCommentLine(output, TypeToString(method.DeclaringType, true) + "." + method.Name);
} }
public virtual void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public virtual void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(property.DeclaringType, true) + "." + property.Name); WriteCommentLine(output, TypeToString(property.DeclaringType, true) + "." + property.Name);
} }
public virtual void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public virtual void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(field.DeclaringType, true) + "." + field.Name); WriteCommentLine(output, TypeToString(field.DeclaringType, true) + "." + field.Name);
} }
public virtual void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public virtual void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(ev.DeclaringType, true) + "." + ev.Name); WriteCommentLine(output, TypeToString(ev.DeclaringType, true) + "." + ev.Name);
} }
public virtual void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public virtual void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, TypeToString(type, true)); WriteCommentLine(output, TypeToString(type, true));
} }
public virtual void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options) public virtual void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, nameSpace); WriteCommentLine(output, nameSpace);
OnDecompilationFinished(null); OnDecompilationFinished(null);
} }
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, assembly.FileName); WriteCommentLine(output, assembly.FileName);
WriteCommentLine(output, assembly.AssemblyDefinition.FullName); WriteCommentLine(output, assembly.AssemblyDefinition.FullName);
} }
public virtual void WriteCommentLine(ITextOutput output, string comment) public virtual void WriteCommentLine(ITextOutput output, string comment)
{ {
output.WriteLine("// " + comment); output.WriteLine("// " + comment);
} }
/// <summary> /// <summary>
/// Converts a type reference into a string. This method is used by the member tree node for parameter and return types. /// Converts a type reference into a string. This method is used by the member tree node for parameter and return types.
/// </summary> /// </summary>
@ -144,7 +147,7 @@ namespace ICSharpCode.ILSpy
else else
return type.Name; return type.Name;
} }
/// <summary> /// <summary>
/// Converts a member signature to a string. /// Converts a member signature to a string.
/// This is used for displaying the tooltip on a member reference. /// This is used for displaying the tooltip on a member reference.
@ -156,7 +159,7 @@ namespace ICSharpCode.ILSpy
else else
return member.ToString(); return member.ToString();
} }
public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null) public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null)
{ {
if (property == null) if (property == null)
@ -164,6 +167,13 @@ namespace ICSharpCode.ILSpy
return property.Name; return property.Name;
} }
public virtual string FormatTypeName(TypeDefinition type)
{
if (type == null)
throw new ArgumentNullException("type");
return type.Name;
}
/// <summary> /// <summary>
/// Used for WPF keyboard navigation. /// Used for WPF keyboard navigation.
/// </summary> /// </summary>
@ -171,11 +181,19 @@ namespace ICSharpCode.ILSpy
{ {
return Name; return Name;
} }
public virtual bool ShowMember(MemberReference member) public virtual bool ShowMember(MemberReference member)
{ {
return true; return true;
} }
/// <summary>
/// Used by the analyzer to map compiler generated code back to the original code's location
/// </summary>
public virtual MemberReference GetOriginalCodeLocation(MemberReference member)
{
return member;
}
protected virtual void OnDecompilationFinished(DecompileEventArgs e) protected virtual void OnDecompilationFinished(DecompileEventArgs e)
{ {
@ -211,33 +229,35 @@ namespace ICSharpCode.ILSpy
} }
} }
} }
public static class Languages public static class Languages
{ {
static ReadOnlyCollection<Language> allLanguages; static ReadOnlyCollection<Language> allLanguages;
/// <summary> /// <summary>
/// A list of all languages. /// A list of all languages.
/// </summary> /// </summary>
public static ReadOnlyCollection<Language> AllLanguages { public static ReadOnlyCollection<Language> AllLanguages
get { {
get
{
return allLanguages; return allLanguages;
} }
} }
internal static void Initialize(CompositionContainer composition) internal static void Initialize(CompositionContainer composition)
{ {
List<Language> languages = new List<Language>(); List<Language> languages = new List<Language>();
languages.AddRange(composition.GetExportedValues<Language>()); languages.AddRange(composition.GetExportedValues<Language>());
languages.Add(new ILLanguage(true)); languages.Add(new ILLanguage(true));
#if DEBUG #if DEBUG
languages.AddRange(ILAstLanguage.GetDebugLanguages()); languages.AddRange(ILAstLanguage.GetDebugLanguages());
languages.AddRange(CSharpLanguage.GetDebugLanguages()); languages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif #endif
allLanguages = languages.AsReadOnly(); allLanguages = languages.AsReadOnly();
} }
/// <summary> /// <summary>
/// Gets a language using its name. /// Gets a language using its name.
/// If the language is not found, C# is returned instead. /// If the language is not found, C# is returned instead.
@ -247,4 +267,4 @@ namespace ICSharpCode.ILSpy
return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First(); return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First();
} }
} }
} }

15
ILSpy/MainWindow.xaml.cs

@ -242,7 +242,7 @@ namespace ICSharpCode.ILSpy
if (!found) { if (!found) {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
output.Write("Cannot find " + args.NavigateTo); output.Write("Cannot find " + args.NavigateTo);
decompilerTextView.Show(output); decompilerTextView.ShowText(output);
} }
} }
commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore
@ -511,8 +511,12 @@ namespace ICSharpCode.ILSpy
if (ignoreDecompilationRequests) if (ignoreDecompilationRequests)
return; return;
if (recordHistory) if (recordHistory) {
history.Record(new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>(), decompilerTextView.GetState())); var dtState = decompilerTextView.GetState();
if(dtState != null)
history.UpdateCurrent(new NavigationState(dtState));
history.Record(new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>()));
}
if (treeView.SelectedItems.Count == 1) { if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode; ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
@ -586,8 +590,9 @@ namespace ICSharpCode.ILSpy
void NavigateHistory(bool forward) void NavigateHistory(bool forward)
{ {
var combinedState = new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>(), decompilerTextView.GetState()); var dtState = decompilerTextView.GetState();
history.Record(combinedState, replace: true, clearForward: false); if(dtState != null)
history.UpdateCurrent(new NavigationState(dtState));
var newState = forward ? history.GoForward() : history.GoBack(); var newState = forward ? history.GoForward() : history.GoBack();
ignoreDecompilationRequests = true; ignoreDecompilationRequests = true;

12
ILSpy/NavigationHistory.cs

@ -71,13 +71,18 @@ namespace ICSharpCode.ILSpy
back.Clear(); back.Clear();
forward.Clear(); forward.Clear();
} }
public void UpdateCurrent(T node)
{
current = node;
}
public void Record(T node, bool replace = false, bool clearForward = true) public void Record(T node)
{ {
var navigationTime = DateTime.Now; var navigationTime = DateTime.Now;
var period = navigationTime - lastNavigationTime; var period = navigationTime - lastNavigationTime;
if (period.TotalSeconds < NavigationSecondsBeforeNewEntry || replace) { if (period.TotalSeconds < NavigationSecondsBeforeNewEntry) {
current = node; current = node;
} else { } else {
if (current != null) if (current != null)
@ -88,8 +93,7 @@ namespace ICSharpCode.ILSpy
current = node; current = node;
} }
if (clearForward) forward.Clear();
forward.Clear();
lastNavigationTime = navigationTime; lastNavigationTime = navigationTime;
} }

10
ILSpy/NavigationState.cs

@ -32,12 +32,18 @@ namespace ICSharpCode.ILSpy
public IEnumerable<SharpTreeNode> TreeNodes { get { return treeNodes; } } public IEnumerable<SharpTreeNode> TreeNodes { get { return treeNodes; } }
public DecompilerTextViewState ViewState { get; private set; } public DecompilerTextViewState ViewState { get; private set; }
public NavigationState(IEnumerable<SharpTreeNode> treeNodes, DecompilerTextViewState viewState) public NavigationState(DecompilerTextViewState viewState)
{ {
this.treeNodes = new HashSet<SharpTreeNode>(treeNodes); this.treeNodes = new HashSet<SharpTreeNode>(viewState.DecompiledNodes);
ViewState = viewState; ViewState = viewState;
} }
public NavigationState(IEnumerable<SharpTreeNode> treeNodes)
{
this.treeNodes = new HashSet<SharpTreeNode>(treeNodes);
}
public bool Equals(NavigationState other) public bool Equals(NavigationState other)
{ {
// TODO: should this care about the view state as well? // TODO: should this care about the view state as well?

29
ILSpy/TextView/DecompilerTextView.cs

@ -29,6 +29,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
@ -63,6 +64,7 @@ namespace ICSharpCode.ILSpy.TextView
readonly UIElementGenerator uiElementGenerator; readonly UIElementGenerator uiElementGenerator;
List<VisualLineElementGenerator> activeCustomElementGenerators = new List<VisualLineElementGenerator>(); List<VisualLineElementGenerator> activeCustomElementGenerators = new List<VisualLineElementGenerator>();
FoldingManager foldingManager; FoldingManager foldingManager;
ILSpyTreeNode[] decompiledNodes;
DefinitionLookup definitionLookup; DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource; CancellationTokenSource currentCancellationTokenSource;
@ -92,6 +94,9 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.Options.RequireControlModifierForHyperlinkClick = false; textEditor.Options.RequireControlModifierForHyperlinkClick = false;
textEditor.TextArea.TextView.MouseHover += TextViewMouseHover; textEditor.TextArea.TextView.MouseHover += TextViewMouseHover;
textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped; textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped;
textEditor.SetBinding(TextEditor.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") });
textEditor.SetBinding(TextEditor.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") });
textEditor.SetBinding(TextEditor.ShowLineNumbersProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("ShowLineNumbers") });
// add marker service & margin // add marker service & margin
iconMargin = new IconBarMargin((manager = new IconBarManager())); iconMargin = new IconBarMargin((manager = new IconBarManager()));
@ -227,11 +232,21 @@ namespace ICSharpCode.ILSpy.TextView
#endregion #endregion
#region ShowOutput #region ShowOutput
public void ShowText(AvalonEditTextOutput textOutput)
{
ShowNodes(textOutput, null);
}
public void ShowNode(AvalonEditTextOutput textOutput, ILSpyTreeNode node, IHighlightingDefinition highlighting = null)
{
ShowNodes(textOutput, new[] { node }, highlighting);
}
/// <summary> /// <summary>
/// Shows the given output in the text view. /// Shows the given output in the text view.
/// Cancels any currently running decompilation tasks. /// Cancels any currently running decompilation tasks.
/// </summary> /// </summary>
public void Show(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null) public void ShowNodes(AvalonEditTextOutput textOutput, ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting = null)
{ {
// Cancel the decompilation task: // Cancel the decompilation task:
if (currentCancellationTokenSource != null) { if (currentCancellationTokenSource != null) {
@ -240,6 +255,7 @@ namespace ICSharpCode.ILSpy.TextView
} }
this.nextDecompilationRun = null; // remove scheduled decompilation run this.nextDecompilationRun = null; // remove scheduled decompilation run
ShowOutput(textOutput, highlighting); ShowOutput(textOutput, highlighting);
decompiledNodes = nodes;
} }
/// <summary> /// <summary>
@ -362,6 +378,7 @@ namespace ICSharpCode.ILSpy.TextView
} finally { } finally {
iconMargin.InvalidateVisual(); iconMargin.InvalidateVisual();
} }
decompiledNodes = context.TreeNodes;
}); });
} }
@ -550,6 +567,7 @@ namespace ICSharpCode.ILSpy.TextView
output.WriteLine(ex.ToString()); output.WriteLine(ex.ToString());
ShowOutput(output); ShowOutput(output);
} }
decompiledNodes = context.TreeNodes;
}); });
} }
@ -612,11 +630,15 @@ namespace ICSharpCode.ILSpy.TextView
public DecompilerTextViewState GetState() public DecompilerTextViewState GetState()
{ {
if (decompiledNodes == null)
return null;
var state = new DecompilerTextViewState(); var state = new DecompilerTextViewState();
if (foldingManager != null) if (foldingManager != null)
state.SaveFoldingsState(foldingManager.AllFoldings); state.SaveFoldingsState(foldingManager.AllFoldings);
state.VerticalOffset = textEditor.VerticalOffset; state.VerticalOffset = textEditor.VerticalOffset;
state.HorizontalOffset = textEditor.HorizontalOffset; state.HorizontalOffset = textEditor.HorizontalOffset;
state.DecompiledNodes = decompiledNodes;
return state; return state;
} }
} }
@ -627,16 +649,17 @@ namespace ICSharpCode.ILSpy.TextView
private int FoldingsChecksum; private int FoldingsChecksum;
public double VerticalOffset; public double VerticalOffset;
public double HorizontalOffset; public double HorizontalOffset;
public ILSpyTreeNode[] DecompiledNodes;
public void SaveFoldingsState(IEnumerable<FoldingSection> foldings) public void SaveFoldingsState(IEnumerable<FoldingSection> foldings)
{ {
ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList(); ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList();
FoldingsChecksum = foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b); FoldingsChecksum = unchecked(foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
} }
internal void RestoreFoldings(List<NewFolding> list) internal void RestoreFoldings(List<NewFolding> list)
{ {
var checksum = list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b); var checksum = unchecked(list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
if (FoldingsChecksum == checksum) if (FoldingsChecksum == checksum)
foreach (var folding in list) foreach (var folding in list)
folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset); folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);

1
ILSpy/TextView/ILAsm-Mode.xshd

@ -348,6 +348,7 @@
<Word>tls</Word> <Word>tls</Word>
<Word>true</Word> <Word>true</Word>
<Word>false</Word> <Word>false</Word>
<Word>strict</Word>
</Keywords> </Keywords>
<Keywords color="Directives"> <Keywords color="Directives">
<Word>.class</Word> <Word>.class</Word>

43
ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorTreeNode.cs

@ -21,50 +21,19 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
internal sealed class AnalyzedEventAccessorsTreeNode : AnalyzerTreeNode internal class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
{ {
public AnalyzedEventAccessorsTreeNode(EventDefinition analyzedEvent) private string name;
{
if (analyzedEvent == null)
throw new ArgumentNullException("analyzedEvent");
if (analyzedEvent.AddMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
if (analyzedEvent.RemoveMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove"));
foreach (var accessor in analyzedEvent.OtherMethods)
this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null));
}
public override object Icon public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
{ {
get { return Images.Search; } this.name = name;
} }
public override object Text public override object Text
{ {
get { return "Accessors"; } get { return name ?? base.Text; }
}
public static bool CanShow(EventDefinition property)
{
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.AddMethod ?? property.RemoveMethod);
}
internal class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
{
private string name;
public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
{
this.name = name;
}
public override object Text
{
get { return name ?? base.Text; }
}
} }
} }
} }

33
ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs

@ -68,36 +68,25 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
}
private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedEvent, FindReferencesInType);
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return analyzer.PerformAnalysis(ct);
} }
private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{ {
string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedEvent.Name; string name = analyzedEvent.Name;
string declTypeName = analyzedEvent.DeclaringType.FullName; string declTypeName = analyzedEvent.DeclaringType.FullName;
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested();
if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (EventDefinition eventDef in type.Events) { if (!TypesHierarchyHelpers.IsBaseType(analyzedEvent.DeclaringType, type, resolveTypeArguments: false))
ct.ThrowIfCancellationRequested(); yield break;
if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) { foreach (EventDefinition eventDef in type.Events) {
MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod; if (TypesHierarchyHelpers.IsBaseEvent(analyzedEvent, eventDef)) {
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; MethodDefinition anyAccessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : ""); bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
} yield return new AnalyzedEventTreeNode(eventDef, hidesParent ? "(hides) " : "");
} }
} }
} }

17
ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs

@ -57,8 +57,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override void LoadChildren() protected override void LoadChildren()
{ {
if (AnalyzedEventAccessorsTreeNode.CanShow(analyzedEvent)) if (analyzedEvent.AddMethod != null)
this.Children.Add(new AnalyzedEventAccessorsTreeNode(analyzedEvent)); this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
if (analyzedEvent.RemoveMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove"));
foreach (var accessor in analyzedEvent.OtherMethods)
this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null));
if (AnalyzedEventOverridesTreeNode.CanShow(analyzedEvent)) if (AnalyzedEventOverridesTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent)); this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent));
if (AnalyzedInterfaceEventImplementedByTreeNode.CanShow(analyzedEvent)) if (AnalyzedInterfaceEventImplementedByTreeNode.CanShow(analyzedEvent))
@ -75,12 +80,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public static bool CanShow(MemberReference member) public static bool CanShow(MemberReference member)
{ {
var property = member as EventDefinition; var eventDef = member as EventDefinition;
if (property == null) if (eventDef == null)
return false; return false;
return AnalyzedEventAccessorsTreeNode.CanShow(property) return !MainWindow.Instance.CurrentLanguage.ShowMember(eventDef.AddMethod ?? eventDef.RemoveMethod)
|| AnalyzedEventOverridesTreeNode.CanShow(property); || AnalyzedEventOverridesTreeNode.CanShow(eventDef);
} }
} }
} }

34
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs

@ -22,6 +22,7 @@ using System.Threading;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using System.Collections;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
@ -30,6 +31,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private readonly bool showWrites; // true: show writes; false: show read access private readonly bool showWrites; // true: show writes; false: show read access
private readonly FieldDefinition analyzedField; private readonly FieldDefinition analyzedField;
private readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
private Lazy<Hashtable> foundMethods;
private object hashLock = new object();
public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites) public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites)
{ {
@ -68,8 +71,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
var analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedField, FindReferencesInType); foundMethods = new Lazy<Hashtable>(LazyThreadSafetyMode.ExecutionAndPublication);
return analyzer.PerformAnalysis(ct);
var analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedField, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct)) {
yield return child;
}
foundMethods = null;
} }
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
@ -95,8 +104,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
method.Body = null; method.Body = null;
if (found) if (found) {
yield return new AnalyzedMethodTreeNode(method); MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
yield return new AnalyzedMethodTreeNode(codeLocation);
}
}
} }
} }
@ -116,5 +129,18 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false; return false;
} }
} }
private bool HasAlreadyBeenFound(MethodDefinition method)
{
Hashtable hashtable = foundMethods.Value;
lock (hashLock) {
if (hashtable.Contains(method)) {
return true;
} else {
hashtable.Add(method, null);
return false;
}
}
}
} }
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs

@ -69,8 +69,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs

@ -67,8 +67,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs

@ -69,8 +69,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

51
ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs

@ -73,45 +73,32 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
}
private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return analyzer.PerformAnalysis(ct);
} }
private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{ {
string asmName = asm.AssemblyDefinition.Name.Name; SharpTreeNode newNode = null;
string name = analyzedMethod.Name; try {
string declTypeName = analyzedMethod.DeclaringType.FullName; if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false))
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) { yield break;
ct.ThrowIfCancellationRequested();
SharpTreeNode newNode = null; foreach (MethodDefinition method in type.Methods) {
try { if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
if (!TypesHierarchyHelpers.IsBaseType(analyzedMethod.DeclaringType, type, resolveTypeArguments: false)) bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
continue; newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
foreach (MethodDefinition method in type.Methods) {
ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseMethod(analyzedMethod, method)) {
bool hidesParent = !method.IsVirtual ^ method.IsNewSlot;
newNode = new AnalyzedMethodTreeNode(method, hidesParent ? "(hides) " : "");
}
} }
} }
catch (ReferenceResolvingException) {
// ignore this type definition. maybe add a notification about such cases.
}
if (newNode != null)
yield return newNode;
} }
catch (ReferenceResolvingException) {
// ignore this type definition. maybe add a notification about such cases.
}
if (newNode != null)
yield return newNode;
} }
public static bool CanShow(MethodDefinition method) public static bool CanShow(MethodDefinition method)

8
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -58,9 +58,15 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
if (analyzedMethod.HasBody) if (analyzedMethod.HasBody)
this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod));
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
if (analyzedMethod.IsVirtual && !(analyzedMethod.IsNewSlot && analyzedMethod.IsFinal))
this.Children.Add(new AnalyzedVirtualMethodUsedByTreeNode(analyzedMethod));
else
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod)) if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod)) if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));
} }

28
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
@ -29,6 +30,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
private readonly MethodDefinition analyzedMethod; private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
private ConcurrentDictionary<MethodDefinition, int> foundMethods;
public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod) public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod)
{ {
@ -66,10 +68,14 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; foundMethods = new ConcurrentDictionary<MethodDefinition, int>();
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType); var analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct); foreach (var child in analyzer.PerformAnalysis(ct)) {
yield return child;
}
foundMethods = null;
} }
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
@ -81,8 +87,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
continue; continue;
foreach (Instruction instr in method.Body.Instructions) { foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference; MethodReference mr = instr.Operand as MethodReference;
if (mr != null && if (mr != null && mr.Name == name &&
mr.Name == name &&
Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
mr.Resolve() == analyzedMethod) { mr.Resolve() == analyzedMethod) {
found = true; found = true;
@ -92,9 +97,18 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
method.Body = null; method.Body = null;
if (found) if (found) {
yield return new AnalyzedMethodTreeNode(method); MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
yield return new AnalyzedMethodTreeNode(codeLocation);
}
}
} }
} }
private bool HasAlreadyBeenFound(MethodDefinition method)
{
return !foundMethods.TryAdd(method, 0);
}
} }
} }

43
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorTreeNode.cs

@ -21,50 +21,19 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
internal sealed class AnalyzedPropertyAccessorsTreeNode : AnalyzerTreeNode internal class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode
{ {
public AnalyzedPropertyAccessorsTreeNode(PropertyDefinition analyzedProperty) private readonly string name;
{
if (analyzedProperty == null)
throw new ArgumentNullException("analyzedProperty");
if (analyzedProperty.GetMethod != null)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
if (analyzedProperty.SetMethod != null)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set"));
foreach (var accessor in analyzedProperty.OtherMethods)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
}
public override object Icon public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
{ {
get { return Images.Search; } this.name = name;
} }
public override object Text public override object Text
{ {
get { return "Accessors"; } get { return name ?? base.Text; }
}
public static bool CanShow(PropertyDefinition property)
{
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod);
}
private class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode
{
private readonly string name;
public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod)
{
this.name = name;
}
public override object Text
{
get { return name ?? base.Text; }
}
} }
} }
} }

40
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs

@ -69,45 +69,27 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
}
private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedProperty, FindReferencesInType);
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return analyzer.PerformAnalysis(ct);
} }
private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{ {
string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedProperty.Name; string name = analyzedProperty.Name;
string declTypeName = analyzedProperty.DeclaringType.FullName; string declTypeName = analyzedProperty.DeclaringType.FullName;
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested();
SharpTreeNode newNode = null; if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
try { yield break;
if (!TypesHierarchyHelpers.IsBaseType(analyzedProperty.DeclaringType, type, resolveTypeArguments: false))
continue;
foreach (PropertyDefinition property in type.Properties) { foreach (PropertyDefinition property in type.Properties) {
ct.ThrowIfCancellationRequested();
if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) { if (TypesHierarchyHelpers.IsBaseProperty(analyzedProperty, property)) {
MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod; MethodDefinition anyAccessor = property.GetMethod ?? property.SetMethod;
bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot; bool hidesParent = !anyAccessor.IsVirtual ^ anyAccessor.IsNewSlot;
newNode = new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : ""); yield return new AnalyzedPropertyTreeNode(property, hidesParent ? "(hides) " : "");
}
}
}
catch (ReferenceResolvingException) {
// ignore this type definition.
} }
if (newNode != null)
yield return newNode;
} }
} }

13
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs

@ -60,8 +60,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override void LoadChildren() protected override void LoadChildren()
{ {
if (AnalyzedPropertyAccessorsTreeNode.CanShow(analyzedProperty)) if (analyzedProperty.GetMethod != null)
this.Children.Add(new AnalyzedPropertyAccessorsTreeNode(analyzedProperty)); this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
if (analyzedProperty.SetMethod != null)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.SetMethod, "set"));
foreach (var accessor in analyzedProperty.OtherMethods)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty)) if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty)); this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty));
if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty)) if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty))
@ -82,8 +87,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
if (property == null) if (property == null)
return false; return false;
return AnalyzedPropertyAccessorsTreeNode.CanShow(property) return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod)
|| AnalyzedPropertyOverridesTreeNode.CanShow(property); || AnalyzedPropertyOverridesTreeNode.CanShow(property);
} }
} }
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs

@ -65,9 +65,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs

@ -66,9 +66,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

4
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -71,9 +71,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType); analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }

151
ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs

@ -0,0 +1,151 @@
// 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.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ICSharpCode.TreeView;
using Mono.Cecil;
using Mono.Cecil.Cil;
using ICSharpCode.Decompiler.Ast;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedVirtualMethodUsedByTreeNode : AnalyzerTreeNode
{
private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading;
private ConcurrentDictionary<MethodDefinition, int> foundMethods;
private MethodDefinition baseMethod;
private List<TypeReference> possibleTypes;
public AnalyzedVirtualMethodUsedByTreeNode(MethodDefinition analyzedMethod)
{
if (analyzedMethod == null)
throw new ArgumentNullException("analyzedMethod");
this.analyzedMethod = analyzedMethod;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Used By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
InitializeAnalyzer();
var analyzer = new ScopedWhereUsedAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
foreach (var child in analyzer.PerformAnalysis(ct)) {
yield return child;
}
ReleaseAnalyzer();
}
private void InitializeAnalyzer()
{
foundMethods = new ConcurrentDictionary<MethodDefinition, int>();
var BaseMethods = TypesHierarchyHelpers.FindBaseMethods(analyzedMethod).ToArray();
if (BaseMethods.Length > 0) {
baseMethod = BaseMethods[BaseMethods.Length - 1];
}
possibleTypes = new List<TypeReference>();
TypeReference type = analyzedMethod.DeclaringType.BaseType;
while (type !=null)
{
possibleTypes.Add(type);
type = type.Resolve().BaseType;
}
}
private void ReleaseAnalyzer()
{
foundMethods = null;
baseMethod = null;
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
string name = analyzedMethod.Name;
foreach (MethodDefinition method in type.Methods) {
bool found = false;
string prefix = string.Empty;
if (!method.HasBody)
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == name) {
// explicit call to the requested method
if (Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) {
found = true;
prefix = "(as base) ";
break;
}
// virtual call to base method
if (instr.OpCode.Code == Code.Callvirt && Helpers.IsReferencedBy(baseMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == baseMethod) {
found = true;
break;
}
}
}
method.Body = null;
if (found) {
MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition;
if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) {
yield return new AnalyzedMethodTreeNode(codeLocation, prefix);
}
}
}
}
private bool HasAlreadyBeenFound(MethodDefinition method)
{
return !foundMethods.TryAdd(method, 0);
}
}
}

63
ILSpy/TreeNodes/Analyzer/Helpers.cs

@ -20,7 +20,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ICSharpCode.Decompiler;
using Mono.Cecil; using Mono.Cecil;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
@ -50,5 +53,65 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return true; return true;
} }
public static MemberReference GetOriginalCodeLocation(MemberReference member)
{
if (member is MethodDefinition)
return GetOriginalCodeLocation((MethodDefinition)member);
return member;
}
public static MethodDefinition GetOriginalCodeLocation(MethodDefinition method)
{
if (method.IsCompilerGenerated()) {
return FindMethodUsageInType(method.DeclaringType, method) ?? method;
}
var typeUsage = GetOriginalCodeLocation(method.DeclaringType, method);
return typeUsage ?? method;
}
public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type, MethodDefinition method)
{
if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) {
MethodDefinition constructor = GetTypeConstructor(type);
return FindMethodUsageInType(type.DeclaringType, constructor);
}
return null;
}
private static MethodDefinition GetTypeConstructor(TypeDefinition type)
{
foreach (MethodDefinition method in type.Methods) {
if (method.Name == ".ctor")
return method;
}
return null;
}
private static MethodDefinition FindMethodUsageInType(TypeDefinition type, MethodDefinition analyzedMethod)
{
string name = analyzedMethod.Name;
foreach (MethodDefinition method in type.Methods) {
bool found = false;
if (!method.HasBody)
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == name &&
Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
mr.Resolve() == analyzedMethod) {
found = true;
break;
}
}
method.Body = null;
if (found)
return method;
}
return null;
}
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save