Browse Source

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

pull/191/merge
Eusebiu Marcu 16 years ago
parent
commit
f71f00b23d
  1. 167
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 100
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 35
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  4. 85
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  5. 142
      ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs
  6. 202
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  7. 47
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs
  8. 280
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs
  9. 56
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
  10. 15
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  11. 7
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  12. 2
      ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
  13. 97
      ICSharpCode.Decompiler/CecilExtensions.cs
  14. 31
      ICSharpCode.Decompiler/DecompilerSettings.cs
  15. 8
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  16. 2
      ICSharpCode.Decompiler/Disassembler/ILStructure.cs
  17. 2
      ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
  18. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  19. 4
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  20. 3
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  21. 71
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  22. 68
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  23. 17
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  24. 37
      ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs
  25. 6
      ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs
  26. 98
      ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  27. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  28. 22
      ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
  29. 25
      ICSharpCode.Decompiler/Tests/InitializerTests.cs
  30. 149
      ICSharpCode.Decompiler/Tests/QueryExpressions.cs
  31. 10
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  32. 15
      ICSharpCode.Decompiler/Tests/ValueTypes.cs
  33. 70
      ILSpy/CSharpLanguage.cs
  34. 2
      ILSpy/ILAstLanguage.cs
  35. 31
      ILSpy/ILSpy.csproj
  36. 34
      ILSpy/Images/AccessOverlayIcon.cs
  37. BIN
      ILSpy/Images/Class.png
  38. BIN
      ILSpy/Images/Constructor.png
  39. BIN
      ILSpy/Images/Delegate.png
  40. BIN
      ILSpy/Images/Enum.png
  41. BIN
      ILSpy/Images/EnumValue.png
  42. BIN
      ILSpy/Images/Event.png
  43. BIN
      ILSpy/Images/ExtensionMethod.png
  44. BIN
      ILSpy/Images/Field.png
  45. BIN
      ILSpy/Images/FieldReadOnly.png
  46. BIN
      ILSpy/Images/Folder.Closed.png
  47. BIN
      ILSpy/Images/Folder.Open.png
  48. 285
      ILSpy/Images/Images.cs
  49. BIN
      ILSpy/Images/Indexer.png
  50. BIN
      ILSpy/Images/Interface.png
  51. BIN
      ILSpy/Images/InternalClass.png
  52. BIN
      ILSpy/Images/InternalDelegate.png
  53. BIN
      ILSpy/Images/InternalEnum.png
  54. BIN
      ILSpy/Images/InternalInterface.png
  55. BIN
      ILSpy/Images/InternalStruct.png
  56. BIN
      ILSpy/Images/Literal.png
  57. 38
      ILSpy/Images/MemberIcon.cs
  58. BIN
      ILSpy/Images/Method.png
  59. BIN
      ILSpy/Images/Operator.png
  60. BIN
      ILSpy/Images/OverlayInternal.png
  61. BIN
      ILSpy/Images/OverlayPrivate.png
  62. BIN
      ILSpy/Images/OverlayProtected.png
  63. BIN
      ILSpy/Images/OverlayProtectedInternal.png
  64. BIN
      ILSpy/Images/OverlayStatic.png
  65. BIN
      ILSpy/Images/PrivateClass.png
  66. BIN
      ILSpy/Images/PrivateDelegate.png
  67. BIN
      ILSpy/Images/PrivateEnum.png
  68. BIN
      ILSpy/Images/PrivateInterface.png
  69. BIN
      ILSpy/Images/PrivateStruct.png
  70. BIN
      ILSpy/Images/Property.png
  71. BIN
      ILSpy/Images/ProtectedClass.png
  72. BIN
      ILSpy/Images/ProtectedDelegate.png
  73. BIN
      ILSpy/Images/ProtectedEnum.png
  74. BIN
      ILSpy/Images/ProtectedInterface.png
  75. BIN
      ILSpy/Images/ProtectedStruct.png
  76. BIN
      ILSpy/Images/Resource.png
  77. BIN
      ILSpy/Images/ResourceImage.png
  78. BIN
      ILSpy/Images/ResourceResourcesFile.png
  79. BIN
      ILSpy/Images/Struct.png
  80. BIN
      ILSpy/Images/SubTypes.png
  81. BIN
      ILSpy/Images/SuperTypes.png
  82. 31
      ILSpy/Images/TypeIcon.cs
  83. BIN
      ILSpy/Images/VirtualMethod.png
  84. 7
      ILSpy/Language.cs
  85. 24
      ILSpy/LoadedAssembly.cs
  86. 1
      ILSpy/Options/DecompilerSettingsPanel.xaml
  87. 2
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs
  88. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs
  89. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  90. 3
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
  91. 9
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
  92. 3
      ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs
  93. 25
      ILSpy/TreeNodes/EventTreeNode.cs
  94. 58
      ILSpy/TreeNodes/FieldTreeNode.cs
  95. 85
      ILSpy/TreeNodes/MethodTreeNode.cs
  96. 102
      ILSpy/TreeNodes/PropertyTreeNode.cs
  97. 7
      ILSpy/TreeNodes/ResourceEntryNode.cs
  98. 8
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  99. 7
      ILSpy/TreeNodes/ResourceTreeNode.cs
  100. 90
      ILSpy/TreeNodes/TypeTreeNode.cs
  101. Some files were not shown because too many files have changed in this diff Show More

167
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.Ast
public class AstBuilder
{
DecompilerContext context = new DecompilerContext();
DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
bool transformationsHaveRun;
@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.Ast
} else if (type != null && type.IsCompilerGenerated()) {
if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
return true;
if (type.Name.StartsWith("<>", StringComparison.Ordinal) && type.Name.Contains("AnonymousType"))
if (type.IsAnonymousType())
return true;
}
FieldDefinition field = member as FieldDefinition;
@ -168,7 +168,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -168,7 +168,7 @@ namespace ICSharpCode.Decompiler.Ast
AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
}
public void AddProperty(PropertyDefinition property)
{
astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
@ -265,7 +265,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -265,7 +265,7 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var m in typeDef.Methods) {
if (m.Name == "Invoke") {
dd.ReturnType = ConvertType(m.ReturnType, m.MethodReturnType);
dd.Parameters.AddRange(MakeParameters(m.Parameters));
dd.Parameters.AddRange(MakeParameters(m));
}
}
result = dd;
@ -277,10 +277,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -277,10 +277,9 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var i in typeDef.Interfaces)
astType.AddChild(ConvertType(i), TypeDeclaration.BaseTypeRole);
AddTypeMembers(astType, typeDef);
if (astType.Members.Any(m => m is IndexerDeclaration)) {
if (astType.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull)) {
// Remove the [DefaultMember] attribute if the class contains indexers
foreach (AttributeSection section in astType.Attributes) {
foreach (Ast.Attribute attr in section.Attributes) {
@ -299,11 +298,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -299,11 +298,6 @@ namespace ICSharpCode.Decompiler.Ast
return result;
}
public void Transform(IAstTransform transform)
{
transform.Run(astCompileUnit);
}
internal static string CleanName(string name)
{
int pos = name.LastIndexOf('`');
@ -635,7 +629,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -635,7 +629,7 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = CleanName(methodDef.Name);
astMethod.TypeParameters.AddRange(MakeTypeParameters(methodDef.GenericParameters));
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) {
@ -727,7 +721,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -727,7 +721,7 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Modifiers &= ~Modifiers.VisibilityMask;
}
astMethod.Name = CleanName(methodDef.DeclaringType.Name);
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters));
astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping);
@ -763,11 +757,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -763,11 +757,11 @@ namespace ICSharpCode.Decompiler.Ast
if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null))
foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef))
if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New;
@ -808,39 +802,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -808,39 +802,12 @@ namespace ICSharpCode.Decompiler.Ast
}
ConvertCustomAttributes(astProp, propDef);
// Check whether the property is an indexer:
if (propDef.HasParameters) {
PropertyDefinition basePropDef = propDef;
if (accessor.HasOverrides) {
// if the property is explicitly implementing an interface, look up the property in the interface:
MethodDefinition baseAccessor = accessor.Overrides.First().Resolve();
if (baseAccessor != null) {
foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) {
if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) {
basePropDef = baseProp;
break;
}
}
}
}
// figure out the name of the indexer:
string defaultMemberName = null;
var defaultMemberAttribute = basePropDef.DeclaringType.CustomAttributes.FirstOrDefault(IsDefaultMemberAttribute);
if (defaultMemberAttribute != null && defaultMemberAttribute.ConstructorArguments.Count == 1) {
defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string;
}
if (basePropDef.Name == defaultMemberName) {
return ConvertPropertyToIndexer(astProp, propDef);
}
}
return astProp;
if(propDef.IsIndexer())
return ConvertPropertyToIndexer(astProp, propDef);
else
return astProp;
}
bool IsDefaultMemberAttribute(CustomAttribute ca)
{
return ca.AttributeType.Name == "DefaultMemberAttribute" && ca.AttributeType.Namespace == "System.Reflection";
}
IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
{
var astIndexer = new IndexerDeclaration();
@ -913,21 +880,38 @@ namespace ICSharpCode.Decompiler.Ast @@ -913,21 +880,38 @@ namespace ICSharpCode.Decompiler.Ast
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);
astField.Modifiers = ConvertModifiers(fieldDef);
if (fieldDef.HasConstant) {
if (fieldDef.Constant == null)
if (fieldDef.Constant == null) {
initializer.Initializer = new NullReferenceExpression();
else
initializer.Initializer = new PrimitiveExpression(fieldDef.Constant);
} else {
TypeCode c = Type.GetTypeCode(fieldDef.Constant.GetType());
if (c >= TypeCode.SByte && c <= TypeCode.UInt64) {
initializer.Initializer = MakePrimitive((long)CSharpPrimitiveCast.Cast(TypeCode.Int64, fieldDef.Constant, false), fieldDef.FieldType);
} else {
initializer.Initializer = new PrimitiveExpression(fieldDef.Constant);
}
}
}
ConvertAttributes(astField, fieldDef);
return astField;
}
public static IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
public static IEnumerable<ParameterDeclaration> MakeParameters(MethodDefinition method, bool isLambda = false)
{
var parameters = MakeParameters(method.Parameters, isLambda);
if (method.CallingConvention == MethodCallingConvention.VarArg) {
return parameters.Concat(new[] { new ParameterDeclaration { Name = "__arglist" } });
} else {
return parameters;
}
}
public static IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol, bool isLambda = false)
{
foreach(ParameterDefinition paramDef in paramCol) {
ParameterDeclaration astParam = new ParameterDeclaration();
astParam.AddAnnotation(paramDef);
astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
if (!(isLambda && paramDef.ParameterType.ContainsAnonymousType()))
astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
astParam.Name = paramDef.Name;
if (paramDef.ParameterType is ByReferenceType) {
@ -1272,27 +1256,40 @@ namespace ICSharpCode.Decompiler.Ast @@ -1272,27 +1256,40 @@ namespace ICSharpCode.Decompiler.Ast
if (type != null)
{ // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum)
{
foreach (FieldDefinition field in enumDefinition.Fields)
{
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
else if (!field.IsStatic && field.IsRuntimeSpecialName)
type = field.FieldType; // use primitive type of the enum
}
if (IsFlagsEnum(enumDefinition))
{
TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type);
if (IsFlagsEnum(enumDefinition)) {
long enumValue = val;
Expression expr = null;
foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic))
{
long negatedEnumValue = ~val;
// limit negatedEnumValue to the appropriate range
switch (enumBaseTypeCode) {
case TypeCode.Byte:
case TypeCode.SByte:
negatedEnumValue &= byte.MaxValue;
break;
case TypeCode.Int16:
case TypeCode.UInt16:
negatedEnumValue &= ushort.MaxValue;
break;
case TypeCode.Int32:
case TypeCode.UInt32:
negatedEnumValue &= uint.MaxValue;
break;
}
Expression negatedExpr = null;
foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) {
long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
if (fieldValue == 0)
continue; // skip None enum value
if ((fieldValue & enumValue) == fieldValue)
{
if ((fieldValue & enumValue) == fieldValue) {
var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
if (expr == null)
expr = fieldExpression;
@ -1300,22 +1297,33 @@ namespace ICSharpCode.Decompiler.Ast @@ -1300,22 +1297,33 @@ namespace ICSharpCode.Decompiler.Ast
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
enumValue &= ~fieldValue;
if (enumValue == 0)
break;
}
if ((fieldValue & negatedEnumValue) == fieldValue) {
var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
if (negatedExpr == null)
negatedExpr = fieldExpression;
else
negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
negatedEnumValue &= ~fieldValue;
}
}
if (enumValue == 0 && expr != null) {
if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
return expr;
}
}
if (negatedEnumValue == 0 && negatedExpr != null) {
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
}
if(enumValue == 0 && expr != null)
return expr;
}
TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type);
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition));
}
}
TypeCode code = TypeAnalysis.GetTypeCode(type);
if (code == TypeCode.Object || code == TypeCode.Empty)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
code = TypeCode.Int32;
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
}
static bool IsFlagsEnum(TypeDefinition type)
@ -1325,18 +1333,5 @@ namespace ICSharpCode.Decompiler.Ast @@ -1325,18 +1333,5 @@ namespace ICSharpCode.Decompiler.Ast
return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
}
/// <summary>
/// Gets the name of the default member of the type pointed by the <see cref="System.Reflection.DefaultMemberAttribute"/> attribute.
/// </summary>
/// <param name="type">The type definition.</param>
/// <returns>The name of the default member or null if no <see cref="System.Reflection.DefaultMemberAttribute"/> attribute has been found.</returns>
private static Tuple<string, CustomAttribute> GetDefaultMember(TypeDefinition type)
{
foreach (CustomAttribute ca in type.CustomAttributes)
if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)")
return Tuple.Create(ca.ConstructorArguments.Single().Value as string, ca);
return new Tuple<string,CustomAttribute>(null, null);
}
}
}

