Browse Source

Reimplement transform for auto events

pull/832/head
Siegfried Pammer 8 years ago
parent
commit
4b6e0cc462
  1. 4
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 6
      ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs
  3. 74
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  4. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  5. 6
      ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs

4
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -202,8 +202,8 @@ namespace ICSharpCode.Decompiler.CSharp
// return true; // return true;
} }
// event-fields are not [CompilerGenerated] // event-fields are not [CompilerGenerated]
// if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name)) if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
// return true; return true;
// HACK : only hide fields starting with '__StaticArrayInit' // HACK : only hide fields starting with '__StaticArrayInit'
if (field.DeclaringType.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal)) { if (field.DeclaringType.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal)) {
if (field.Name.StartsWith("__StaticArrayInit", StringComparison.Ordinal)) if (field.Name.StartsWith("__StaticArrayInit", StringComparison.Ordinal))

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

@ -126,10 +126,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!m.Success) if (!m.Success)
break; break;
IMember fieldOrProperty = (m.Get<AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition; IMember fieldOrPropertyOrEvent = (m.Get<AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition;
if (!(fieldOrProperty is IField) && !(fieldOrProperty is IProperty)) if (!(fieldOrPropertyOrEvent is IField) && !(fieldOrPropertyOrEvent is IProperty) && !(fieldOrPropertyOrEvent is IEvent))
break; break;
AstNode fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrProperty); AstNode fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrPropertyOrEvent);
if (fieldOrPropertyOrEventDecl == null) if (fieldOrPropertyOrEventDecl == null)
break; break;
Expression initializer = m.Get<Expression>("initializer").Single(); Expression initializer = m.Get<Expression>("initializer").Single();

