|
|
@ -4,6 +4,7 @@ |
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.Linq; |
|
|
|
using System.Linq; |
|
|
|
using ICSharpCode.NRefactory.CSharp; |
|
|
|
using ICSharpCode.NRefactory.CSharp; |
|
|
|
|
|
|
|
using ICSharpCode.NRefactory.CSharp.PatternMatching; |
|
|
|
using Mono.Cecil; |
|
|
|
using Mono.Cecil; |
|
|
|
|
|
|
|
|
|
|
|
namespace ICSharpCode.Decompiler.Ast.Transforms |
|
|
|
namespace ICSharpCode.Decompiler.Ast.Transforms |
|
|
@ -32,26 +33,91 @@ namespace ICSharpCode.Decompiler.Ast.Transforms |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
// Move arguments from invocation to initializer:
|
|
|
|
// Move arguments from invocation to initializer:
|
|
|
|
invocation.Arguments.MoveTo(ci.Arguments); |
|
|
|
invocation.Arguments.MoveTo(ci.Arguments); |
|
|
|
// Add the initializer:
|
|
|
|
// Add the initializer: (unless it is the default 'base()')
|
|
|
|
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>()); |
|
|
|
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0)) |
|
|
|
|
|
|
|
constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation<MethodReference>()); |
|
|
|
// Remove the statement:
|
|
|
|
// Remove the statement:
|
|
|
|
stmt.Remove(); |
|
|
|
stmt.Remove(); |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static readonly ExpressionStatement fieldInitializerPattern = new ExpressionStatement { |
|
|
|
|
|
|
|
Expression = new AssignmentExpression { |
|
|
|
|
|
|
|
Left = new NamedNode("fieldAccess", new MemberReferenceExpression { Target = new ThisReferenceExpression() }), |
|
|
|
|
|
|
|
Operator = AssignmentOperatorType.Assign, |
|
|
|
|
|
|
|
Right = new AnyNode("initializer") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) |
|
|
|
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
var instanceCtors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); |
|
|
|
|
|
|
|
if (instanceCtors.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class) { |
|
|
|
|
|
|
|
// Recognize field initializers:
|
|
|
|
|
|
|
|
// Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
|
|
|
|
|
|
|
|
bool allSame; |
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
Match m = fieldInitializerPattern.Match(instanceCtors[0].Body.FirstOrDefault()); |
|
|
|
|
|
|
|
if (m == null) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allSame = true; |
|
|
|
|
|
|
|
for (int i = 1; i < instanceCtors.Length; i++) { |
|
|
|
|
|
|
|
if (instanceCtors[0].Body.First().Match(instanceCtors[i].Body.FirstOrDefault()) == null) |
|
|
|
|
|
|
|
allSame = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (allSame) { |
|
|
|
|
|
|
|
foreach (var ctor in instanceCtors) |
|
|
|
|
|
|
|
ctor.Body.First().Remove(); |
|
|
|
|
|
|
|
fieldDecl.Variables.Single().Initializer = m.Get<Expression>("initializer").Single().Detach(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} while (allSame); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now convert base constructor calls to initializers:
|
|
|
|
base.VisitTypeDeclaration(typeDeclaration, data); |
|
|
|
base.VisitTypeDeclaration(typeDeclaration, data); |
|
|
|
|
|
|
|
|
|
|
|
// Remove single empty constructor:
|
|
|
|
// Remove single empty constructor:
|
|
|
|
var ctors = typeDeclaration.Members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); |
|
|
|
if (instanceCtors.Length == 1) { |
|
|
|
if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0 |
|
|
|
ConstructorDeclaration emptyCtor = new ConstructorDeclaration(); |
|
|
|
&& ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base |
|
|
|
emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public); |
|
|
|
&& ctors[0].Initializer.Arguments.Count() == 0 |
|
|
|
emptyCtor.Body = new BlockStatement(); |
|
|
|
&& ctors[0].Parameters.Count == 0 |
|
|
|
if (emptyCtor.Match(instanceCtors[0]) != null) |
|
|
|
&& ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public)) |
|
|
|
instanceCtors[0].Remove(); |
|
|
|
{ |
|
|
|
} |
|
|
|
ctors[0].Remove(); |
|
|
|
|
|
|
|
|
|
|
|
// Convert static constructor into field initializers if the class is BeforeFieldInit
|
|
|
|
|
|
|
|
var staticCtor = typeDeclaration.Members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static); |
|
|
|
|
|
|
|
if (staticCtor != null) { |
|
|
|
|
|
|
|
TypeDefinition typeDef = typeDeclaration.Annotation<TypeDefinition>(); |
|
|
|
|
|
|
|
if (typeDef != null && typeDef.IsBeforeFieldInit) { |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement; |
|
|
|
|
|
|
|
if (es == null) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
AssignmentExpression assignment = es.Expression as AssignmentExpression; |
|
|
|
|
|
|
|
if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
FieldDefinition fieldDef = assignment.Left.Annotation<FieldDefinition>(); |
|
|
|
|
|
|
|
if (fieldDef == null || !fieldDef.IsStatic) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
FieldDeclaration fieldDecl = typeDeclaration.Members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef); |
|
|
|
|
|
|
|
if (fieldDecl == null) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
fieldDecl.Variables.Single().Initializer = assignment.Right.Detach(); |
|
|
|
|
|
|
|
es.Remove(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (staticCtor.Body.Statements.Count == 0) |
|
|
|
|
|
|
|
staticCtor.Remove(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|