100
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -91,7 +91,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -91,7 +91,12 @@ namespace ICSharpCode.Decompiler.Ast
Statement insertionPoint = astBlock.Statements.FirstOrDefault();
foreach (ILVariable v in localVariablesToDefine) {
var newVarDecl = new VariableDeclarationStatement(AstBuilder.ConvertType(v.Type), v.Name);
AstType type;
if (v.Type.ContainsAnonymousType())
type = new SimpleType("var");
else
type = AstBuilder.ConvertType(v.Type);
var newVarDecl = new VariableDeclarationStatement(type, v.Name);
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
}
@ -165,12 +170,18 @@ namespace ICSharpCode.Decompiler.Ast @@ -165,12 +170,18 @@ namespace ICSharpCode.Decompiler.Ast
var tryCatchStmt = new Ast.TryCatchStatement();
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
tryCatchStmt.CatchClauses.Add(
new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause)
});
if (catchClause.ExceptionVariable == null
&& (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
{
tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
} else {
tryCatchStmt.CatchClauses.Add(
new Ast.CatchClause {
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause)
});
}
}
if (tryCatchNode.FinallyBlock != null)
tryCatchStmt.FinallyBlock = TransformBlock(tryCatchNode.FinallyBlock);
@ -353,8 +364,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -353,8 +364,9 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
case ILCode.CompoundAssignment:
{
BinaryOperatorExpression boe = (BinaryOperatorExpression)arg1;
return new Ast.AssignmentExpression {
CastExpression cast = arg1 as CastExpression;
BinaryOperatorExpression boe = (BinaryOperatorExpression)(cast != null ? cast.Expression : arg1);
var assignment = new Ast.AssignmentExpression {
Left = boe.Left.Detach(),
Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
Right = boe.Right.Detach()
@ -362,6 +374,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -362,6 +374,12 @@ namespace ICSharpCode.Decompiler.Ast
// We do not mark the resulting assignment as RestoreOriginalAssignOperatorAnnotation, because
// the operator cannot be translated back to the expanded form (as the left-hand expression
// would be evaluated twice, and might have side-effects)
if (cast != null) {
cast.Expression = assignment;
return cast;
} else {
return assignment;
}
}
#endregion
#region Comparison
@ -449,7 +467,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -449,7 +467,12 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Castclass: return arg1.CastTo(operandAsTypeRef);
case ILCode.Unbox_Any: return arg1.CastTo(operandAsTypeRef);
case ILCode.Unbox_Any:
// unboxing does not require a cast if the argument was an isinst instruction
if (arg1 is AsExpression && byteCode.Arguments[0].Code == ILCode.Isinst && TypeAnalysis.IsSameType(operand as TypeReference, byteCode.Arguments[0].Operand as TypeReference))
return arg1;
else
return arg1.CastTo(operandAsTypeRef);
case ILCode.Isinst: return arg1.CastAs(operandAsTypeRef);
case ILCode.Box: return arg1;
case ILCode.Unbox: return InlineAssembly(byteCode, args);
@ -468,16 +491,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -468,16 +491,17 @@ namespace ICSharpCode.Decompiler.Ast
else
return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2);
#endregion
case ILCode.Arglist: return InlineAssembly(byteCode, args);
case ILCode.Arglist:
return new ArgListExpression { IsAccess = true };
case ILCode.Break: return InlineAssembly(byteCode, args);
case ILCode.Call:
case ILCode.CallGetter:
case ILCode.CallSetter:
return TransformCall(false, operand, args);
return TransformCall(false, byteCode, args);
case ILCode.Callvirt:
case ILCode.CallvirtGetter:
case ILCode.CallvirtSetter:
return TransformCall(true, operand, args);
return TransformCall(true, byteCode, args);
case ILCode.Ldftn: {
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
var expr = new Ast.IdentifierExpression(cecilMethod.Name);
@ -511,8 +535,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -511,8 +535,10 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args);
case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_I4:
return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8:
return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_R4:
case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal:
@ -583,7 +609,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -583,7 +609,14 @@ namespace ICSharpCode.Decompiler.Ast
CountExpression = DivideBySize(arg1, type)
};
}
case ILCode.Mkrefany: return InlineAssembly(byteCode, args);
case ILCode.Mkrefany:
{
DirectionExpression dir = arg1 as DirectionExpression;
if (dir != null)
return new IdentifierExpression("__makeref").Invoke(dir.Expression.Detach());
else
return InlineAssembly(byteCode, args);
}
case ILCode.Newobj: {
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
if (declaringType is ArrayType) {
@ -598,6 +631,20 @@ namespace ICSharpCode.Decompiler.Ast @@ -598,6 +631,20 @@ namespace ICSharpCode.Decompiler.Ast
}
}
var oce = new Ast.ObjectCreateExpression();
if (declaringType.IsAnonymousType()) {
MethodDefinition ctor = ((MethodReference)operand).Resolve();
if (methodDef != null) {
oce.Initializer = new ArrayInitializerExpression();
for (int i = 0; i < args.Count; i++) {
oce.Initializer.Elements.Add(
new NamedArgumentExpression {
Identifier = ctor.Parameters[i].Name,
Expression = args[i]
});
}
}
return oce;
}
oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
@ -713,9 +760,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -713,9 +760,10 @@ namespace ICSharpCode.Decompiler.Ast
return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) };
}
AstNode TransformCall(bool isVirtual, object operand, List<Ast.Expression> args)
AstNode TransformCall(bool isVirtual, ILExpression byteCode, List<Ast.Expression> args)
{
Cecil.MethodReference cecilMethod = ((MethodReference)operand);
Cecil.MethodReference cecilMethod = (MethodReference)byteCode.Operand;
Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve();
Ast.Expression target;
List<Ast.Expression> methodArgs = new List<Ast.Expression>(args);
if (cecilMethod.HasThis) {
@ -728,6 +776,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -728,6 +776,17 @@ namespace ICSharpCode.Decompiler.Ast
target = ((DirectionExpression)target).Expression;
target.Remove(); // detach from DirectionExpression
}
if (cecilMethodDef != null && cecilMethodDef.DeclaringType.IsInterface) {
TypeReference tr = byteCode.Arguments[0].InferredType;
if (tr != null) {
TypeDefinition td = tr.Resolve();
if (td != null && !td.IsInterface) {
// Calling an interface method on a non-interface object:
// we need to introduce an explicit cast
target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType));
}
}
}
} else {
target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType) };
}
@ -757,8 +816,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -757,8 +816,7 @@ namespace ICSharpCode.Decompiler.Ast
return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last());
}
// Resolve the method to figure out whether it is an accessor:
Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve();
// Test whether the method is an accessor:
if (cecilMethodDef != null) {
if (cecilMethodDef.IsGetter && methodArgs.Count == 0) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) {
@ -906,6 +964,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -906,6 +964,8 @@ namespace ICSharpCode.Decompiler.Ast
GenericInstanceMethod g = cecilMethod as GenericInstanceMethod;
if (g == null)
return null;
if (g.GenericArguments.Any(ta => ta.ContainsAnonymousType()))
return null;
return g.GenericArguments.Select(t => AstBuilder.ConvertType(t));
}

35
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -2,21 +2,54 @@ @@ -2,21 +2,54 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
public class DecompilerContext
{
public ModuleDefinition CurrentModule;
public CancellationToken CancellationToken;
public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod;
public DecompilerSettings Settings = new DecompilerSettings();
// public ITypeResolveContext TypeResolveContext;
// public IProjectContent ProjectContent;
public DecompilerContext(ModuleDefinition currentModule)
{
if (currentModule == null)
throw new ArgumentNullException("currentModule");
this.CurrentModule = currentModule;
// this.ProjectContent = new CecilTypeResolveContext(currentModule);
// List<ITypeResolveContext> resolveContexts = new List<ITypeResolveContext>();
// resolveContexts.Add(this.ProjectContent);
// foreach (AssemblyNameReference r in currentModule.AssemblyReferences) {
// AssemblyDefinition d = currentModule.AssemblyResolver.Resolve(r);
// if (d != null) {
// resolveContexts.Add(new CecilTypeResolveContext(d.MainModule));
// }
// }
// this.TypeResolveContext = new CompositeTypeResolveContext(resolveContexts);
}
/// <summary>
/// Used to pass variable names from a method to its anonymous methods.
/// </summary>
internal List<string> ReservedVariableNames = new List<string>();
public DecompilerContext Clone()
{
return (DecompilerContext)MemberwiseClone();
DecompilerContext ctx = (DecompilerContext)MemberwiseClone();
ctx.ReservedVariableNames = new List<string>(ctx.ReservedVariableNames);
return ctx;
}
}
}