74
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -86,6 +86,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (result != null) if (result != null)
return result; return result;
} }
if (context.Settings.AutomaticEvents) {
result = ReplaceEventFieldAnnotation(expressionStatement);
if (result != null)
return result;
}
return base.VisitExpressionStatement(expressionStatement); return base.VisitExpressionStatement(expressionStatement);
} }
@ -1057,15 +1062,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
return null; return null;
} }
ExpressionStatement ReplaceEventFieldAnnotation(ExpressionStatement expressionStatement)
{
foreach (var identifier in expressionStatement.Descendants.OfType<Identifier>()) {
var parent = identifier.Parent;
var mrr = parent.Annotation<MemberResolveResult>();
var field = mrr?.Member as IField;
if (field == null) continue;
var @event = field.DeclaringType.GetEvents(ev => ev.Name == field.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault();
if (@event != null) {
parent.RemoveAnnotations<MemberResolveResult>();
parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, @event));
}
}
return null;
}
#endregion #endregion
#region Automatic Events #region Automatic Events
static readonly Accessor automaticEventPatternV4 = new Accessor { static readonly Accessor automaticEventPatternV4 = new Accessor {
Attributes = { new Repeat(new AnyNode()) }, Attributes = { new Repeat(new AnyNode()) },
Body = new BlockStatement { Body = new BlockStatement {
new VariableDeclarationStatement { Type = new AnyNode("type"), Variables = { new AnyNode() } },
new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } },
new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } },
new AssignmentExpression { new AssignmentExpression {
Left = new NamedNode("var1", new IdentifierExpression(Pattern.AnyString)), Left = new NamedNode("var1", new IdentifierExpression(Pattern.AnyString)),
Operator = AssignmentOperatorType.Assign, Operator = AssignmentOperatorType.Assign,
@ -1076,14 +1094,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
MemberName = Pattern.AnyString MemberName = Pattern.AnyString
}) })
}, },
new DoWhileStatement { new WhileStatement {
Condition = new PrimitiveExpression(true),
EmbeddedStatement = new BlockStatement { EmbeddedStatement = new BlockStatement {
new AssignmentExpression(new NamedNode("var2", new IdentifierExpression(Pattern.AnyString)), new IdentifierExpressionBackreference("var1")), new AssignmentExpression(new NamedNode("var2", new IdentifierExpression(Pattern.AnyString)), new IdentifierExpressionBackreference("var1")),
new AssignmentExpression { new AssignmentExpression {
Left = new NamedNode("var3", new IdentifierExpression(Pattern.AnyString)), Left = new NamedNode("var3", new IdentifierExpression(Pattern.AnyString)),
Operator = AssignmentOperatorType.Assign, Operator = AssignmentOperatorType.Assign,
Right = new CastExpression(new Backreference("type"), new InvocationExpression(new AnyNode("delegateCombine").ToExpression(), new IdentifierExpressionBackreference("var2"), Right = new CastExpression(new AnyNode("type"), new InvocationExpression(new AnyNode("delegateCombine").ToExpression(), new CastExpression(new TypePattern(typeof(System.Delegate)), new IdentifierExpressionBackreference("var2")),
new IdentifierExpression("value") new CastExpression(new TypePattern(typeof(System.Delegate)), new IdentifierExpression("value"))
)) ))
}, },
new AssignmentExpression { new AssignmentExpression {
@ -1096,13 +1115,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
new IdentifierExpressionBackreference("var3"), new IdentifierExpressionBackreference("var3"),
new IdentifierExpressionBackreference("var2") new IdentifierExpressionBackreference("var2")
} }
)} )},
}, new IfElseStatement {
Condition = new BinaryOperatorExpression { Condition = new BinaryOperatorExpression {
Left = new IdentifierExpressionBackreference("var1"), Left = new CastExpression(new TypePattern(typeof(object)), new IdentifierExpressionBackreference("var1")),
Operator = BinaryOperatorType.InEquality, Operator = BinaryOperatorType.Equality,
Right = new IdentifierExpressionBackreference("var2") Right = new IdentifierExpressionBackreference("var2")
}} },
TrueStatement = new BreakStatement()
}
}
}
}}; }};
bool CheckAutomaticEventV4Match(Match m, CustomEventDeclaration ev, bool isAddAccessor) bool CheckAutomaticEventV4Match(Match m, CustomEventDeclaration ev, bool isAddAccessor)
@ -1113,11 +1136,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return false; // field name must match event name return false; // field name must match event name
if (!ev.ReturnType.IsMatch(m.Get("type").Single())) if (!ev.ReturnType.IsMatch(m.Get("type").Single()))
return false; // variable types must match event type return false; // variable types must match event type
var combineMethod = m.Get<AstNode>("delegateCombine").Single().Parent.Annotation<MethodReference>(); var combineMethod = m.Get<AstNode>("delegateCombine").Single().Parent.GetSymbol() as IMethod;
if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove")) if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove"))
return false; return false;
return combineMethod.DeclaringType.FullName == "System.Delegate"; return combineMethod.DeclaringType.FullName == "System.Delegate";
} }
static readonly string[] attributeTypesToRemoveFromAutoEvents = new[] {
"System.Runtime.CompilerServices.CompilerGeneratedAttribute",
"System.Diagnostics.DebuggerBrowsableAttribute"
};
EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev) EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev)
{ {
@ -1127,6 +1155,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor); Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor);
if (!CheckAutomaticEventV4Match(m2, ev, false)) if (!CheckAutomaticEventV4Match(m2, ev, false))
return null; return null;
RemoveCompilerGeneratedAttribute(ev.AddAccessor.Attributes);
EventDeclaration ed = new EventDeclaration(); EventDeclaration ed = new EventDeclaration();
ev.Attributes.MoveTo(ed.Attributes); ev.Attributes.MoveTo(ed.Attributes);
foreach (var attr in ev.AddAccessor.Attributes) { foreach (var attr in ev.AddAccessor.Attributes) {
@ -1138,12 +1167,21 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
ed.Variables.Add(new VariableInitializer(ev.Name)); ed.Variables.Add(new VariableInitializer(ev.Name));
ed.CopyAnnotationsFrom(ev); ed.CopyAnnotationsFrom(ev);
EventDefinition eventDef = ev.Annotation<EventDefinition>(); IEvent eventDef = ev.GetSymbol() as IEvent;
if (eventDef != null) { if (eventDef != null) {
FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name); IField field = eventDef.DeclaringType.GetFields(f => f.Name == ev.Name, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault();
if (field != null) { if (field != null) {
ed.AddAnnotation(field); ed.AddAnnotation(field);
// TODO AstBuilder.ConvertAttributes(ed, field, "field"); var attributes = field.Attributes
.Where(a => !attributeTypesToRemoveFromAutoEvents.Any(t => t == a.AttributeType.FullName))
.Select(context.TypeSystemAstBuilder.ConvertAttribute).ToArray();
if (attributes.Length > 0) {
var section = new AttributeSection {
AttributeTarget = "field"
};
section.Attributes.AddRange(attributes);
ed.Attributes.Add(section);
}
} }
} }

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -153,6 +153,7 @@
<Compile Include="TestCases\Pretty\ExceptionHandling.cs" /> <Compile Include="TestCases\Pretty\ExceptionHandling.cs" />
<Compile Include="TestCases\Pretty\HelloWorld.cs" /> <Compile Include="TestCases\Pretty\HelloWorld.cs" />
<Compile Include="TestCases\Pretty\InlineAssignmentTest.cs" /> <Compile Include="TestCases\Pretty\InlineAssignmentTest.cs" />
<Compile Include="TestCases\Pretty\PropertiesAndEvents.cs" />
<Compile Include="TestCases\Pretty\ShortCircuit.cs" /> <Compile Include="TestCases\Pretty\ShortCircuit.cs" />
<Compile Include="TestTraceListener.cs" /> <Compile Include="TestTraceListener.cs" />
<Compile Include="Util\IntervalTests.cs" /> <Compile Include="Util\IntervalTests.cs" />

6
ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs

@ -115,6 +115,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions); Run(cscOptions: cscOptions);
} }
[Test]
public void PropertiesAndEvents([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);
}
[Test] [Test]
public void AutoProperties([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions) public void AutoProperties([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
{ {

Loading…
Cancel
Save