private static T ForEachChild()

in Public/Src/FrontEnd/TypeScript.Net/TypeScript.Net/Printing/NodeWalkerEx.cs [123:632]


        private static T ForEachChild<T>(INode node, Func<NodeOrNodesOrNull, T> cbNode, Func<NodeOrNodesOrNull, T> cbNodeArray = null) where T : class
        {
            if (node == null)
            {
                return default(T);
            }

            // The visitXXX functions could be written as local functions that close over the cbNode and cbNodeArray
            // callback parameters, but that causes a closure allocation for each invocation with noticeable effects
            // on performance.
            Func<Func<NodeOrNodesOrNull, T>, INodeArray<INode>, T> visitNodes = cbNodeArray != null
                ? (Func<Func<NodeOrNodesOrNull, T>, INodeArray<INode>, T>)VisitNodeArray
                : VisitEachNode;

            var cbNodes = cbNodeArray ?? cbNode;
            switch (node.Kind)
            {
                case SyntaxKind.QualifiedName:
                    {
                        var concreteNode = node.Cast<IQualifiedName>();
                        return VisitNode(cbNode, concreteNode.Left) ??
                                VisitNode(cbNode, concreteNode.Right);
                    }

                case SyntaxKind.TypeParameter:
                    {
                        var concreteNode = node.Cast<ITypeParameterDeclaration>();
                        return VisitNode(cbNode, concreteNode.Name) ??
                            VisitNode(cbNode, concreteNode.Constraint) ??
                            VisitNode(cbNode, concreteNode.Expression);
                    }

                case SyntaxKind.ShorthandPropertyAssignment:
                    {
                        var concreteNode = node.Cast<IShorthandPropertyAssignment>();
                        return visitNodes(cbNodes, node.Decorators) ??
                                                    visitNodes(cbNodes, node.Modifiers) ??
                                                    VisitNode(cbNode, concreteNode.Name) ??
                                                    VisitNode(cbNode, concreteNode.QuestionToken.ValueOrDefault) ??
                                                    VisitNode(cbNode, concreteNode.EqualsToken.ValueOrDefault) ??
                                                    VisitNode(cbNode, concreteNode.ObjectAssignmentInitializer);
                    }

                case SyntaxKind.Parameter:
                case SyntaxKind.PropertyDeclaration:
                case SyntaxKind.PropertySignature:
                case SyntaxKind.PropertyAssignment:
                case SyntaxKind.VariableDeclaration:
                case SyntaxKind.BindingElement:
                    {
                        var concreteNode = node.Cast<IVariableLikeDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.PropertyName) ??
                           VisitNode(cbNode, concreteNode.DotDotDotToken.ValueOrDefault) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.QuestionToken.ValueOrDefault) ??
                           VisitNode(cbNode, concreteNode.Type) ??
                           VisitNode(cbNode, concreteNode.Initializer);
                    }

                case SyntaxKind.FunctionType:
                case SyntaxKind.ConstructorType:
                case SyntaxKind.CallSignature:
                case SyntaxKind.ConstructSignature:
                case SyntaxKind.IndexSignature:
                    {
                        var concreteNode = node.Cast<ISignatureDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           visitNodes(cbNodes, concreteNode.TypeParameters) ??
                           visitNodes(cbNodes, concreteNode.Parameters) ??
                           VisitNode(cbNode, concreteNode.Type);
                    }

                case SyntaxKind.MethodDeclaration:
                case SyntaxKind.MethodSignature:
                case SyntaxKind.Constructor:
                case SyntaxKind.GetAccessor:
                case SyntaxKind.SetAccessor:
                case SyntaxKind.FunctionExpression:
                case SyntaxKind.FunctionDeclaration:
                case SyntaxKind.ArrowFunction:
                    {
                        var concreteNode = node.Cast<IFunctionLikeDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.AsteriskToken.ValueOrDefault) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.QuestionToken.ValueOrDefault) ??
                           visitNodes(cbNodes, concreteNode.TypeParameters) ??
                           visitNodes(cbNodes, concreteNode.Parameters) ??
                           VisitNode(cbNode, concreteNode.Type) ??
                           VisitNode(cbNode, node.As<IArrowFunction>()?.EqualsGreaterThanToken) ??
                           VisitNode(cbNode, concreteNode.Body);
                    }

                case SyntaxKind.TypeReference:
                    {
                        var concreteNode = node.Cast<ITypeReferenceNode>();
                        return VisitNode(cbNode, concreteNode.TypeName) ??
                               visitNodes(cbNodes, concreteNode.TypeArguments);
                    }

                case SyntaxKind.TypePredicate:
                    {
                        var concreteNode = node.Cast<ITypePredicateNode>();
                        return VisitNode(cbNode, concreteNode.ParameterName) ??
                           VisitNode(cbNode, concreteNode.Type);
                    }

                case SyntaxKind.TypeQuery:
                    return VisitNode(cbNode, node.Cast<ITypeQueryNode>().ExprName);
                case SyntaxKind.TypeLiteral:
                    return visitNodes(cbNodes, node.Cast<ITypeLiteralNode>().Members);
                case SyntaxKind.ArrayType:
                    return VisitNode(cbNode, node.Cast<IArrayTypeNode>().ElementType);
                case SyntaxKind.TupleType:
                    return visitNodes(cbNodes, node.Cast<ITupleTypeNode>().ElementTypes);
                case SyntaxKind.UnionType:
                case SyntaxKind.IntersectionType:
                    return visitNodes(cbNodes, node.Cast<IUnionOrIntersectionTypeNode>().Types);
                case SyntaxKind.ParenthesizedType:
                    return VisitNode(cbNode, node.Cast<IParenthesizedTypeNode>().Type);
                case SyntaxKind.ObjectBindingPattern:
                case SyntaxKind.ArrayBindingPattern:
                    return visitNodes(cbNodes, node.Cast<IBindingPattern>().Elements);
                case SyntaxKind.ArrayLiteralExpression:
                    return visitNodes(cbNodes, node.Cast<IArrayLiteralExpression>().Elements);
                case SyntaxKind.ObjectLiteralExpression:
                    return visitNodes(cbNodes, node.Cast<IObjectLiteralExpression>().Properties);
                case SyntaxKind.PropertyAccessExpression:
                    {
                        var concreteNode = node.Cast<IPropertyAccessExpression>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.DotToken) ??
                           VisitNode(cbNode, concreteNode.Name);
                    }

                case SyntaxKind.ElementAccessExpression:
                    {
                        var concreteNode = node.Cast<IPropertyAccessExpression>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, node.Cast<IElementAccessExpression>().ArgumentExpression);
                    }

                case SyntaxKind.CallExpression:
                case SyntaxKind.NewExpression:
                    {
                        var concreteNode = node.Cast<ICallExpression>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           visitNodes(cbNodes, concreteNode.TypeArguments) ??
                           visitNodes(cbNodes, concreteNode.Arguments);
                    }

                case SyntaxKind.TaggedTemplateExpression:
                    {
                        var concreteNode = node.Cast<ITaggedTemplateExpression>();
                        return VisitNode(cbNode, concreteNode.Tag) ??
                           VisitNode(cbNode, concreteNode.TemplateExpression);
                    }

                case SyntaxKind.TypeAssertionExpression:
                    {
                        var concreteNode = node.Cast<ITypeAssertion>();
                        return VisitNode(cbNode, concreteNode.Type) ??
                           VisitNode(cbNode, concreteNode.Expression);
                    }

                case SyntaxKind.ParenthesizedExpression:
                    return VisitNode(cbNode, node.Cast<IParenthesizedExpression>().Expression);
                case SyntaxKind.DeleteExpression:
                    return VisitNode(cbNode, node.Cast<IDeleteExpression>().Expression);
                case SyntaxKind.TypeOfExpression:
                    return VisitNode(cbNode, node.Cast<ITypeOfExpression>().Expression);
                case SyntaxKind.VoidExpression:
                    return VisitNode(cbNode, node.Cast<IVoidExpression>().Expression);
                case SyntaxKind.PrefixUnaryExpression:
                    return VisitNode(cbNode, node.Cast<IPrefixUnaryExpression>().Operand);
                case SyntaxKind.YieldExpression:
                    {
                        var concreteNode = node.Cast<IYieldExpression>();
                        return VisitNode(cbNode, concreteNode.AsteriskToken) ??
                           VisitNode(cbNode, concreteNode.Expression);
                    }

                case SyntaxKind.AwaitExpression:
                    return VisitNode(cbNode, node.Cast<IAwaitExpression>().Expression);
                case SyntaxKind.PostfixUnaryExpression:
                    return VisitNode(cbNode, node.Cast<IPostfixUnaryExpression>().Operand);
                case SyntaxKind.BinaryExpression:
                    {
                        var concreteNode = node.Cast<IBinaryExpression>();
                        return VisitNode(cbNode, concreteNode.Left) ??
                           VisitNode(cbNode, concreteNode.OperatorToken) ??
                           VisitNode(cbNode, concreteNode.Right);
                    }

                case SyntaxKind.AsExpression:
                    {
                        var concreteNode = node.Cast<IAsExpression>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.Type);
                    }

                case SyntaxKind.ConditionalExpression:
                    {
                        var concreteNode = node.Cast<IConditionalExpression>();
                        return VisitNode(cbNode, concreteNode.Condition) ??
                           VisitNode(cbNode, concreteNode.QuestionToken) ??
                           VisitNode(cbNode, concreteNode.WhenTrue) ??
                           VisitNode(cbNode, concreteNode.ColonToken) ??
                           VisitNode(cbNode, concreteNode.WhenFalse);
                    }
                    
                case SyntaxKind.SwitchExpression:
                    {
                        var concreteNode = node.Cast<ISwitchExpression>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                            visitNodes(cbNode, concreteNode.Clauses);
                    }
                case SyntaxKind.SwitchExpressionClause:
                    {
                        var concreteNode = node.Cast<ISwitchExpressionClause>();
                        return (concreteNode.IsDefaultFallthrough ? null : VisitNode(cbNode, concreteNode.Match)) ??
                           VisitNode(cbNode, concreteNode.Expression);
                    }

                case SyntaxKind.SpreadElementExpression:
                    return VisitNode(cbNode, node.Cast<ISpreadElementExpression>().Expression);
                case SyntaxKind.Block:
                case SyntaxKind.ModuleBlock:
                    return visitNodes(cbNodes, node.Cast<IBlock>().Statements);
                case SyntaxKind.SourceFile:
                    {
                        var concreteNode = node.Cast<ISourceFile>();
                        return visitNodes(cbNodes, concreteNode.Statements) ??
                           VisitNode(cbNode, concreteNode.EndOfFileToken);
                    }

                case SyntaxKind.VariableStatement:
                    {
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, node.Cast<IVariableStatement>().DeclarationList);
                    }

                case SyntaxKind.VariableDeclarationList:
                    return visitNodes(cbNodes, node.Cast<IVariableDeclarationList>().Declarations);
                case SyntaxKind.ExpressionStatement:
                    return VisitNode(cbNode, node.Cast<IExpressionStatement>().Expression);
                case SyntaxKind.IfStatement:
                    {
                        var concreteNode = node.Cast<IIfStatement>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.ThenStatement) ??
                           VisitNode(cbNode, concreteNode.ElseStatement.ValueOrDefault);
                    }

                case SyntaxKind.DoStatement:
                    {
                        var concreteNode = node.Cast<IDoStatement>();
                        return VisitNode(cbNode, concreteNode.Statement) ??
                           VisitNode(cbNode, concreteNode.Expression);
                    }

                case SyntaxKind.WhileStatement:
                    {
                        var concreteNode = node.Cast<IWhileStatement>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.ForStatement:
                    {
                        var concreteNode = node.Cast<IForStatement>();
                        return VisitNode(cbNode, concreteNode.Initializer) ??
                           VisitNode(cbNode, concreteNode.Condition) ??
                           VisitNode(cbNode, concreteNode.Incrementor) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.ForInStatement:
                    {
                        var concreteNode = node.Cast<IForInStatement>();
                        return VisitNode(cbNode, concreteNode.Initializer) ??
                           VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.ForOfStatement:
                    {
                        var concreteNode = node.Cast<IForOfStatement>();
                        return VisitNode(cbNode, concreteNode.Initializer) ??
                           VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.ContinueStatement:
                case SyntaxKind.BreakStatement:
                    return VisitNode(cbNode, node.Cast<IBreakOrContinueStatement>().Label);
                case SyntaxKind.ReturnStatement:
                    return VisitNode(cbNode, node.Cast<IReturnStatement>().Expression);
                case SyntaxKind.WithStatement:
                    {
                        var concreteNode = node.Cast<IWithStatement>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.SwitchStatement:
                    {
                        var concreteNode = node.Cast<ISwitchStatement>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           VisitNode(cbNode, concreteNode.CaseBlock);
                    }

                case SyntaxKind.CaseBlock:
                    return visitNodes(cbNodes, node.Cast<ICaseBlock>().Clauses);
                case SyntaxKind.CaseClause:
                    {
                        var concreteNode = node.Cast<ICaseClause>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                             visitNodes(cbNodes, concreteNode.Statements);
                    }

                case SyntaxKind.DefaultClause:
                    return visitNodes(cbNodes, node.Cast<IDefaultClause>().Statements);
                case SyntaxKind.LabeledStatement:
                    {
                        var concreteNode = node.Cast<ILabeledStatement>();
                        return VisitNode(cbNode, concreteNode.Label) ??
                           VisitNode(cbNode, concreteNode.Statement);
                    }

                case SyntaxKind.ThrowStatement:
                    return VisitNode(cbNode, node.Cast<IThrowStatement>().Expression);
                case SyntaxKind.TryStatement:
                    {
                        var concreteNode = node.Cast<ITryStatement>();
                        return VisitNode(cbNode, concreteNode.TryBlock) ??
                           VisitNode(cbNode, concreteNode.CatchClause) ??
                           VisitNode(cbNode, concreteNode.FinallyBlock);
                    }

                case SyntaxKind.CatchClause:
                    {
                        var concreteNode = node.Cast<ICatchClause>();
                        return VisitNode(cbNode, concreteNode.VariableDeclaration) ??
                           VisitNode(cbNode, concreteNode.Block);
                    }

                case SyntaxKind.Decorator:
                    return VisitNode(cbNode, node.Cast<IDecorator>().Expression);
                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.ClassExpression:
                    {
                        var concreteNode = node.Cast<IClassLikeDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           visitNodes(cbNodes, concreteNode.TypeParameters) ??
                           visitNodes(cbNodes, concreteNode.HeritageClauses) ??
                           visitNodes(cbNodes, concreteNode.Members);
                    }

                case SyntaxKind.InterfaceDeclaration:
                    {
                        var concreteNode = node.Cast<IInterfaceDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           visitNodes(cbNodes, concreteNode.TypeParameters) ??
                           visitNodes(cbNodes, concreteNode.HeritageClauses) ??
                           visitNodes(cbNodes, concreteNode.Members);
                    }

                case SyntaxKind.TypeAliasDeclaration:
                    {
                        var concreteNode = node.Cast<ITypeAliasDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           visitNodes(cbNodes, concreteNode.TypeParameters) ??
                           VisitNode(cbNode, concreteNode.Type);
                    }

                case SyntaxKind.EnumDeclaration:
                    {
                        var concreteNode = node.Cast<IEnumDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           visitNodes(cbNodes, concreteNode.Members);
                    }

                case SyntaxKind.EnumMember:
                    {
                        var concreteNode = node.Cast<IEnumMember>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.Initializer.ValueOrDefault);
                    }

                case SyntaxKind.ModuleDeclaration:
                    {
                        var concreteNode = node.Cast<IModuleDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.Body);
                    }

                case SyntaxKind.ImportEqualsDeclaration:
                    {
                        var concreteNode = node.Cast<IImportEqualsDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.ModuleReference);
                    }

                case SyntaxKind.ImportDeclaration:
                    {
                        var concreteNode = node.Cast<IImportDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, concreteNode.ImportClause) ??
                           VisitNode(cbNode, concreteNode.ModuleSpecifier);
                    }

                case SyntaxKind.ImportClause:
                    {
                        var concreteNode = node.Cast<IImportClause>();
                        return VisitNode(cbNode, concreteNode.Name) ??
                           VisitNode(cbNode, concreteNode.NamedBindings);
                    }

                case SyntaxKind.NamespaceImport:
                    return VisitNode(cbNode, node.Cast<INamespaceImport>().Name);
                case SyntaxKind.NamedImports:
                    return visitNodes(cbNodes, node.Cast<INamedImports>().Elements);
                case SyntaxKind.NamedExports:
                    return visitNodes(cbNodes, node.Cast<INamedExports>().Elements);
                case SyntaxKind.ExportDeclaration:
                    {
                        var concreteNode = node.Cast<IExportDeclaration>();
                        return visitNodes(cbNodes, node.Decorators) ??
                               visitNodes(cbNodes, node.Modifiers) ??
                               VisitNode(cbNode, concreteNode.ExportClause) ??
                               VisitNode(cbNode, concreteNode.ModuleSpecifier);
                    }

                case SyntaxKind.ImportSpecifier:
                    {
                        var concreteNode = node.Cast<IImportSpecifier>();
                        return VisitNode(cbNode, concreteNode.PropertyName) ??
                           VisitNode(cbNode, concreteNode.Name);
                    }

                case SyntaxKind.ExportSpecifier:
                    {
                        var concreteNode = node.Cast<IExportSpecifier>();
                        return VisitNode(cbNode, concreteNode.PropertyName) ??
                           VisitNode(cbNode, concreteNode.Name);
                    }

                case SyntaxKind.ExportAssignment:
                    {
                        return visitNodes(cbNodes, node.Decorators) ??
                           visitNodes(cbNodes, node.Modifiers) ??
                           VisitNode(cbNode, node.Cast<IExportAssignment>().Expression);
                    }

                case SyntaxKind.TemplateExpression:
                    {
                        var concreteNode = node.Cast<ITemplateExpression>();
                        return VisitNode(cbNode, concreteNode.Head) ??
                        visitNodes(cbNodes, concreteNode.TemplateSpans);
                    }

                case SyntaxKind.TemplateSpan:
                    {
                        var concreteNode = node.Cast<ITemplateSpan>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                        VisitNode(cbNode, concreteNode.Literal);
                    }

                case SyntaxKind.ComputedPropertyName:
                    return VisitNode(cbNode, node.Cast<IComputedPropertyName>().Expression);
                case SyntaxKind.HeritageClause:
                    return visitNodes(cbNodes, node.Cast<IHeritageClause>().Types);
                case SyntaxKind.ExpressionWithTypeArguments:
                    {
                        var concreteNode = node.Cast<IExpressionWithTypeArguments>();
                        return VisitNode(cbNode, concreteNode.Expression) ??
                           visitNodes(cbNodes, concreteNode.TypeArguments);
                    }

                case SyntaxKind.ExternalModuleReference:
                    return VisitNode(cbNode, node.Cast<IExternalModuleReference>().Expression);
                case SyntaxKind.MissingDeclaration:
                    return visitNodes(cbNodes, node.Decorators);
                case SyntaxKind.StringLiteralType:
                    // DScript-specific: decorators on string literal types
                    return visitNodes(cbNodes, node.Decorators);
            }

            return default(T);
        }