85
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -36,8 +36,16 @@ namespace ICSharpCode.Decompiler.Ast @@ -36,8 +36,16 @@ namespace ICSharpCode.Decompiler.Ast
NameVariables nv = new NameVariables();
nv.context = context;
nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList();
nv.AddExistingNames(parameters.Select(p => p.Name));
nv.AddExistingNames(variables.Where(v => v.IsGenerated).Select(v => v.Name));
// First mark existing variable names as reserved.
foreach (string name in context.ReservedVariableNames)
nv.AddExistingName(name);
foreach (var p in parameters)
nv.AddExistingName(p.Name);
foreach (var v in variables) {
if (v.IsGenerated)
nv.AddExistingName(v.Name);
}
// Now generate names:
foreach (ILVariable p in parameters) {
if (string.IsNullOrEmpty(p.Name))
p.Name = nv.GenerateNameForVariable(p, methodBody);
@ -53,30 +61,59 @@ namespace ICSharpCode.Decompiler.Ast @@ -53,30 +61,59 @@ namespace ICSharpCode.Decompiler.Ast
List<string> fieldNamesInCurrentType;
Dictionary<string, int> typeNames = new Dictionary<string, int>();
void AddExistingNames(IEnumerable<string> existingNames)
public void AddExistingName(string name)
{
foreach (string name in existingNames) {
if (string.IsNullOrEmpty(name))
continue;
// First, identify whether the name already ends with a number:
int pos = name.Length;
while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9')
pos--;
if (pos < name.Length) {
int number;
if (int.TryParse(name.Substring(pos), out number)) {
string nameWithoutDigits = name.Substring(0, pos);
int existingNumber;
if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) {
typeNames[nameWithoutDigits] = Math.Max(number, existingNumber);
} else {
typeNames.Add(nameWithoutDigits, number);
}
continue;
if (string.IsNullOrEmpty(name))
return;
int number;
string nameWithoutDigits = SplitName(name, out number);
int existingNumber;
if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) {
typeNames[nameWithoutDigits] = Math.Max(number, existingNumber);
} else {
typeNames.Add(nameWithoutDigits, number);
}
}
string SplitName(string name, out int number)
{
// First, identify whether the name already ends with a number:
int pos = name.Length;
while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9')
pos--;
if (pos < name.Length) {
if (int.TryParse(name.Substring(pos), out number)) {
return name.Substring(0, pos);
}
}
number = 1;
return name;
}
const char maxLoopVariableName = 'n';
public string GetAlternativeName(string oldVariableName)
{
if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) {
for (char c = 'i'; c <= maxLoopVariableName; c++) {
if (!typeNames.ContainsKey(c.ToString())) {
typeNames.Add(c.ToString(), 1);
return c.ToString();
}
}
if (!typeNames.ContainsKey(name))
typeNames.Add(name, 1);
}
int number;
string nameWithoutDigits = SplitName(oldVariableName, out number);
if (!typeNames.ContainsKey(nameWithoutDigits)) {
typeNames.Add(nameWithoutDigits, 0);
}
int count = ++typeNames[nameWithoutDigits];
if (count > 1) {
return nameWithoutDigits + count.ToString();
} else {
return nameWithoutDigits;
}
}
@ -106,7 +143,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -106,7 +143,7 @@ namespace ICSharpCode.Decompiler.Ast
}
if (isLoopCounter) {
// For loop variables, use i,j,k,l,m,n
for (char c = 'i'; c <= 'n'; c++) {
for (char c = 'i'; c <= maxLoopVariableName; c++) {
if (!typeNames.ContainsKey(c.ToString())) {
proposedName = c.ToString();
break;

142
ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Combines query expressions and removes transparent identifiers.
/// </summary>
public class CombineQueryExpressions : IAstTransform
{
readonly DecompilerContext context;
public CombineQueryExpressions(DecompilerContext context)
{
this.context = context;
}
public void Run(AstNode compilationUnit)
{
if (!context.Settings.QueryExpressions)
return;
CombineQueries(compilationUnit);
}
static readonly InvocationExpression castPattern = new InvocationExpression {
Target = new MemberReferenceExpression {
Target = new AnyNode("inExpr"),
MemberName = "Cast",
TypeArguments = { new AnyNode("targetType") }
}};
void CombineQueries(AstNode node)
{
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
CombineQueries(child);
}
QueryExpression query = node as QueryExpression;
if (query != null) {
QueryFromClause fromClause = (QueryFromClause)query.Clauses.First();
QueryExpression innerQuery = fromClause.Expression as QueryExpression;
if (innerQuery != null) {
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery)) {
RemoveTransparentIdentifierReferences(query);
} else {
QueryContinuationClause continuation = new QueryContinuationClause();
continuation.PrecedingQuery = innerQuery.Detach();
continuation.Identifier = fromClause.Identifier;
fromClause.ReplaceWith(continuation);
}
} else {
Match m = castPattern.Match(fromClause.Expression);
if (m != null) {
fromClause.Type = m.Get<AstType>("targetType").Single().Detach();
fromClause.Expression = m.Get<Expression>("inExpr").Single().Detach();
}
}
}
}
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new ObjectCreateExpression {
Initializer = new ArrayInitializerExpression {
Elements = {
new NamedNode("nae1", new NamedArgumentExpression { Expression = new IdentifierExpression() }),
new NamedNode("nae2", new NamedArgumentExpression { Expression = new AnyNode() })
}
}
}};
bool IsTransparentIdentifier(string identifier)
{
return identifier.StartsWith("<>", StringComparison.Ordinal) && identifier.Contains("TransparentIdentifier");
}
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery)
{
if (!IsTransparentIdentifier(fromClause.Identifier))
return false;
Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last());
if (match == null)
return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedArgumentExpression nae1 = match.Get<NamedArgumentExpression>("nae1").Single();
NamedArgumentExpression nae2 = match.Get<NamedArgumentExpression>("nae2").Single();
if (nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
return false;
IdentifierExpression nae2IdentExpr = nae2.Expression as IdentifierExpression;
if (nae2IdentExpr != null && nae2.Identifier == nae2IdentExpr.Identifier) {
// from * in (from x in ... select new { x = x, y = y }) ...
// =>
// from x in ... ...
fromClause.Remove();
selectClause.Remove();
// Move clauses from innerQuery to query
QueryClause insertionPos = null;
foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
}
} else {
// from * in (from x in ... select new { x = x, y = expr }) ...
// =>
// from x in ... let y = expr ...
fromClause.Remove();
selectClause.Remove();
// Move clauses from innerQuery to query
QueryClause insertionPos = null;
foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
}
query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2.Identifier, Expression = nae2.Expression.Detach() });
}
return true;
}
/// <summary>
/// Removes all occurrences of transparent identifiers
/// </summary>
void RemoveTransparentIdentifierReferences(AstNode node)
{
foreach (AstNode child in node.Children) {
RemoveTransparentIdentifierReferences(child);
}
MemberReferenceExpression mre = node as MemberReferenceExpression;
if (mre != null) {
IdentifierExpression ident = mre.Target as IdentifierExpression;
if (ident != null && IsTransparentIdentifier(ident.Identifier)) {
IdentifierExpression newIdent = new IdentifierExpression(mre.MemberName);
mre.TypeArguments.MoveTo(newIdent.TypeArguments);
newIdent.CopyAnnotationsFrom(mre);
newIdent.RemoveAnnotations<PropertyDeclaration>(); // remove the reference to the property of the anonymous type
mre.ReplaceWith(newIdent);
return;
}
}
}
}
}

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

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler;
@ -37,6 +38,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -37,6 +38,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
}
List<string> currentlyUsedVariableNames = new List<string>();
public DelegateConstruction(DecompilerContext context) : base(context)
{
}
@ -116,13 +119,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -116,13 +119,19 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Create AnonymousMethodExpression and prepare parameters
AnonymousMethodExpression ame = new AnonymousMethodExpression();
ame.Parameters.AddRange(AstBuilder.MakeParameters(method.Parameters));
ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true));
ame.HasParameterList = true;
// rename variables so that they don't conflict with the parameters:
foreach (ParameterDeclaration pd in ame.Parameters) {
EnsureVariableNameIsAvailable(objectCreateExpression, pd.Name);
}
// Decompile the anonymous method:
DecompilerContext subContext = context.Clone();
subContext.CurrentMethod = method;
subContext.ReservedVariableNames.AddRange(currentlyUsedVariableNames);
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext);
body.AcceptVisitor(this, null);
@ -179,6 +188,76 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -179,6 +188,76 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return true;
}
#region Track current variables
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
Debug.Assert(currentlyUsedVariableNames.Count == 0);
try {
currentlyUsedVariableNames.AddRange(methodDeclaration.Parameters.Select(p => p.Name));
return base.VisitMethodDeclaration(methodDeclaration, data);
} finally {
currentlyUsedVariableNames.Clear();
}
}
public override object VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data)
{
Debug.Assert(currentlyUsedVariableNames.Count == 0);
try {
currentlyUsedVariableNames.AddRange(operatorDeclaration.Parameters.Select(p => p.Name));
return base.VisitOperatorDeclaration(operatorDeclaration, data);
} finally {
currentlyUsedVariableNames.Clear();
}
}
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
Debug.Assert(currentlyUsedVariableNames.Count == 0);
try {
currentlyUsedVariableNames.AddRange(constructorDeclaration.Parameters.Select(p => p.Name));
return base.VisitConstructorDeclaration(constructorDeclaration, data);
} finally {
currentlyUsedVariableNames.Clear();
}
}
public override object VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data)
{
Debug.Assert(currentlyUsedVariableNames.Count == 0);
try {
currentlyUsedVariableNames.AddRange(indexerDeclaration.Parameters.Select(p => p.Name));
return base.VisitIndexerDeclaration(indexerDeclaration, data);
} finally {
currentlyUsedVariableNames.Clear();
}
}
public override object VisitAccessor(Accessor accessor, object data)
{
try {
currentlyUsedVariableNames.Add("value");
return base.VisitAccessor(accessor, data);
} finally {
currentlyUsedVariableNames.RemoveAt(currentlyUsedVariableNames.Count - 1);
}
}
public override object VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data)
{
foreach (VariableInitializer v in variableDeclarationStatement.Variables)
currentlyUsedVariableNames.Add(v.Name);
return base.VisitVariableDeclarationStatement(variableDeclarationStatement, data);
}
public override object VisitFixedStatement(FixedStatement fixedStatement, object data)
{
foreach (VariableInitializer v in fixedStatement.Variables)
currentlyUsedVariableNames.Add(v.Name);
return base.VisitFixedStatement(fixedStatement, data);
}
#endregion
static readonly ExpressionStatement displayClassAssignmentPattern =
new ExpressionStatement(new AssignmentExpression(
new NamedNode("variable", new IdentifierExpression()),
@ -187,6 +266,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -187,6 +266,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count;
base.VisitBlockStatement(blockStatement, data);
foreach (ExpressionStatement stmt in blockStatement.Statements.OfType<ExpressionStatement>().ToArray()) {
Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
@ -216,51 +296,57 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -216,51 +296,57 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Delete the variable declaration statement:
AstNode cur = stmt.NextSibling;
stmt.Remove();
if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor) {
// Delete any following statements as long as they assign parameters to the display class
// Do parameter handling only for closures created in the top scope (direct child of method/accessor)
List<ILVariable> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>()
.Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
AstNode next;
for (; cur != null; cur = next) {
next = cur.NextSibling;
// Test for the pattern:
// "variableName.MemberName = right;"
ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }),
new AnyNode("right")
)
);
Match m = closureFieldAssignmentPattern.Match(cur);
if (m != null) {
AstNode right = m.Get("right").Single();
bool isParameter = false;
if (right is ThisReferenceExpression) {
isParameter = true;
} else if (right is IdentifierExpression) {
// handle parameters only if the whole method contains no other occurrance except for 'right'
ILVariable param = right.Annotation<ILVariable>();
isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1;
}
if (isParameter) {
dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule()] = right;
cur.Remove();
} else {
break;
// Delete any following statements as long as they assign parameters to the display class
BlockStatement rootBlock = blockStatement.Ancestors.OfType<BlockStatement>().LastOrDefault() ?? blockStatement;
List<ILVariable> parameterOccurrances = rootBlock.Descendants.OfType<IdentifierExpression>()
.Select(n => n.Annotation<ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
AstNode next;
for (; cur != null; cur = next) {
next = cur.NextSibling;
// Test for the pattern:
// "variableName.MemberName = right;"
ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }),
new AnyNode("right")
)
);
Match m = closureFieldAssignmentPattern.Match(cur);
if (m != null) {
FieldDefinition fieldDef = m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>().ResolveWithinSameModule();
AstNode right = m.Get("right").Single();
bool isParameter = false;
bool isDisplayClassParentPointerAssignment = false;
if (right is ThisReferenceExpression) {
isParameter = true;
} else if (right is IdentifierExpression) {
// handle parameters only if the whole method contains no other occurrance except for 'right'
ILVariable v = right.Annotation<ILVariable>();
isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
if (!isParameter && TypeAnalysis.IsSameType(v.Type, fieldDef.FieldType) && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) {
isDisplayClassParentPointerAssignment = true;
}
}
if (isParameter || isDisplayClassParentPointerAssignment) {
dict[fieldDef] = right;
cur.Remove();
} else {
break;
}
} else {
break;
}
}
// Now create variables for all fields of the display class (except for those that we already handled as parameters)
List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>();
foreach (FieldDefinition field in type.Fields) {
if (dict.ContainsKey(field))
if (dict.ContainsKey(field)) // skip field if it already was handled as parameter
continue;
EnsureVariableNameIsAvailable(blockStatement, field.Name);
currentlyUsedVariableNames.Add(field.Name);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name));
dict[field] = new IdentifierExpression(field.Name);
}
@ -283,7 +369,53 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -283,7 +369,53 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
}
}
currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
return null;
}
void EnsureVariableNameIsAvailable(AstNode currentNode, string name)
{
int pos = currentlyUsedVariableNames.IndexOf(name);
if (pos < 0) {
// name is still available
return;
}
// Naming conflict. Let's rename the existing variable so that the field keeps the name from metadata.
NameVariables nv = new NameVariables();
// Add currently used variable and parameter names
foreach (string nameInUse in currentlyUsedVariableNames)
nv.AddExistingName(nameInUse);
// variables declared in child nodes of this block
foreach (VariableInitializer vi in currentNode.Descendants.OfType<VariableInitializer>())
nv.AddExistingName(vi.Name);
// parameters in child lambdas
foreach (ParameterDeclaration pd in currentNode.Descendants.OfType<ParameterDeclaration>())
nv.AddExistingName(pd.Name);
string newName = nv.GetAlternativeName(name);
currentlyUsedVariableNames[pos] = newName;
// find top-most block
AstNode topMostBlock = currentNode.Ancestors.OfType<BlockStatement>().LastOrDefault() ?? currentNode;
// rename identifiers
foreach (IdentifierExpression ident in topMostBlock.Descendants.OfType<IdentifierExpression>()) {
if (ident.Identifier == name) {
ident.Identifier = newName;
ILVariable v = ident.Annotation<ILVariable>();
if (v != null)
v.Name = newName;
}
}
// rename variable declarations
foreach (VariableInitializer vi in topMostBlock.Descendants.OfType<VariableInitializer>()) {
if (vi.Name == name) {
vi.Name = newName;
ILVariable v = vi.Annotation<ILVariable>();
if (v != null)
v.Name = newName;
}
}
}
}
}

47
ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Converts extension method calls into infix syntax.
/// </summary>
public class IntroduceExtensionMethods : IAstTransform
{
readonly DecompilerContext context;
public IntroduceExtensionMethods(DecompilerContext context)
{
this.context = context;
}
public void Run(AstNode compilationUnit)
{
foreach (InvocationExpression invocation in compilationUnit.Descendants.OfType<InvocationExpression>()) {
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
MethodReference methodReference = invocation.Annotation<MethodReference>();
if (mre != null && mre.Target is TypeReferenceExpression && methodReference != null && invocation.Arguments.Any()) {
MethodDefinition d = methodReference.Resolve();
if (d != null) {
foreach (var ca in d.CustomAttributes) {
if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") {
mre.Target = invocation.Arguments.First().Detach();
if (invocation.Arguments.Any()) {
// HACK: removing type arguments should be done indepently from whether a method is an extension method,
// just by testing whether the arguments can be inferred
mre.TypeArguments.Clear();
}
break;
}
}
}
}
}
}
}
}

280
ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs

