Browse Source

Add support for decompiling automatic events.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
f3069b99f9
  1. 18
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 6
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  3. 97
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  4. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  5. 3
      ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs

18
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -56,6 +56,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -56,6 +56,9 @@ namespace ICSharpCode.Decompiler.Ast
if (settings.AutomaticProperties && field.Name.StartsWith("<", StringComparison.Ordinal) && field.Name.EndsWith("BackingField", StringComparison.Ordinal))
return true;
}
// event-fields are not [CompilerGenerated]
if (field != null && settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
return true;
return false;
}
@ -922,20 +925,27 @@ namespace ICSharpCode.Decompiler.Ast @@ -922,20 +925,27 @@ namespace ICSharpCode.Decompiler.Ast
}
}
void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition)
internal static void ConvertAttributes(AttributedNode attributedNode, FieldDefinition fieldDefinition, AttributeTarget target = AttributeTarget.None)
{
ConvertCustomAttributes(attributedNode, fieldDefinition);
#region FieldOffsetAttribute
if (fieldDefinition.HasLayoutInfo) {
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute));
Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute), fieldDefinition.Module);
fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset));
attributedNode.Attributes.Add(new AttributeSection(fieldOffset));
attributedNode.Attributes.Add(new AttributeSection(fieldOffset) { AttributeTarget = target });
}
#endregion
#region NonSerializedAttribute
if (fieldDefinition.IsNotSerialized) {
Ast.Attribute nonSerialized = CreateNonCustomAttribute(typeof(NonSerializedAttribute), fieldDefinition.Module);
attributedNode.Attributes.Add(new AttributeSection(nonSerialized) { AttributeTarget = target });
}
#endregion
if (fieldDefinition.HasMarshalInfo) {
attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)));
attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)) { AttributeTarget = target });
}
}

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

@ -65,8 +65,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -65,8 +65,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation<FieldDefinition>();
if (fieldDef == null)
break;
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldDecl == null)
AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldOrEventDecl == null)
break;
allSame = true;
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (allSame) {
foreach (var ctor in instanceCtors)
ctor.Body.First().Remove();
fieldDecl.Variables.Single().Initializer = m.Get<Expression>("initializer").Single().Detach();
fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = m.Get<Expression>("initializer").Single().Detach();
}
} while (allSame);
}

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

@ -33,6 +33,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -33,6 +33,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
TransformDoWhile(compilationUnit);
if (context.Settings.AutomaticProperties)
TransformAutomaticProperties(compilationUnit);
if (context.Settings.AutomaticEvents)
TransformAutomaticEvents(compilationUnit);
}
/// <summary>
@ -357,5 +359,100 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -357,5 +359,100 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
}
#endregion
#region Automatic Events
Accessor automaticEventPatternV4 = new Accessor {
Body = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("type"),
Variables = {
new NamedNode(
"var1", new VariableInitializer {
Initializer = new NamedNode("field", new MemberReferenceExpression { Target = new ThisReferenceExpression() })
})}
},
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = { new NamedNode("var2", new VariableInitializer()) }
},
new DoWhileStatement {
EmbeddedStatement = new BlockStatement {
new AssignmentExpression(new IdentifierExpressionBackreference("var2"), new IdentifierExpressionBackreference("var1")),
new VariableDeclarationStatement {
Type = new Backreference("type"),
Variables = {
new NamedNode(
"var3", new VariableInitializer {
Initializer = new AnyNode("delegateCombine").ToExpression().Invoke(
new IdentifierExpressionBackreference("var2"),
new IdentifierExpression("value")
).CastTo(new Backreference("type"))
})
}},
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("var1"),
Right = new AnyNode("Interlocked").ToType().Invoke(
"CompareExchange",
new AstType[] { new Backreference("type") }, // type argument
new Expression[] { // arguments
new DirectionExpression { FieldDirection = FieldDirection.Ref, Expression = new Backreference("field") },
new IdentifierExpressionBackreference("var3"),
new IdentifierExpressionBackreference("var2")
}
)}
},
Condition = new BinaryOperatorExpression {
Left = new IdentifierExpressionBackreference("var1"),
Operator = BinaryOperatorType.InEquality,
Right = new IdentifierExpressionBackreference("var2")
}}
}};
bool CheckAutomaticEventV4Match(Match m, CustomEventDeclaration ev, bool isAddAccessor)
{
if (m == null)
return false;
if (m.Get<MemberReferenceExpression>("field").Single().MemberName != ev.Name)
return false; // field name must match event name
if (ev.ReturnType.Match(m.Get("type").Single()) == null)
return false; // variable types must match event type
var combineMethod = m.Get("delegateCombine").Single().Parent.Annotation<MethodReference>();
if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove"))
return false;
if (combineMethod.DeclaringType.FullName != "System.Delegate")
return false;
var ice = m.Get("Interlocked").Single().Annotation<TypeReference>();
return ice != null && ice.FullName == "System.Threading.Interlocked";
}
void TransformAutomaticEvents(AstNode compilationUnit)
{
foreach (var ev in compilationUnit.Descendants.OfType<CustomEventDeclaration>().ToArray()) {
Match m1 = automaticEventPatternV4.Match(ev.AddAccessor);
if (!CheckAutomaticEventV4Match(m1, ev, true))
continue;
Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor);
if (!CheckAutomaticEventV4Match(m2, ev, false))
continue;
EventDeclaration ed = new EventDeclaration();
ev.Attributes.MoveTo(ed.Attributes);
ed.ReturnType = ev.ReturnType.Detach();
ed.Modifiers = ev.Modifiers;
ed.Variables.Add(new VariableInitializer(ev.Name));
ed.CopyAnnotationsFrom(ev);
EventDefinition eventDef = ev.Annotation<EventDefinition>();
if (eventDef != null) {
FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name);
if (field != null) {
ed.AddAnnotation(field);
AstBuilder.ConvertAttributes(ed, field, AttributeTarget.Field);
}
}
ev.ReplaceWith(ed);
}
}
#endregion
}
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -56,6 +56,21 @@ namespace ICSharpCode.Decompiler @@ -56,6 +56,21 @@ namespace ICSharpCode.Decompiler
}
}
bool automaticEvents = true;
/// <summary>
/// Decompile automatic events
/// </summary>
public bool AutomaticEvents {
get { return automaticEvents; }
set {
if (automaticEvents != value) {
automaticEvents = value;
OnPropertyChanged("AutomaticEvents");
}
}
}
bool usingStatement = true;
/// <summary>

3
ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs

@ -39,6 +39,9 @@ public class PropertiesAndEvents @@ -39,6 +39,9 @@ public class PropertiesAndEvents
public event EventHandler AutomaticEvent;
[field: NonSerialized]
public event EventHandler AutomaticEventWithInitializer = delegate {};
public event EventHandler CustomEvent {
add {
this.AutomaticEvent += value;

Loading…
Cancel
Save