﻿using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.NRefactory.CSharp;

namespace JSIL {
    public class DeclarationHoister : ContextTrackingVisitor<object> {
        public readonly BlockStatement Output;
        public VariableDeclarationStatement Statement = null;
        public readonly HashSet<string> HoistedNames = new HashSet<string>();

        public DeclarationHoister (DecompilerContext context, BlockStatement output)
            : base(context) {

            Output = output;
        }

        public override object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) {
            if (Statement == null) {
                Statement = new VariableDeclarationStatement();
                Output.Add(Statement);
            }

            foreach (var variable in variableDeclarationStatement.Variables) {
                if (!HoistedNames.Contains(variable.Name)) {
                    Statement.Variables.Add(new VariableInitializer(
                        variable.Name
                    ));
                    HoistedNames.Add(variable.Name);
                }
            }

            var replacement = new BlockStatement();
            foreach (var variable in variableDeclarationStatement.Variables) {
                replacement.Add(new ExpressionStatement(new AssignmentExpression {
                    Left = new IdentifierExpression(variable.Name),
                    Right = variable.Initializer.Clone()
                }));
            }

            if (replacement.Statements.Count == 1) {
                var firstChild = replacement.FirstChild;
                firstChild.Remove();
                variableDeclarationStatement.ReplaceWith(firstChild);
            } else if (replacement.Statements.Count > 1) {
                variableDeclarationStatement.ReplaceWith(replacement);
            }

            return null;
        }
    }
}

﻿using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.NRefactory.CSharp;

namespace JSIL {
    public class DeclarationHoister : ContextTrackingVisitor<object> {
        public readonly BlockStatement Output;
        public VariableDeclarationStatement Statement = null;
        public readonly HashSet<string> HoistedNames = new HashSet<string>();

        public DeclarationHoister (DecompilerContext context, BlockStatement output)
            : base(context) {

            Output = output;
        }

        public override object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) {
            if (Statement == null) {
                Statement = new VariableDeclarationStatement();
                Output.Add(Statement);
            }

            foreach (var variable in variableDeclarationStatement.Variables) {
                if (!HoistedNames.Contains(variable.Name)) {
                    Statement.Variables.Add(new VariableInitializer(
                        variable.Name
                    ));
                    HoistedNames.Add(variable.Name);
                }
            }

            var replacement = new BlockStatement();
            foreach (var variable in variableDeclarationStatement.Variables) {
                if (variable.IsNull)
                    continue;
                if (variable.Initializer.IsNull)
                    continue;

                replacement.Add(new ExpressionStatement(new AssignmentExpression {
                    Left = new IdentifierExpression(variable.Name),
                    Right = variable.Initializer.Clone()
                }));
            }

            if (replacement.Statements.Count == 1) {
                var firstChild = replacement.FirstChild;
                firstChild.Remove();
                variableDeclarationStatement.ReplaceWith(firstChild);
            } else if (replacement.Statements.Count > 1) {
                variableDeclarationStatement.ReplaceWith(replacement);
            } else {
                variableDeclarationStatement.Remove();
            }

            return null;
        }
    }
}

Fix hoisting of null initializers
Fix hoisting of null initializers