@ -0,0 +1,280 @@ @@ -0,0 +1,280 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
/// <summary>
/// Decompiles query expressions.
/// Based on C# 4.0 spec, §7.16.2 Query expression translation
/// </summary>
public class IntroduceQueryExpressions : IAstTransform
{
readonly DecompilerContext context;
public IntroduceQueryExpressions(DecompilerContext context)
{
this.context = context;
}
public void Run(AstNode compilationUnit)
{
if (!context.Settings.QueryExpressions)
return;
DecompileQueries(compilationUnit);
// After all queries were decompiled, detect degenerate queries (queries not property terminated with 'select' or 'group')
// and fix them, either by adding a degenerate select, or by combining them with another query.
foreach (QueryExpression query in compilationUnit.Descendants.OfType<QueryExpression>()) {
QueryFromClause fromClause = (QueryFromClause)query.Clauses.First();
if (IsDegenerateQuery(query)) {
// introduce select for degenerate query
query.Clauses.Add(new QuerySelectClause { Expression = new IdentifierExpression(fromClause.Identifier) });
}
// See if the data source of this query is a degenerate query,
// and combine the queries if possible.
QueryExpression innerQuery = fromClause.Expression as QueryExpression;
while (IsDegenerateQuery(innerQuery)) {
QueryFromClause innerFromClause = (QueryFromClause)innerQuery.Clauses.First();
if (fromClause.Identifier != innerFromClause.Identifier)
break;
// Replace the fromClause with all clauses from the inner query
fromClause.Remove();
QueryClause insertionPos = null;
foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
}
fromClause = innerFromClause;
innerQuery = fromClause.Expression as QueryExpression;
}
}
}
bool IsDegenerateQuery(QueryExpression query)
{
if (query == null)
return false;
var lastClause = query.Clauses.LastOrDefault();
return !(lastClause is QuerySelectClause || lastClause is QueryGroupClause);
}
void DecompileQueries(AstNode node)
{
QueryExpression query = DecompileQuery(node as InvocationExpression);
if (query != null)
node.ReplaceWith(query);
for (AstNode child = (query ?? node).FirstChild; child != null; child = child.NextSibling) {
DecompileQueries(child);
}
}
QueryExpression DecompileQuery(InvocationExpression invocation)
{
if (invocation == null)
return null;
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
if (mre == null)
return null;
switch (mre.MemberName) {
case "Select":
{
if (invocation.Arguments.Count != 1)
return null;
string parameterName;
Expression body;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QuerySelectClause { Expression = body.Detach() });
return query;
}
return null;
}
case "GroupBy":
{
if (invocation.Arguments.Count == 2) {
string parameterName1, parameterName2;
Expression keySelector, elementSelector;
if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector)
&& MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector)
&& parameterName1 == parameterName2)
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() });
return query;
}
} else if (invocation.Arguments.Count == 1) {
string parameterName;
Expression keySelector;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out keySelector)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameterName), Key = keySelector.Detach() });
return query;
}
}
return null;
}
case "SelectMany":
{
if (invocation.Arguments.Count != 2)
return null;
string parameterName;
Expression collectionSelector;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName, out collectionSelector))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(1) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) {
ParameterDeclaration p1 = lambda.Parameters.ElementAt(0);
ParameterDeclaration p2 = lambda.Parameters.ElementAt(1);
if (p1.Name == parameterName) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = p1.Name, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryFromClause { Identifier = p2.Name, Expression = collectionSelector.Detach() });
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() });
return query;
}
}
return null;
}
case "Where":
{
if (invocation.Arguments.Count != 1)
return null;
string parameterName;
Expression body;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() });
return query;
}
return null;
}
case "OrderBy":
case "OrderByDescending":
case "ThenBy":
case "ThenByDescending":
{
if (invocation.Arguments.Count != 1)
return null;
string parameterName;
Expression orderExpression;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out orderExpression)) {
if (ValidateThenByChain(invocation, parameterName)) {
QueryOrderClause orderClause = new QueryOrderClause();
InvocationExpression tmp = invocation;
while (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") {
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "ThenBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
tmp = (InvocationExpression)mre.Target;
mre = (MemberReferenceExpression)tmp.Target;
MatchSimpleLambda(tmp.Arguments.Single(), out parameterName, out orderExpression);
}
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "OrderBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(orderClause);
return query;
}
}
return null;
}
case "Join":
case "GroupJoin":
{
if (invocation.Arguments.Count != 4)
return null;
Expression source1 = mre.Target;
Expression source2 = invocation.Arguments.ElementAt(0);
string elementName1, elementName2;
Expression key1, key2;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(1), out elementName1, out key1))
return null;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(2), out elementName2, out key2))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) {
ParameterDeclaration p1 = lambda.Parameters.ElementAt(0);
ParameterDeclaration p2 = lambda.Parameters.ElementAt(1);
if (p1.Name == elementName1 && (p2.Name == elementName2 || mre.MemberName == "GroupJoin")) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = elementName1, Expression = source1.Detach() });
QueryJoinClause joinClause = new QueryJoinClause();
joinClause.JoinIdentifier = elementName2; // join elementName2
joinClause.InExpression = source2.Detach(); // in source2
joinClause.OnExpression = key1.Detach(); // on key1
joinClause.EqualsExpression = key2.Detach(); // equals key2
if (mre.MemberName == "GroupJoin") {
joinClause.IntoIdentifier = p2.Name; // into p2.Name
}
query.Clauses.Add(joinClause);
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() });
return query;
}
}
return null;
}
default:
return null;
}
}
/// <summary>
/// Ensure that all ThenBy's are correct, and that the list of ThenBy's is terminated by an 'OrderBy' invocation.
/// </summary>
bool ValidateThenByChain(InvocationExpression invocation, string expectedParameterName)
{
if (invocation == null || invocation.Arguments.Count != 1)
return false;
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
if (mre == null)
return false;
string parameterName;
Expression body;
if (!MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body))
return false;
if (parameterName != expectedParameterName)
return false;
if (mre.MemberName == "OrderBy" || mre.MemberName == "OrderByDescending")
return true;
else if (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending")
return ValidateThenByChain(mre.Target as InvocationExpression, expectedParameterName);
else
return false;
}
/// <summary>Matches simple lambdas of the form "a => b"</summary>
bool MatchSimpleLambda(Expression expr, out string parameterName, out Expression body)
{
LambdaExpression lambda = expr as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 1 && lambda.Body is Expression) {
ParameterDeclaration p = lambda.Parameters.Single();
if (p.ParameterModifier == ParameterModifier.None) {
parameterName = p.Name;
body = (Expression)lambda.Body;
return true;
}
}
parameterName = null;
body = null;
return false;
}
}
}

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

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

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

@ -126,12 +126,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -126,12 +126,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
));
#region using
static Expression InvokeDispose(Expression identifier)
{
return new Choice {
identifier.Invoke("Dispose"),
identifier.Clone().CastTo(new TypePattern(typeof(IDisposable))).Invoke("Dispose")
};
}
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body"),
FinallyBlock = new BlockStatement {
new Choice {
{ "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose"))
new ExpressionStatement(InvokeDispose(new NamedNode("ident", new IdentifierExpression())))
},
{ "referenceType",
new IfElseStatement {
@ -141,7 +149,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -141,7 +149,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
new ExpressionStatement(InvokeDispose(new Backreference("ident")))
}
}
}
@ -299,6 +307,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -299,6 +307,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
};
if (foreachStatement.InExpression is BaseReferenceExpression)
foreachStatement.InExpression = new ThisReferenceExpression();
node.ReplaceWith(foreachStatement);
foreach (Statement stmt in m.Get<Statement>("variablesOutsideLoop")) {
((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(null, stmt.Detach());
@ -578,6 +588,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -578,6 +588,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,
ReturnType = new AnyNode(),
PrivateImplementationType = new OptionalNode(new AnyNode()),
Getter = new Accessor {
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,

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

@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
public interface IAstTransform
{
void Run(AstNode node);
void Run(AstNode compilationUnit);
}
public static class TransformationPipeline
@ -25,7 +25,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -25,7 +25,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new AddCheckedBlocks(),
new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
new IntroduceUsingDeclarations(context)
new IntroduceUsingDeclarations(context),
new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
new CombineQueryExpressions(context),
};
}

2
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

@ -167,6 +167,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -167,6 +167,8 @@ namespace ICSharpCode.Decompiler.Ast
{
if (tr1 == tr2)
return true;
if (tr1 == null || tr2 == null)
return false;
if (tr1.Name == tr2.Name && tr1.FullName == tr2.FullName)
return true;

97
ICSharpCode.Decompiler/CecilExtensions.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@ -58,7 +59,7 @@ namespace ICSharpCode.Decompiler @@ -58,7 +59,7 @@ namespace ICSharpCode.Decompiler
throw new NotSupportedException ();
}
public static int GetPopDelta(this Instruction instruction, MethodDefinition current, int currentStackSize)
public static int? GetPopDelta(this Instruction instruction)
{
OpCode code = instruction.OpCode;
switch (code.StackBehaviourPop) {
@ -88,18 +89,18 @@ namespace ICSharpCode.Decompiler @@ -88,18 +89,18 @@ namespace ICSharpCode.Decompiler
return 3;
case StackBehaviour.PopAll:
return currentStackSize;
return null;
case StackBehaviour.Varpop:
if (code == OpCodes.Ret)
return IsVoid (current.ReturnType) ? 0 : 1;
return null;
if (code.FlowControl != FlowControl.Call)
break;
IMethodSignature method = (IMethodSignature) instruction.Operand;
int count = method.HasParameters ? method.Parameters.Count : 0;
if (method.HasThis && code != OpCodes.Newobj)
if (code == OpCodes.Calli || (method.HasThis && code != OpCodes.Newobj))
++count;
return count;
@ -110,7 +111,9 @@ namespace ICSharpCode.Decompiler @@ -110,7 +111,9 @@ namespace ICSharpCode.Decompiler
public static bool IsVoid(this TypeReference type)
{
return type.FullName == "System.Void" && !(type is TypeSpecification);
while (type is OptionalModifierType || type is RequiredModifierType)
type = ((TypeSpecification)type).ElementType;
return type.MetadataType == MetadataType.Void;
}
public static bool IsValueTypeOrVoid(this TypeReference type)
@ -202,5 +205,89 @@ namespace ICSharpCode.Decompiler @@ -202,5 +205,89 @@ namespace ICSharpCode.Decompiler
return true;
return IsCompilerGeneratedOrIsInCompilerGeneratedClass(member.DeclaringType);
}
public static bool IsAnonymousType(this TypeReference type)
{
if (type == null)
return false;
if (string.IsNullOrEmpty(type.Namespace) && type.Name.StartsWith("<>", StringComparison.Ordinal) && type.Name.Contains("AnonymousType")) {
TypeDefinition td = type.Resolve();
return td != null && td.IsCompilerGenerated();
}
return false;
}
public static bool ContainsAnonymousType(this TypeReference type)
{
GenericInstanceType git = type as GenericInstanceType;
if (git != null) {
if (IsAnonymousType(git))
return true;
for (int i = 0; i < git.GenericArguments.Count; i++) {
if (git.GenericArguments[i].ContainsAnonymousType())
return true;
}
return false;
}
TypeSpecification typeSpec = type as TypeSpecification;
if (typeSpec != null)
return typeSpec.ElementType.ContainsAnonymousType();
else
return false;
}
public static string GetDefaultMemberName(this TypeDefinition type)
{
CustomAttribute attr;
return type.GetDefaultMemberName(out attr);
}
public static string GetDefaultMemberName(this TypeDefinition type, out CustomAttribute defaultMemberAttribute)
{
if (type.HasCustomAttributes)
foreach (CustomAttribute ca in type.CustomAttributes)
if (ca.Constructor.DeclaringType.Name == "DefaultMemberAttribute" && ca.Constructor.DeclaringType.Namespace == "System.Reflection"
&& ca.Constructor.FullName == @"System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") {
defaultMemberAttribute = ca;
return ca.ConstructorArguments[0].Value as string;
}
defaultMemberAttribute = null;
return null;
}
public static bool IsIndexer(this PropertyDefinition property)
{
CustomAttribute attr;
return property.IsIndexer(out attr);
}
public static bool IsIndexer(this PropertyDefinition property, out CustomAttribute defaultMemberAttribute)
{
defaultMemberAttribute = null;
if (property.HasParameters) {
var accessor = property.GetMethod ?? property.SetMethod;
PropertyDefinition basePropDef = property;
if (accessor.HasOverrides) {
// if the property is explicitly implementing an interface, look up the property in the interface:
MethodDefinition baseAccessor = accessor.Overrides.First().Resolve();
if (baseAccessor != null) {
foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) {
if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) {
basePropDef = baseProp;
break;
}
}
} else
return false;
}
CustomAttribute attr;
var defaultMemberName = basePropDef.DeclaringType.GetDefaultMemberName(out attr);
if (defaultMemberName == basePropDef.Name) {
defaultMemberAttribute = attr;
return true;
}
}
return false;
}
}
}

31
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -140,6 +140,30 @@ namespace ICSharpCode.Decompiler @@ -140,6 +140,30 @@ namespace ICSharpCode.Decompiler
}
}
bool queryExpressions = true;
public bool QueryExpressions {
get { return queryExpressions; }
set {
if (queryExpressions != value) {
queryExpressions = value;
OnPropertyChanged("QueryExpressions");
}
}
}
bool fullyQualifyAmbiguousTypeNames = true;
public bool FullyQualifyAmbiguousTypeNames {
get { return fullyQualifyAmbiguousTypeNames; }
set {
if (fullyQualifyAmbiguousTypeNames != value) {
fullyQualifyAmbiguousTypeNames = value;
OnPropertyChanged("FullyQualifyAmbiguousTypeNames");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
@ -148,5 +172,12 @@ namespace ICSharpCode.Decompiler @@ -148,5 +172,12 @@ namespace ICSharpCode.Decompiler
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public DecompilerSettings Clone()
{
DecompilerSettings settings = (DecompilerSettings)MemberwiseClone();
settings.PropertyChanged = null;
return settings;
}
}
}

8
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -39,8 +39,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -39,8 +39,6 @@ namespace ICSharpCode.Decompiler.Disassembler
if (exceptionHandler.FilterStart != null) {
writer.Write(' ');
WriteOffsetReference(writer, exceptionHandler.FilterStart);
writer.Write('-');
WriteOffsetReference(writer, exceptionHandler.FilterEnd);
writer.Write(" handler ");
}
if (exceptionHandler.CatchType != null) {
@ -88,8 +86,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -88,8 +86,10 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.Write("instance ");
method.ReturnType.WriteTo(writer);
writer.Write(' ');
method.DeclaringType.WriteTo(writer, true);
writer.Write("::");
if (method.DeclaringType != null) {
method.DeclaringType.WriteTo(writer, true);
writer.Write("::");
}
writer.WriteReference(method.Name, method);
writer.Write("(");
var parameters = method.Parameters;

2
ICSharpCode.Decompiler/Disassembler/ILStructure.cs

@ -91,7 +91,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -91,7 +91,7 @@ namespace ICSharpCode.Decompiler.Disassembler
foreach (ExceptionHandler eh in body.ExceptionHandlers) {
AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh));
if (eh.HandlerType == ExceptionHandlerType.Filter)
AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.FilterEnd.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));
}
// Very simple loop detection: look for backward branches

2
ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs

@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
continue;
}
int popCount = inst.GetPopDelta(method, stackSize);
int popCount = inst.GetPopDelta() ?? stackSize;
stackSize -= popCount;
if (stackSize < 0)
throw new InvalidProgramException("IL stack underflow");

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -59,10 +59,13 @@ @@ -59,10 +59,13 @@
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\AddCheckedBlocks.cs" />
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DeclareVariables.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\IntroduceExtensionMethods.cs" />
<Compile Include="Ast\Transforms\IntroduceQueryExpressions.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="Ast\Transforms\IntroduceUsingDeclarations.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />

4
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -247,8 +247,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -247,8 +247,8 @@ namespace ICSharpCode.Decompiler.ILAst
EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
Code = code,
Operand = operand,
PopCount = inst.GetPopCount(),
PushCount = inst.GetPushCount()
PopCount = inst.GetPopDelta(),
PushCount = inst.GetPushDelta()
};
if (prefixes != null) {
instrToByteCode[prefixes[0]] = byteCode;

3
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -172,7 +172,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -172,7 +172,8 @@ namespace ICSharpCode.Decompiler.ILAst
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
// TODO: Move before loops
CachedDelegateInitialization(block, ref i);
CachedDelegateInitializationWithField(block, ref i);
CachedDelegateInitializationWithLocal(block, ref i);
}
}

71
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -343,77 +343,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -343,77 +343,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
public static int? GetPopCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return null;
case StackBehaviour.Varpop:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret: return null;
case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
}
}
public static int GetPushCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == "System.Void") {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody)
{
switch (code) {

68
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)
void CachedDelegateInitializationWithField(ILBlock block, ref int i)
{
// if (logicnot(ldsfld(field))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
@ -174,13 +174,75 @@ namespace ICSharpCode.Decompiler.ILAst @@ -174,13 +174,75 @@ namespace ICSharpCode.Decompiler.ILAst
if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field) {
parent.Arguments[j] = newObj;
block.Body.RemoveAt(i);
i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: true);
i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false);
return;
}
}
}
}
}
void CachedDelegateInitializationWithLocal(ILBlock block, ref int i)
{
// if (logicnot(ldloc(v))) {
// stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method)))
// } else {
// }
// ...(..., ldloc(v), ...)
ILCondition c = block.Body[i] as ILCondition;
if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
return;
if (!c.Condition.Match(ILCode.LogicNot))
return;
ILExpression condition = c.Condition.Arguments.Single() as ILExpression;
if (condition == null || condition.Code != ILCode.Ldloc)
return;
ILVariable v = (ILVariable)condition.Operand;
ILExpression stloc = c.TrueBlock.Body[0] as ILExpression;
if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v))
return;
ILExpression newObj = stloc.Arguments[0];
if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
return;
if (newObj.Arguments[0].Code != ILCode.Ldloc)
return;
if (newObj.Arguments[1].Code != ILCode.Ldftn)
return;
MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly
if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
return;
ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);
if (followingNode != null && followingNode.GetSelfAndChildrenRecursive<ILExpression>().Count(
e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v) == 1)
{
ILInlining inlining = new ILInlining(method);
if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0))
return;
// Find the store instruction that initializes the local to null:
foreach (ILBlock storeBlock in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int j = 0; j < storeBlock.Body.Count; j++) {
ILVariable storedVar;
ILExpression storedExpr;
if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull)) {
// Remove the instruction
storeBlock.Body.RemoveAt(j);
if (storeBlock == block && j < i)
i--;
break;
}
}
}
block.Body[i] = stloc; // remove the 'if (v==null)'
inlining = new ILInlining(method);
inlining.InlineIfPossible(block.Body, ref i);
}
}
#endregion
#region MakeAssignmentExpression
@ -646,7 +708,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -646,7 +708,7 @@ namespace ICSharpCode.Decompiler.ILAst
// that can be eliminated.
if (arrayLoadingExpr.Code == ILCode.Stloc) {
ILInlining inlining = new ILInlining(method);
if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 &&
if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 &&
inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0)
{
arrayLoadingExpr = arrayLoadingExpr.Arguments[0];

17
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -341,8 +341,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -341,8 +341,8 @@ namespace ICSharpCode.Decompiler.ILAst
{
MethodReference addMethod = (MethodReference)expr.Operand;
if (forceInferChildren) {
for (int i = 1; i < addMethod.Parameters.Count; i++) {
InferTypeForExpression(expr.Arguments[i-1], SubstituteTypeArgs(addMethod.Parameters[i].ParameterType, addMethod));
for (int i = 0; i < addMethod.Parameters.Count; i++) {
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(addMethod.Parameters[i].ParameterType, addMethod));
}
}
return addMethod.DeclaringType;
@ -453,6 +453,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -453,6 +453,11 @@ namespace ICSharpCode.Decompiler.ILAst
}
return elementType;
}
case ILCode.Mkrefany:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], (TypeReference)expr.Operand);
}
return typeSystem.TypedReference;
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement
@ -648,9 +653,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -648,9 +653,15 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Conv_R_Un:
return (expectedType != null && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double;
case ILCode.Castclass:
case ILCode.Isinst:
case ILCode.Unbox_Any:
return (TypeReference)expr.Operand;
case ILCode.Isinst:
{
// isinst performs the equivalent of a cast only for reference types;
// value types still need to be unboxed after an isinst instruction
TypeReference tr = (TypeReference)expr.Operand;
return tr.IsValueType ? typeSystem.Object : tr;
}
case ILCode.Box:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand);

37
ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
public class CallOverloadedMethod
{
public void OverloadedMethod(object a)
{
}
public void OverloadedMethod(int? a)
{
}
public void OverloadedMethod(string a)
{
}
public void Call()
{
this.OverloadedMethod("(string)");
this.OverloadedMethod((object)"(object)");
this.OverloadedMethod(5);
this.OverloadedMethod((object)5);
this.OverloadedMethod(5L);
this.OverloadedMethod((object)null);
this.OverloadedMethod((string)null);
this.OverloadedMethod((int?)null);
}
public void CallMethodUsingInterface(List<int> list)
{
((ICollection<int>)list).Clear();
}
}

6
ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs

@ -34,10 +34,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -34,10 +34,12 @@ namespace ICSharpCode.Decompiler.Tests
/// <returns>The decompilation result of compiled source code.</returns>
static string RoundtripCode(string code)
{
DecompilerSettings settings = new DecompilerSettings();
settings.FullyQualifyAmbiguousTypeNames = false;
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext());
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings });
decompiler.AddAssembly(assembly);
decompiler.Transform(new Helpers.RemoveCompilerAttribute());
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
return output.ToString();

98
ICSharpCode.Decompiler/Tests/DelegateConstruction.cs

@ -3,43 +3,82 @@ @@ -3,43 +3,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
public static class DelegateConstruction
{
class InstanceTests
{
public Action CaptureOfThis()
{
return delegate {
CaptureOfThis();
};
}
public Action CaptureOfThisAndParameter(int a)
{
return delegate {
CaptureOfThisAndParameter(a);
};
}
public Action CaptureOfThisAndParameterInForEach(int a)
{
foreach (var item in Enumerable.Empty<int>()) {
return delegate {
CaptureOfThisAndParameter(item + a);
};
}
return null;
}
public Action CaptureOfThisAndParameterInForEachWithItemCopy(int a)
{
foreach (var item in Enumerable.Empty<int>()) {
int copyOfItem = item;
return delegate {
CaptureOfThisAndParameter(item + a + copyOfItem);
};
}
return null;
}
}
public static void Test(this string a)
{
}
public static Action<string> ExtensionMethodUnbound()
{
return new Action<string>(DelegateConstruction.Test);
}
public static Action ExtensionMethodBound()
{
return new Action("abc".Test);
}
public static Action ExtensionMethodBoundOnNull()
{
return new Action(((string)null).Test);
}
public static object StaticMethod()
{
return new Func<Action>(DelegateConstruction.ExtensionMethodBound);
}
public static object InstanceMethod()
{
return new Func<string>("hello".ToUpper);
}
public static object InstanceMethodOnNull()
{
return new Func<string>(((string)null).ToUpper);
}
public static List<Action<int>> AnonymousMethodStoreWithinLoop()
{
List<Action<int>> list = new List<Action<int>>();
@ -54,7 +93,7 @@ public static class DelegateConstruction @@ -54,7 +93,7 @@ public static class DelegateConstruction
}
return list;
}
public static List<Action<int>> AnonymousMethodStoreOutsideLoop()
{
List<Action<int>> list = new List<Action<int>>();
@ -69,7 +108,7 @@ public static class DelegateConstruction @@ -69,7 +108,7 @@ public static class DelegateConstruction
}
return list;
}
public static Action StaticAnonymousMethodNoClosure()
{
return delegate
@ -77,4 +116,45 @@ public static class DelegateConstruction @@ -77,4 +116,45 @@ public static class DelegateConstruction
Console.WriteLine();
};
}
public static void NameConflict()
{
// i is captured variable,
// j is parameter in anonymous method
// k is local in anonymous method,
// l is local in main method
// Ensure that the decompiler doesn't introduce name conflicts
List<Action<int>> list = new List<Action<int>>();
for (int l = 0; l < 10; l++) {
int i;
for (i = 0; i < 10; i++) {
list.Add(
delegate (int j) {
for (int k = 0; k < i; k += j) {
Console.WriteLine();
}
});
}
}
}
public static void NameConflict2(int j)
{
List<Action<int>> list = new List<Action<int>>();
for (int k = 0; k < 10; k++) {
list.Add(
delegate(int i) {
Console.WriteLine(i);
});
}
}
public static Action<int> NameConflict3(int i)
{
return delegate(int j) {
for (int k = 0; k < j; k++) {
Console.WriteLine(k);
}
};
}
}

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

@ -52,8 +52,10 @@ @@ -52,8 +52,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="IncrementDecrement.cs" />
<Compile Include="QueryExpressions.cs" />
<Compile Include="Switch.cs" />
<Compile Include="UnsafeCode.cs" />
<Compile Include="Types\S_TypeDeclarations.cs" />

22
ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

@ -5,11 +5,20 @@ using System; @@ -5,11 +5,20 @@ using System;
public class IncrementDecrement
{
[Flags]
private enum MyEnum
{
None = 0,
One = 1,
Two = 2,
Four = 4
}
public class MutableClass
{
public int Field;
public int Property
public int Property
{
get;
set;
@ -27,11 +36,12 @@ public class IncrementDecrement @@ -27,11 +36,12 @@ public class IncrementDecrement
}
}
private IncrementDecrement.MyEnum enumField;
public static int StaticField;
public static int StaticProperty
{
get;
{
get;
set;
}
@ -155,6 +165,12 @@ public class IncrementDecrement @@ -155,6 +165,12 @@ public class IncrementDecrement
return *ptr /= 1.5;
}
public void CompoundAssignEnum()
{
this.enumField |= IncrementDecrement.MyEnum.Two;
this.enumField &= ~IncrementDecrement.MyEnum.Four;
}
public int PostIncrementInAddition(int i, int j)
{
return i++ + j;

25
ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -6,6 +6,18 @@ using System.Collections.Generic; @@ -6,6 +6,18 @@ using System.Collections.Generic;
public class InitializerTests
{
enum MyEnum
{
a,
b
}
enum MyEnum2
{
c,
d
}
// Helper methods used to ensure initializers used within expressions work correctly
static void X(object a, object b)
{
@ -100,6 +112,11 @@ public class InitializerTests @@ -100,6 +112,11 @@ public class InitializerTests
{
X(Y(), new string[] { "", null, "Hello", "World" });
}
public static void ArrayEnum()
{
X(Y(), new InitializerTests.MyEnum[] { InitializerTests.MyEnum.a, InitializerTests.MyEnum.b, InitializerTests.MyEnum.a, InitializerTests.MyEnum.b });
}
#endregion
public static void CollectionInitializerList()
@ -115,4 +132,12 @@ public class InitializerTests @@ -115,4 +132,12 @@ public class InitializerTests
{ "Third" , 3 }
});
}
public static void CollectionInitializerDictionaryWithEnumTypes()
{
X(Y(), new Dictionary<InitializerTests.MyEnum, InitializerTests.MyEnum2> {
{ InitializerTests.MyEnum.a, InitializerTests.MyEnum2.c },
{ InitializerTests.MyEnum.b, InitializerTests.MyEnum2.d }
});
}
}

149
ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -0,0 +1,149 @@ @@ -0,0 +1,149 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
public class QueryExpressions
{
public class Customer
{
public int CustomerID;
public IEnumerable<QueryExpressions.Order> Orders;
public string Name;
public string Country;
public string City;
}
public class Order
{
public int OrderID;
public DateTime OrderDate;
public Customer Customer;
public int CustomerID;
public decimal Total;
public IEnumerable<QueryExpressions.OrderDetail> Details;
}
public class OrderDetail
{
public decimal UnitPrice;
public int Quantity;
}
public IEnumerable<QueryExpressions.Customer> customers;
public IEnumerable<QueryExpressions.Order> orders;
public object MultipleWhere()
{
return
from c in this.customers
where c.Orders.Count() > 10
where c.Country == "DE"
select c;
}
public object SelectManyFollowedBySelect()
{
return
from c in this.customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total };
}
public object SelectManyFollowedByOrderBy()
{
return
from c in this.customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total };
}
public object MultipleSelectManyFollowedBySelect()
{
return
from c in this.customers
from o in c.Orders
from d in o.Details
select new { c.Name, o.OrderID, d.Quantity };
}
public object MultipleSelectManyFollowedByLet()
{
return
from c in this.customers
from o in c.Orders
from d in o.Details
let x = d.Quantity * d.UnitPrice
select new { c.Name, o.OrderID, x };
}
public object FromLetWhereSelect()
{
return
from o in this.orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t };
}
public object MultipleLet()
{
return
from a in this.customers
let b = a.Country
let c = a.Name
select b + c;
}
public object Join()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total };
}
public object JoinInto()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
where n >= 10
select new { c.Name, OrderCount = n };
}
public object OrderBy()
{
return
from o in orders
orderby o.Customer.Name, o.Total descending
select o;
}
public object GroupBy()
{
return
from c in customers
group c.Name by c.Country;
}
public object ExplicitType()
{
return
from Customer c in customers
where c.City == "London"
select c;
}
public object QueryContinuation()
{
return
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() };
}
}

10
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -94,13 +94,19 @@ namespace ICSharpCode.Decompiler.Tests @@ -94,13 +94,19 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\YieldReturn.cs");
}
[Test, Ignore("Formatting differences")]
public void QueryExpressions()
{
TestFile(@"..\..\Tests\QueryExpressions.cs");
}
static void TestFile(string fileName)
{
string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder(new DecompilerContext());
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
decompiler.Transform(new Helpers.RemoveCompilerAttribute());
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));
StringWriter diff = new StringWriter();

15
ICSharpCode.Decompiler/Tests/ValueTypes.cs

@ -111,4 +111,19 @@ public static class ValueTypes @@ -111,4 +111,19 @@ public static class ValueTypes
{
ValueTypes.MakeArray()[Environment.TickCount]++;
}
public static bool Is(object obj)
{
return obj is ValueTypes.S;
}
public static bool IsNullable(object obj)
{
return obj is ValueTypes.S?;
}
public static ValueTypes.S? As(object obj)
{
return obj as ValueTypes.S?;
}
}

70
ILSpy/CSharpLanguage.cs

@ -51,8 +51,9 @@ namespace ICSharpCode.ILSpy @@ -51,8 +51,9 @@ namespace ICSharpCode.ILSpy
#if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{
DecompilerContext context = new DecompilerContext(ModuleDefinition.CreateModule("dummy", ModuleKind.Dll));
string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline(new DecompilerContext()).Select(v => v.GetType()).Distinct()) {
foreach (Type _transformType in TransformationPipeline.CreatePipeline(context).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda
yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v),
@ -83,7 +84,7 @@ namespace ICSharpCode.ILSpy @@ -83,7 +84,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, method.DeclaringType);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
@ -92,7 +93,7 @@ namespace ICSharpCode.ILSpy @@ -92,7 +93,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, property.DeclaringType);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true);
codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
@ -101,7 +102,7 @@ namespace ICSharpCode.ILSpy @@ -101,7 +102,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, field.DeclaringType);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
@ -110,7 +111,7 @@ namespace ICSharpCode.ILSpy @@ -110,7 +111,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, ev.DeclaringType);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true);
codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
@ -118,7 +119,7 @@ namespace ICSharpCode.ILSpy @@ -118,7 +119,7 @@ namespace ICSharpCode.ILSpy
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
@ -133,10 +134,13 @@ namespace ICSharpCode.ILSpy @@ -133,10 +134,13 @@ namespace ICSharpCode.ILSpy
WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule);
} else {
base.DecompileAssembly(assembly, fileName, output, options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: null);
codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: !options.FullDecompilation);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
// don't automatically load additional assemblies when an assembly node is selected in the tree view
using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: !options.FullDecompilation);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
}
}
}
@ -296,7 +300,7 @@ namespace ICSharpCode.ILSpy @@ -296,7 +300,7 @@ namespace ICSharpCode.ILSpy
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
delegate (IGrouping<string, TypeDefinition> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, null);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
foreach (TypeDefinition type in file) {
codeDomBuilder.AddType(type);
}
@ -383,13 +387,20 @@ namespace ICSharpCode.ILSpy @@ -383,13 +387,20 @@ namespace ICSharpCode.ILSpy
}
#endregion
AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType)
AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false)
{
if (currentModule == null)
currentModule = currentType.Module;
DecompilerSettings settings = options.DecompilerSettings;
if (isSingleMember) {
settings = settings.Clone();
settings.UsingDeclarations = false;
}
return new AstBuilder(
new DecompilerContext {
new DecompilerContext(currentModule) {
CancellationToken = options.CancellationToken,
CurrentType = currentType,
Settings = options.DecompilerSettings
Settings = settings
});
}
@ -415,6 +426,37 @@ namespace ICSharpCode.ILSpy @@ -415,6 +426,37 @@ namespace ICSharpCode.ILSpy
astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null);
return w.ToString();
}
public override string FormatPropertyName(PropertyDefinition property, bool? isIndexer)
{
if (property == null)
throw new ArgumentNullException("property");
if (!isIndexer.HasValue) {
isIndexer = property.IsIndexer();
}
if (isIndexer.Value) {
var buffer = new System.Text.StringBuilder();
var accessor = property.GetMethod ?? property.SetMethod;
if (accessor.HasOverrides) {
var declaringType = accessor.Overrides.First().DeclaringType;
buffer.Append(TypeToString(declaringType, includeNamespace: true));
buffer.Append(@".");
}
buffer.Append(@"this[");
bool addSeparator = false;
foreach (var p in property.Parameters) {
if (addSeparator)
buffer.Append(@", ");
else
addSeparator = true;
buffer.Append(TypeToString(p.ParameterType, includeNamespace: true));
}
buffer.Append(@"]");
return buffer.ToString();
} else
return property.Name;
}
public override bool ShowMember(MemberReference member)
{

2
ILSpy/ILAstLanguage.cs

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

31
ILSpy/ILSpy.csproj

@ -108,6 +108,9 @@ @@ -108,6 +108,9 @@
<Compile Include="ILAstLanguage.cs" />
<Compile Include="ILLanguage.cs" />
<Compile Include="ILSpySettings.cs" />
<Compile Include="Images\AccessOverlayIcon.cs" />
<Compile Include="Images\MemberIcon.cs" />
<Compile Include="Images\TypeIcon.cs" />
<Compile Include="ISmartTextOutput.cs" />
<Compile Include="Language.cs" />
<Compile Include="Images\Images.cs" />
@ -212,25 +215,10 @@ @@ -212,25 +215,10 @@
<Resource Include="Images\Enum.png" />
<Resource Include="Images\Field.png" />
<Resource Include="Images\Interface.png" />
<Resource Include="Images\InternalClass.png" />
<Resource Include="Images\InternalDelegate.png" />
<Resource Include="Images\InternalEnum.png" />
<Resource Include="Images\InternalInterface.png" />
<Resource Include="Images\InternalStruct.png" />
<Resource Include="Images\Literal.png" />
<Resource Include="Images\Method.png" />
<Resource Include="Images\NameSpace.png" />
<Resource Include="Images\Open.png" />
<Resource Include="Images\PrivateClass.png" />
<Resource Include="Images\PrivateDelegate.png" />
<Resource Include="Images\PrivateEnum.png" />
<Resource Include="Images\PrivateInterface.png" />
<Resource Include="Images\PrivateStruct.png" />
<Resource Include="Images\ProtectedClass.png" />
<Resource Include="Images\ProtectedDelegate.png" />
<Resource Include="Images\ProtectedEnum.png" />
<Resource Include="Images\ProtectedInterface.png" />
<Resource Include="Images\ProtectedStruct.png" />
<Resource Include="Images\Assembly.png" />
<Resource Include="Images\Struct.png" />
<Resource Include="Images\ReferenceFolder.Closed.png" />
@ -245,10 +233,23 @@ @@ -245,10 +233,23 @@
<Resource Include="Images\SubTypes.png" />
<Resource Include="Images\SuperTypes.png" />
<Resource Include="Images\Resource.png" />
<Resource Include="Images\Folder.Closed.png" />
<Resource Include="Images\Folder.Open.png" />
<Resource Include="Images\ResourceImage.png" />
<Resource Include="Images\ResourceResourcesFile.png" />
<Resource Include="Images\Back.png" />
<Resource Include="Images\Forward.png" />
<Resource Include="Images\PrivateInternal.png" />
<Resource Include="Images\Refresh.png" />
<Resource Include="Images\Constructor.png" />
<Resource Include="Images\EnumValue.png" />
<Resource Include="Images\FieldReadOnly.png" />
<Resource Include="Images\OverlayInternal.png" />
<Resource Include="Images\OverlayPrivate.png" />
<Resource Include="Images\OverlayProtected.png" />
<Resource Include="Images\OverlayProtectedInternal.png" />
<Resource Include="Images\OverlayStatic.png" />
<Resource Include="Images\VirtualMethod.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Debugger\ILSpy.Debugger\ILSpy.Debugger.csproj">

34
ILSpy/Images/AccessOverlayIcon.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// 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)
// 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;
namespace ICSharpCode.ILSpy
{
internal enum AccessOverlayIcon
{
Public,
Protected,
Internal,
ProtectedInternal,
Private,
}
}

BIN
ILSpy/Images/Class.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 470 B

BIN
ILSpy/Images/Constructor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

BIN
ILSpy/Images/Delegate.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 908 B

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ILSpy/Images/Enum.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ILSpy/Images/EnumValue.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

BIN
ILSpy/Images/Event.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

After

Width:  |  Height:  |  Size: 494 B

BIN
ILSpy/Images/ExtensionMethod.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 567 B

BIN
ILSpy/Images/Field.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 411 B

BIN
ILSpy/Images/FieldReadOnly.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

BIN
ILSpy/Images/Folder.Closed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

BIN
ILSpy/Images/Folder.Open.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

285
ILSpy/Images/Images.cs

@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
using System;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;
using System.Collections.Generic;
namespace ICSharpCode.ILSpy
{
@ -14,61 +17,64 @@ namespace ICSharpCode.ILSpy @@ -14,61 +17,64 @@ namespace ICSharpCode.ILSpy
image.Freeze();
return image;
}
public static readonly BitmapImage ViewCode = LoadBitmap("ViewCode");
public static readonly BitmapImage Save = LoadBitmap("SaveFile");
public static readonly BitmapImage OK = LoadBitmap("OK");
public static readonly BitmapImage Delete = LoadBitmap("Delete");
public static readonly BitmapImage Search = LoadBitmap("Search");
public static readonly BitmapImage Assembly = LoadBitmap("Assembly");
public static readonly BitmapImage AssemblyWarning = LoadBitmap("AssemblyWarning");
public static readonly BitmapImage AssemblyLoading = LoadBitmap("FindAssembly");
public static readonly BitmapImage Library = LoadBitmap("Library");
public static readonly BitmapImage Namespace = LoadBitmap("NameSpace");
public static readonly BitmapImage ReferenceFolderOpen = LoadBitmap("ReferenceFolder.Open");
public static readonly BitmapImage ReferenceFolderClosed = LoadBitmap("ReferenceFolder.Closed");
public static readonly BitmapImage SubTypes = LoadBitmap("SubTypes");
public static readonly BitmapImage SuperTypes = LoadBitmap("SuperTypes");
public static readonly BitmapImage FolderOpen = LoadBitmap("Folder.Open");
public static readonly BitmapImage FolderClosed = LoadBitmap("Folder.Closed");
public static readonly BitmapImage Resource = LoadBitmap("Resource");
public static readonly BitmapImage ResourceImage = LoadBitmap("ResourceImage");
public static readonly BitmapImage ResourceResourcesFile = LoadBitmap("ResourceResourcesFile");
public static readonly BitmapImage Class = LoadBitmap("Class");
public static readonly BitmapImage Struct = LoadBitmap("Struct");
public static readonly BitmapImage Interface = LoadBitmap("Interface");
public static readonly BitmapImage Delegate = LoadBitmap("Delegate");
public static readonly BitmapImage Enum = LoadBitmap("Enum");
public static readonly BitmapImage Interface = LoadBitmap("Interface");
public static readonly BitmapImage Struct = LoadBitmap("Struct");
public static readonly BitmapImage Field = LoadBitmap("Field");
public static readonly BitmapImage Method = LoadBitmap("Method");
public static readonly BitmapImage ExtensionMethod = LoadBitmap("ExtensionMethod");
public static readonly BitmapImage Literal = LoadBitmap("Literal");
public static readonly BitmapImage Property = LoadBitmap("Property");
public static readonly BitmapImage Event = LoadBitmap("Event");
public static readonly BitmapImage Indexer = LoadBitmap("Indexer");
public static readonly BitmapImage Operator = LoadBitmap("Operator");
public static readonly BitmapImage InternalClass = LoadBitmap("InternalClass");
public static readonly BitmapImage InternalDelegate = LoadBitmap("InternalDelegate");
public static readonly BitmapImage InternalEnum = LoadBitmap("InternalEnum");
public static readonly BitmapImage InternalInterface = LoadBitmap("InternalInterface");
public static readonly BitmapImage InternalStruct = LoadBitmap("InternalStruct");
public static readonly BitmapImage PrivateClass = LoadBitmap("PrivateClass");
public static readonly BitmapImage PrivateDelegate = LoadBitmap("PrivateDelegate");
public static readonly BitmapImage PrivateEnum = LoadBitmap("PrivateEnum");
public static readonly BitmapImage PrivateInterface = LoadBitmap("PrivateInterface");
public static readonly BitmapImage PrivateStruct = LoadBitmap("PrivateStruct");
public static readonly BitmapImage ProtectedClass = LoadBitmap("ProtectedClass");
public static readonly BitmapImage ProtectedDelegate = LoadBitmap("ProtectedDelegate");
public static readonly BitmapImage ProtectedEnum = LoadBitmap("ProtectedEnum");
public static readonly BitmapImage ProtectedInterface = LoadBitmap("ProtectedInterface");
public static readonly BitmapImage ProtectedStruct = LoadBitmap("ProtectedStruct");
public static readonly BitmapImage Delete = LoadBitmap("Delete");
public static readonly BitmapImage Search = LoadBitmap("Search");
private static readonly BitmapImage Field = LoadBitmap("Field");
private static readonly BitmapImage FieldReadOnly = LoadBitmap("FieldReadOnly");
private static readonly BitmapImage Literal = LoadBitmap("Literal");
private static readonly BitmapImage EnumValue = LoadBitmap("EnumValue");
private static readonly BitmapImage Method = LoadBitmap("Method");
private static readonly BitmapImage Constructor = LoadBitmap("Constructor");
private static readonly BitmapImage VirtualMethod = LoadBitmap("VirtualMethod");
private static readonly BitmapImage Operator = LoadBitmap("Operator");
private static readonly BitmapImage ExtensionMethod = LoadBitmap("ExtensionMethod");
private static readonly BitmapImage Property = LoadBitmap("Property");
private static readonly BitmapImage Indexer = LoadBitmap("Indexer");
private static readonly BitmapImage Event = LoadBitmap("Event");
private static readonly BitmapImage OverlayProtected = LoadBitmap("OverlayProtected");
private static readonly BitmapImage OverlayInternal = LoadBitmap("OverlayInternal");
private static readonly BitmapImage OverlayProtectedInternal = LoadBitmap("OverlayProtectedInternal");
private static readonly BitmapImage OverlayPrivate = LoadBitmap("OverlayPrivate");
private static readonly BitmapImage OverlayStatic = LoadBitmap("OverlayStatic");
public static BitmapImage LoadImage(object part, string icon)
{
Uri uri;
@ -80,5 +86,206 @@ namespace ICSharpCode.ILSpy @@ -80,5 +86,206 @@ namespace ICSharpCode.ILSpy
image.Freeze();
return image;
}
private static TypeIconCache typeIconCache = new TypeIconCache();
private static MemberIconCache memberIconCache = new MemberIconCache();
public static ImageSource GetIcon(TypeIcon icon, AccessOverlayIcon overlay)
{
return typeIconCache.GetIcon(icon, overlay, false);
}
public static ImageSource GetIcon(MemberIcon icon, AccessOverlayIcon overlay, bool isStatic)
{
return memberIconCache.GetIcon(icon, overlay, isStatic);
}
#region icon caches & overlay management
private class TypeIconCache : IconCache<TypeIcon>
{
public TypeIconCache()
{
PreloadPublicIconToCache(TypeIcon.Class, Images.Class);
PreloadPublicIconToCache(TypeIcon.Enum, Images.Enum);
PreloadPublicIconToCache(TypeIcon.Struct, Images.Struct);
PreloadPublicIconToCache(TypeIcon.Interface, Images.Interface);
PreloadPublicIconToCache(TypeIcon.Delegate, Images.Delegate);
}
protected override ImageSource GetBaseImage(TypeIcon icon)
{
ImageSource baseImage;
switch (icon) {
case TypeIcon.Class:
baseImage = Images.Class;
break;
case TypeIcon.Enum:
baseImage = Images.Enum;
break;
case TypeIcon.Struct:
baseImage = Images.Struct;
break;
case TypeIcon.Interface:
baseImage = Images.Interface;
break;
case TypeIcon.Delegate:
baseImage = Images.Delegate;
break;
default:
throw new NotSupportedException();
}
return baseImage;
}
}
private class MemberIconCache : IconCache<MemberIcon>
{
public MemberIconCache()
{
PreloadPublicIconToCache(MemberIcon.Field, Images.Field);
PreloadPublicIconToCache(MemberIcon.FieldReadOnly, Images.FieldReadOnly);
PreloadPublicIconToCache(MemberIcon.Literal, Images.Literal);
PreloadPublicIconToCache(MemberIcon.EnumValue, Images.EnumValue);
PreloadPublicIconToCache(MemberIcon.Property, Images.Property);
PreloadPublicIconToCache(MemberIcon.Indexer, Images.Indexer);
PreloadPublicIconToCache(MemberIcon.Method, Images.Method);
PreloadPublicIconToCache(MemberIcon.Constructor, Images.Constructor);
PreloadPublicIconToCache(MemberIcon.VirtualMethod, Images.VirtualMethod);
PreloadPublicIconToCache(MemberIcon.Operator, Images.Operator);
PreloadPublicIconToCache(MemberIcon.ExtensionMethod, Images.ExtensionMethod);
PreloadPublicIconToCache(MemberIcon.Event, Images.Event);
}
protected override ImageSource GetBaseImage(MemberIcon icon)
{
ImageSource baseImage;
switch (icon) {
case MemberIcon.Field:
baseImage = Images.Field;
break;
case MemberIcon.FieldReadOnly:
baseImage = Images.FieldReadOnly;
break;
case MemberIcon.Literal:
baseImage = Images.Literal;
break;
case MemberIcon.EnumValue:
baseImage = Images.Literal;
break;
case MemberIcon.Property:
baseImage = Images.Property;
break;
case MemberIcon.Indexer:
baseImage = Images.Indexer;
break;
case MemberIcon.Method:
baseImage = Images.Method;
break;
case MemberIcon.Constructor:
baseImage = Images.Constructor;
break;
case MemberIcon.VirtualMethod:
baseImage = Images.VirtualMethod;
break;
case MemberIcon.Operator:
baseImage = Images.Operator;
break;
case MemberIcon.ExtensionMethod:
baseImage = Images.ExtensionMethod;
break;
case MemberIcon.Event:
baseImage = Images.Event;
break;
default:
throw new NotSupportedException();
}
return baseImage;
}
}
private abstract class IconCache<T>
{
private Dictionary<Tuple<T, AccessOverlayIcon, bool>, ImageSource> cache = new Dictionary<Tuple<T, AccessOverlayIcon, bool>, ImageSource>();
protected void PreloadPublicIconToCache(T icon, ImageSource image)
{
var iconKey = new Tuple<T, AccessOverlayIcon, bool>(icon, AccessOverlayIcon.Public, false);
cache.Add(iconKey, image);
}
public ImageSource GetIcon(T icon, AccessOverlayIcon overlay, bool isStatic)
{
var iconKey = new Tuple<T, AccessOverlayIcon, bool>(icon, overlay, isStatic);
if (cache.ContainsKey(iconKey)) {
return cache[iconKey];
} else {
ImageSource result = BuildMemberIcon(icon, overlay, isStatic);
cache.Add(iconKey, result);
return result;
}
}
private ImageSource BuildMemberIcon(T icon, AccessOverlayIcon overlay, bool isStatic)
{
ImageSource baseImage = GetBaseImage(icon);
ImageSource overlayImage = GetOverlayImage(overlay);
return CreateOverlayImage(baseImage, overlayImage, isStatic);
}
protected abstract ImageSource GetBaseImage(T icon);
private static ImageSource GetOverlayImage(AccessOverlayIcon overlay)
{
ImageSource overlayImage;
switch (overlay) {
case AccessOverlayIcon.Public:
overlayImage = null;
break;
case AccessOverlayIcon.Protected:
overlayImage = Images.OverlayProtected;
break;
case AccessOverlayIcon.Internal:
overlayImage = Images.OverlayInternal;
break;
case AccessOverlayIcon.ProtectedInternal:
overlayImage = Images.OverlayProtectedInternal;
break;
case AccessOverlayIcon.Private:
overlayImage = Images.OverlayPrivate;
break;
default:
throw new NotSupportedException();
}
return overlayImage;
}
private static readonly Rect iconRect = new Rect(0, 0, 16, 16);
private static ImageSource CreateOverlayImage(ImageSource baseImage, ImageSource overlay, bool isStatic)
{
var group = new DrawingGroup();
group.Children.Add(new ImageDrawing(baseImage, iconRect));
if (overlay != null) {
group.Children.Add(new ImageDrawing(overlay, iconRect));
}
if (isStatic) {
group.Children.Add(new ImageDrawing(Images.OverlayStatic, iconRect));
}
var image = new DrawingImage(group);
image.Freeze();
return image;
}
}
#endregion
}
}

BIN
ILSpy/Images/Indexer.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 500 B

BIN
ILSpy/Images/Interface.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ILSpy/Images/InternalClass.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

BIN
ILSpy/Images/InternalDelegate.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

BIN
ILSpy/Images/InternalEnum.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 B

BIN
ILSpy/Images/InternalInterface.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 B

BIN
ILSpy/Images/InternalStruct.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 575 B

BIN
ILSpy/Images/Literal.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 586 B

38
ILSpy/Images/MemberIcon.cs

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
// 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;
namespace ICSharpCode.ILSpy
{
internal enum MemberIcon
{
Literal,
FieldReadOnly,
Field,
EnumValue,
Property,
Indexer,
Method,
Constructor,
VirtualMethod,
Operator,
ExtensionMethod,
Event
}
}

BIN
ILSpy/Images/Method.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 532 B

BIN
ILSpy/Images/Operator.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 526 B

BIN
ILSpy/Images/OverlayInternal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ILSpy/Images/OverlayPrivate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

BIN
ILSpy/Images/OverlayProtected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

BIN
ILSpy/Images/OverlayProtectedInternal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

BIN
ILSpy/Images/OverlayStatic.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

BIN
ILSpy/Images/PrivateClass.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 920 B

BIN
ILSpy/Images/PrivateDelegate.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

BIN
ILSpy/Images/PrivateEnum.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 B

BIN
ILSpy/Images/PrivateInterface.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

BIN
ILSpy/Images/PrivateStruct.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 642 B

BIN
ILSpy/Images/Property.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

After

Width:  |  Height:  |  Size: 746 B

BIN
ILSpy/Images/ProtectedClass.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

BIN
ILSpy/Images/ProtectedDelegate.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 937 B

BIN
ILSpy/Images/ProtectedEnum.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 784 B

BIN
ILSpy/Images/ProtectedInterface.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 753 B

BIN
ILSpy/Images/ProtectedStruct.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 B

BIN
ILSpy/Images/Resource.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 575 B

After

Width:  |  Height:  |  Size: 562 B

BIN
ILSpy/Images/ResourceImage.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

BIN
ILSpy/Images/ResourceResourcesFile.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ILSpy/Images/Struct.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

After

Width:  |  Height:  |  Size: 564 B

BIN
ILSpy/Images/SubTypes.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ILSpy/Images/SuperTypes.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

After

Width:  |  Height:  |  Size: 1.3 KiB

31
ILSpy/Images/TypeIcon.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
// 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;
namespace ICSharpCode.ILSpy
{
internal enum TypeIcon
{
Class,
Enum,
Struct,
Interface,
Delegate
}
}

BIN
ILSpy/Images/VirtualMethod.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

7
ILSpy/Language.cs

@ -105,6 +105,13 @@ namespace ICSharpCode.ILSpy @@ -105,6 +105,13 @@ namespace ICSharpCode.ILSpy
else
return type.Name;
}
public virtual string FormatPropertyName(PropertyDefinition property, bool? isIndexer = null)
{
if (property == null)
throw new ArgumentNullException("property");
return property.Name;
}
/// <summary>
/// Used for WPF keyboard navigation.

24
ILSpy/LoadedAssembly.cs

@ -72,6 +72,28 @@ namespace ICSharpCode.ILSpy @@ -72,6 +72,28 @@ namespace ICSharpCode.ILSpy
return AssemblyDefinition.ReadAssembly(fileName, p);
}
[ThreadStatic]
static int assemblyLoadDisableCount;
public static IDisposable DisableAssemblyLoad()
{
assemblyLoadDisableCount++;
return new DecrementAssemblyLoadDisableCount();
}
sealed class DecrementAssemblyLoadDisableCount : IDisposable
{
bool disposed;
public void Dispose()
{
if (!disposed) {
disposed = true;
assemblyLoadDisableCount--;
}
}
}
sealed class MyAssemblyResolver : IAssemblyResolver
{
readonly LoadedAssembly parent;
@ -112,6 +134,8 @@ namespace ICSharpCode.ILSpy @@ -112,6 +134,8 @@ namespace ICSharpCode.ILSpy
if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
return asm;
}
if (assemblyLoadDisableCount > 0)
return null;
if (!App.Current.Dispatcher.CheckAccess()) {
// Call this method on the GUI thread.

1
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -5,5 +5,6 @@ @@ -5,5 +5,6 @@
<StackPanel Margin="10">
<CheckBox IsChecked="{Binding AnonymousMethods}">Decompile anonymous methods/lambdas</CheckBox>
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
<CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox>
</StackPanel>
</UserControl>

2
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -45,6 +45,7 @@ namespace ICSharpCode.ILSpy @@ -45,6 +45,7 @@ namespace ICSharpCode.ILSpy
DecompilerSettings s = new DecompilerSettings();
s.AnonymousMethods = (bool?)e.Attribute("anonymousMethods") ?? s.AnonymousMethods;
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions;
return s;
}
@ -54,6 +55,7 @@ namespace ICSharpCode.ILSpy @@ -54,6 +55,7 @@ namespace ICSharpCode.ILSpy
XElement section = new XElement("DecompilerSettings");
section.SetAttributeValue("anonymousMethods", s.AnonymousMethods);
section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("queryExpressions", s.QueryExpressions);
XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null)

3
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs

@ -57,8 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -57,8 +57,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
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)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
}

3
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -70,8 +70,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -70,8 +70,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
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)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
}

3
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs

@ -54,8 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -54,8 +54,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
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)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
}

9
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs

@ -18,31 +18,34 @@ @@ -18,31 +18,34 @@
using System;
using Mono.Cecil;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedPropertyTreeNode : AnalyzerTreeNode
{
PropertyDefinition analyzedProperty;
bool isIndexer;
string prefix;
public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "")
{
if (analyzedProperty == null)
throw new ArgumentNullException("analyzedMethod");
this.isIndexer = analyzedProperty.IsIndexer();
this.analyzedProperty = analyzedProperty;
this.prefix = prefix;
this.LazyLoading = true;
}
public override object Icon {
get { return PropertyTreeNode.GetIcon(analyzedProperty); }
get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); }
}
public override object Text {
get {
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language); }
// TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer); }
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)

3
ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs

@ -58,8 +58,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer @@ -58,8 +58,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
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)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
}

25
ILSpy/TreeNodes/EventTreeNode.cs

@ -55,12 +55,29 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -55,12 +55,29 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return HighlightSearchMatch(ev.Name, " : " + this.Language.TypeToString(ev.EventType, false, ev)); }
}
public override object Icon {
get {
return Images.Event;
public override object Icon
{
get { return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(ev.AddMethod.Attributes), ev.AddMethod.IsStatic); }
}
private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes)
{
switch (methodAttributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Public:
return AccessOverlayIcon.Public;
case MethodAttributes.Assembly:
case MethodAttributes.FamANDAssem:
return AccessOverlayIcon.Internal;
case MethodAttributes.Family:
case MethodAttributes.FamORAssem:
return AccessOverlayIcon.Protected;
case MethodAttributes.Private:
return AccessOverlayIcon.Private;
default:
throw new NotSupportedException();
}
}
public override FilterResult Filter(FilterSettings settings)
{
if (settings.SearchTermMatches(ev.Name) && settings.Language.ShowMember(ev))

58
ILSpy/TreeNodes/FieldTreeNode.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Media;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -28,34 +29,60 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -28,34 +29,60 @@ namespace ICSharpCode.ILSpy.TreeNodes
public sealed class FieldTreeNode : ILSpyTreeNode, IMemberTreeNode
{
readonly FieldDefinition field;
public FieldDefinition FieldDefinition {
public FieldDefinition FieldDefinition
{
get { return field; }
}
public FieldTreeNode(FieldDefinition field)
{
if (field == null)
throw new ArgumentNullException("field");
this.field = field;
}
public override object Text {
public override object Text
{
get { return HighlightSearchMatch(field.Name, " : " + this.Language.TypeToString(field.FieldType, false, field)); }
}
public override object Icon {
public override object Icon
{
get { return GetIcon(field); }
}
public static object GetIcon(FieldDefinition field)
public static ImageSource GetIcon(FieldDefinition field)
{
if (field.DeclaringType.IsEnum && !field.Attributes.HasFlag(FieldAttributes.SpecialName))
return Images.GetIcon(MemberIcon.EnumValue, GetOverlayIcon(field.Attributes), false);
if (field.IsLiteral)
return Images.Literal;
return Images.GetIcon(MemberIcon.Literal, GetOverlayIcon(field.Attributes), false);
else if (field.IsInitOnly)
return Images.GetIcon(MemberIcon.FieldReadOnly, GetOverlayIcon(field.Attributes), field.IsStatic);
else
return Images.Field;
return Images.GetIcon(MemberIcon.Field, GetOverlayIcon(field.Attributes), field.IsStatic);
}
private static AccessOverlayIcon GetOverlayIcon(FieldAttributes fieldAttributes)
{
switch (fieldAttributes & FieldAttributes.FieldAccessMask) {
case FieldAttributes.Public:
return AccessOverlayIcon.Public;
case FieldAttributes.Assembly:
case FieldAttributes.FamANDAssem:
return AccessOverlayIcon.Internal;
case FieldAttributes.Family:
case FieldAttributes.FamORAssem:
return AccessOverlayIcon.Protected;
case FieldAttributes.Private:
return AccessOverlayIcon.Private;
default:
throw new NotSupportedException();
}
}
public override FilterResult Filter(FilterSettings settings)
{
if (settings.SearchTermMatches(field.Name) && settings.Language.ShowMember(field))
@ -63,13 +90,14 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -63,13 +90,14 @@ namespace ICSharpCode.ILSpy.TreeNodes
else
return FilterResult.Hidden;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileField(field, output, options);
}
MemberReference IMemberTreeNode.Member {
MemberReference IMemberTreeNode.Member
{
get { return field; }
}
}

85
ILSpy/TreeNodes/MethodTreeNode.cs

@ -18,8 +18,7 @@ @@ -18,8 +18,7 @@
using System;
using System.Text;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -31,20 +30,23 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -31,20 +30,23 @@ namespace ICSharpCode.ILSpy.TreeNodes
public sealed class MethodTreeNode : ILSpyTreeNode, IMemberTreeNode
{
MethodDefinition method;
public MethodDefinition MethodDefinition {
public MethodDefinition MethodDefinition
{
get { return method; }
}
public MethodTreeNode(MethodDefinition method)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
}
public override object Text {
get {
public override object Text
{
get
{
return GetText(method, Language);
}
}
@ -58,35 +60,71 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -58,35 +60,71 @@ namespace ICSharpCode.ILSpy.TreeNodes
b.Append(", ");
b.Append(language.TypeToString(method.Parameters[i].ParameterType, false, method.Parameters[i]));
}
if (method.CallingConvention == MethodCallingConvention.VarArg) {
if (method.HasParameters)
b.Append(", ");
b.Append("...");
}
b.Append(") : ");
b.Append(language.TypeToString(method.ReturnType, false, method.MethodReturnType));
return HighlightSearchMatch(method.Name, b.ToString());
}
public override object Icon {
get {
return GetIcon(method);
}
public override object Icon
{
get { return GetIcon(method); }
}
public static BitmapImage GetIcon(MethodDefinition method)
public static ImageSource GetIcon(MethodDefinition method)
{
if (method.IsSpecialName && method.Name.StartsWith("op_", StringComparison.Ordinal))
return Images.Operator;
if (method.IsSpecialName && method.Name.StartsWith("op_", StringComparison.Ordinal)) {
return Images.GetIcon(MemberIcon.Operator, GetOverlayIcon(method.Attributes), false);
}
if (method.IsStatic && method.HasCustomAttributes) {
foreach (var ca in method.CustomAttributes) {
if (ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
return Images.ExtensionMethod;
if (ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") {
return Images.GetIcon(MemberIcon.ExtensionMethod, GetOverlayIcon(method.Attributes), false);
}
}
}
return Images.Method;
if (method.IsSpecialName &&
(method.Name == ".ctor" || method.Name == ".cctor")) {
return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(method.Attributes), false);
}
bool showAsVirtual = method.IsVirtual && !(method.IsNewSlot && method.IsFinal) && !method.DeclaringType.IsInterface;
return Images.GetIcon(
showAsVirtual ? MemberIcon.VirtualMethod : MemberIcon.Method,
GetOverlayIcon(method.Attributes),
method.IsStatic);
}
private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes)
{
switch (methodAttributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Public:
return AccessOverlayIcon.Public;
case MethodAttributes.Assembly:
case MethodAttributes.FamANDAssem:
return AccessOverlayIcon.Internal;
case MethodAttributes.Family:
case MethodAttributes.FamORAssem:
return AccessOverlayIcon.Protected;
case MethodAttributes.Private:
return AccessOverlayIcon.Private;
default:
throw new NotSupportedException();
}
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileMethod(method, output, options);
}
public override FilterResult Filter(FilterSettings settings)
{
if (settings.SearchTermMatches(method.Name) && settings.Language.ShowMember(method))
@ -94,8 +132,9 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -94,8 +132,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
else
return FilterResult.Hidden;
}
MemberReference IMemberTreeNode.Member {
MemberReference IMemberTreeNode.Member
{
get { return method; }
}
}

102
ILSpy/TreeNodes/PropertyTreeNode.cs

@ -17,8 +17,7 @@ @@ -17,8 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -31,13 +30,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -31,13 +30,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
readonly PropertyDefinition property;
readonly bool isIndexer;
public PropertyTreeNode(PropertyDefinition property, bool isIndexer)
public PropertyTreeNode(PropertyDefinition property)
{
if (property == null)
throw new ArgumentNullException("property");
this.property = property;
this.isIndexer = isIndexer;
using (LoadedAssembly.DisableAssemblyLoad()) {
this.isIndexer = property.IsIndexer();
}
if (property.GetMethod != null)
this.Children.Add(new MethodTreeNode(property.GetMethod));
if (property.SetMethod != null)
@ -52,27 +54,88 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -52,27 +54,88 @@ namespace ICSharpCode.ILSpy.TreeNodes
public PropertyDefinition PropertyDefinition {
get { return property; }
}
public override object Text {
get { return GetText(property, Language); }
public override object Text
{
get { return GetText(property, Language, isIndexer); }
}
public static object GetText(PropertyDefinition property, Language language, bool? isIndexer = null)
{
return HighlightSearchMatch(language.FormatPropertyName(property, isIndexer), " : " + language.TypeToString(property.PropertyType, false, property));
}
public static object GetText(PropertyDefinition property, Language language)
public override object Icon
{
return HighlightSearchMatch(property.Name, " : " + language.TypeToString(property.PropertyType, false, property));
get { return GetIcon(property); }
}
public override object Icon {
get {
return GetIcon(property, isIndexer);
public static ImageSource GetIcon(PropertyDefinition property, bool isIndexer = false)
{
MemberIcon icon = isIndexer ? MemberIcon.Indexer : MemberIcon.Property;
MethodAttributes attributesOfMostAccessibleMethod = GetAttributesOfMostAccessibleMethod(property);
bool isStatic = (attributesOfMostAccessibleMethod & MethodAttributes.Static) != 0;
return Images.GetIcon(icon, GetOverlayIcon(attributesOfMostAccessibleMethod), isStatic);
}
private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes)
{
switch (methodAttributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Public:
return AccessOverlayIcon.Public;
case MethodAttributes.Assembly:
case MethodAttributes.FamANDAssem:
return AccessOverlayIcon.Internal;
case MethodAttributes.Family:
case MethodAttributes.FamORAssem:
return AccessOverlayIcon.Protected;
case MethodAttributes.Private:
return AccessOverlayIcon.Private;
default:
throw new NotSupportedException();
}
}
public static BitmapImage GetIcon(PropertyDefinition property, bool? isIndexer = null)
private static MethodAttributes GetAttributesOfMostAccessibleMethod(PropertyDefinition property)
{
return (isIndexer ?? false) ? Images.Indexer : Images.Property;
// There should always be at least one method from which to
// obtain the result, but the compiler doesn't know this so
// initialize the result with a default value
MethodAttributes result = (MethodAttributes)0;
// Method access is defined from inaccessible (lowest) to public (highest)
// in numeric order, so we can do an integer comparison of the masked attribute
int accessLevel = 0;
if (property.GetMethod != null) {
int methodAccessLevel = (int)(property.GetMethod.Attributes & MethodAttributes.MemberAccessMask);
if (accessLevel < methodAccessLevel) {
accessLevel = methodAccessLevel;
result = property.GetMethod.Attributes;
}
}
if (property.SetMethod != null) {
int methodAccessLevel = (int)(property.SetMethod.Attributes & MethodAttributes.MemberAccessMask);
if (accessLevel < methodAccessLevel) {
accessLevel = methodAccessLevel;
result = property.SetMethod.Attributes;
}
}
if (property.HasOtherMethods) {
foreach (var m in property.OtherMethods) {
int methodAccessLevel = (int)(m.Attributes & MethodAttributes.MemberAccessMask);
if (accessLevel < methodAccessLevel) {
accessLevel = methodAccessLevel;
result = m.Attributes;
}
}
}
return result;
}
public override FilterResult Filter(FilterSettings settings)
{
if (settings.SearchTermMatches(property.Name) && settings.Language.ShowMember(property))
@ -80,13 +143,14 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -80,13 +143,14 @@ namespace ICSharpCode.ILSpy.TreeNodes
else
return FilterResult.Hidden;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileProperty(property, output, options);
}
MemberReference IMemberTreeNode.Member {
MemberReference IMemberTreeNode.Member
{
get { return property; }
}
}

7
ILSpy/TreeNodes/ResourceEntryNode.cs

@ -102,7 +102,12 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -102,7 +102,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
public ImageResourceEntryNode(string key, Stream data) : base(key, data)
{
}
public override object Icon
{
get { return Images.ResourceImage; }
}
internal override bool View(DecompilerTextView textView)
{
try {

8
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -37,12 +37,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -37,12 +37,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public override object Icon {
get { return Images.Resource; }
get { return Images.FolderClosed; }
}
public override object ExpandedIcon {
get { return Images.FolderOpen; }
}
protected override void LoadChildren()
{
foreach (Resource r in module.Resources)
foreach (Resource r in module.Resources.OrderBy(m => m.Name))
this.Children.Add(ResourceTreeNode.Create(r));
}

7
ILSpy/TreeNodes/ResourceTreeNode.cs

@ -151,7 +151,12 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -151,7 +151,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
this.LazyLoading = true;
}
public override object Icon
{
get { return Images.ResourceResourcesFile; }
}
protected override void LoadChildren()
{
EmbeddedResource er = this.Resource as EmbeddedResource;

90
ILSpy/TreeNodes/TypeTreeNode.cs

@ -105,16 +105,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -105,16 +105,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.Children.Add(new FieldTreeNode(field));
}
// figure out the name of the indexer:
string defaultMemberName = null;
var defaultMemberAttribute = type.CustomAttributes.FirstOrDefault(
a => a.AttributeType.FullName == typeof(System.Reflection.DefaultMemberAttribute).FullName);
if (defaultMemberAttribute != null && defaultMemberAttribute.ConstructorArguments.Count == 1) {
defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string;
}
foreach (PropertyDefinition property in type.Properties.OrderBy(m => m.Name)) {
this.Children.Add(new PropertyTreeNode(property, property.Name == defaultMemberName));
this.Children.Add(new PropertyTreeNode(property));
}
foreach (EventDefinition ev in type.Events.OrderBy(m => m.Name)) {
this.Children.Add(new EventTreeNode(ev));
@ -132,82 +124,62 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -132,82 +124,62 @@ namespace ICSharpCode.ILSpy.TreeNodes
DebugData.CurrentType = type;
language.DecompileType(type, output, options);
}
#region Icon
enum ClassType
public override object Icon
{
Class,
Enum,
Struct,
Interface,
Delegate
get { return GetIcon(type); }
}
static ClassType GetClassType(TypeDefinition type)
public static ImageSource GetIcon(TypeDefinition type)
{
TypeIcon typeIcon = GetTypeIcon(type);
AccessOverlayIcon overlayIcon = GetOverlayIcon(type);
return Images.GetIcon(typeIcon, overlayIcon);
}
static TypeIcon GetTypeIcon(TypeDefinition type)
{
if (type.IsValueType) {
if (type.IsEnum)
return ClassType.Enum;
return TypeIcon.Enum;
else
return ClassType.Struct;
return TypeIcon.Struct;
} else {
if (type.IsInterface)
return ClassType.Interface;
return TypeIcon.Interface;
else if (type.BaseType != null && type.BaseType.FullName == typeof(MulticastDelegate).FullName)
return ClassType.Delegate;
return TypeIcon.Delegate;
else
return ClassType.Class;
return TypeIcon.Class;
}
}
public override object Icon {
get {
return GetIcon(type);
}
}
public static ImageSource GetIcon(TypeDefinition type)
private static AccessOverlayIcon GetOverlayIcon(TypeDefinition type)
{
AccessOverlayIcon overlay;
switch (type.Attributes & TypeAttributes.VisibilityMask) {
case TypeAttributes.Public:
case TypeAttributes.NestedPublic:
switch (GetClassType(type)) {
case ClassType.Delegate: return Images.Delegate;
case ClassType.Enum: return Images.Enum;
case ClassType.Interface: return Images.Interface;
case ClassType.Struct: return Images.Struct;
default: return Images.Class;
}
overlay = AccessOverlayIcon.Public;
break;
case TypeAttributes.NotPublic:
case TypeAttributes.NestedAssembly:
case TypeAttributes.NestedFamANDAssem:
switch (GetClassType(type)) {
case ClassType.Delegate: return Images.InternalDelegate;
case ClassType.Enum: return Images.InternalEnum;
case ClassType.Interface: return Images.InternalInterface;
case ClassType.Struct: return Images.InternalStruct;
default: return Images.InternalClass;
}
overlay = AccessOverlayIcon.Internal;
break;
case TypeAttributes.NestedFamily:
case TypeAttributes.NestedFamORAssem:
switch (GetClassType(type)) {
case ClassType.Delegate: return Images.ProtectedDelegate;
case ClassType.Enum: return Images.ProtectedEnum;
case ClassType.Interface: return Images.ProtectedInterface;
case ClassType.Struct: return Images.ProtectedStruct;
default: return Images.ProtectedClass;
}
overlay = AccessOverlayIcon.Protected;
break;
case TypeAttributes.NestedPrivate:
switch (GetClassType(type)) {
case ClassType.Delegate: return Images.PrivateDelegate;
case ClassType.Enum: return Images.PrivateEnum;
case ClassType.Interface: return Images.PrivateInterface;
case ClassType.Struct: return Images.PrivateStruct;
default: return Images.PrivateClass;
}
overlay = AccessOverlayIcon.Private;
break;
default:
throw new NotSupportedException();
}
return overlay;
}
#endregion

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

Loading…
Cancel
Save