src/Shared/EntityFramework/Core/Query/InternalTrees/RuleProcessor.cs
// <summary>
// Apply rules to the current subtree in a bottom-up fashion.
// </summary>
// <param name="context"> Current rule processing context </param>
// <param name="rules"> The look-up table with the rules to be applied </param>
// <param name="subTreeRoot"> Current subtree </param>
// <param name="parent"> Parent node </param>
// <param name="childIndexInParent"> Index of this child within the parent </param>
// <returns> the result of the transformation </returns>
Apply rules to the current subtree in a bottom-up fashion.
Apply rules to the current subtree in a bottom - up fashion .
private Node ApplyRulesToSubtree(
            RuleProcessingContext context,
            ReadOnlyCollection<ReadOnlyCollection<Rule>> rules,
            Node subTreeRoot, Node parent, int childIndexInParent)
        {
            var loopCount = 0;
            var localProcessedMap = new Dictionary<SubTreeId, SubTreeId>();
            SubTreeId subTreeId;
            while (true)
            {
                Debug.Assert(loopCount < 12, "endless loops?");
                loopCount++;
                 We may need to update state regardless of whether this subTree has 
                 changed after it has been processed last. For example, it may be 
                 affected by transformation in its siblings due to external references.
                context.PreProcessSubTree(subTreeRoot);
                subTreeId = new SubTreeId(context, subTreeRoot, parent, childIndexInParent);
                 Have I seen this subtree already? Just return, if so
                if (m_processedNodeMap.ContainsKey(subTreeId))
                {
                    break;
                }
                 Avoid endless loops here - avoid cycles of 2 or more
                if (localProcessedMap.ContainsKey(subTreeId))
                {
                     mark this subtree as processed
                    m_processedNodeMap[subTreeId] = subTreeId;
                    break;
                }
                 Keep track of this one
                localProcessedMap[subTreeId] = subTreeId;
                 Walk my children
                for (var i = 0; i < subTreeRoot.Children.Count; i++)
                {
                    var childNode = subTreeRoot.Children[i];
                    if (ShouldApplyRules(childNode, subTreeRoot))
                    {
                        subTreeRoot.Children[i] = ApplyRulesToSubtree(context, rules, childNode, subTreeRoot, i);
                    }
                }
                 Apply rules to myself. If no transformations were performed, 
                 then mark this subtree as processed, and break out
                Node newSubTreeRoot;
                if (!ApplyRulesToNode(context, rules, subTreeRoot, out newSubTreeRoot))
                {
                    Debug.Assert(subTreeRoot == newSubTreeRoot);
                     mark this subtree as processed
                    m_processedNodeMap[subTreeId] = subTreeId;
                    break;
                }
                context.PostProcessSubTree(subTreeRoot);
                subTreeRoot = newSubTreeRoot;
            }
            context.PostProcessSubTree(subTreeRoot);
            return subTreeRoot;
        }
private Node ApplyRulesToSubtree ( RuleProcessingContext context , ReadOnlyCollection < ReadOnlyCollection < Rule > > rules , Node subTreeRoot , Node parent , int childIndexInParent ) { var loopCount = 0 ; var localProcessedMap = new Dictionary < SubTreeId , SubTreeId > ( ) ; SubTreeId subTreeId ; while ( true ) { Debug . Assert ( loopCount < 12 , " " ) ; loopCount ++ ; context . PreProcessSubTree ( subTreeRoot ) ; subTreeId = new SubTreeId ( context , subTreeRoot , parent , childIndexInParent ) ; if ( m_processedNodeMap . ContainsKey ( subTreeId ) ) { break ; } if ( localProcessedMap . ContainsKey ( subTreeId ) ) { m_processedNodeMap [ subTreeId ] = subTreeId ; break ; } localProcessedMap [ subTreeId ] = subTreeId ; for ( var i = 0 ; i < subTreeRoot . Children . Count ; i ++ ) { var childNode = subTreeRoot . Children [ i ] ; if ( ShouldApplyRules ( childNode , subTreeRoot ) ) { subTreeRoot . Children [ i ] = ApplyRulesToSubtree ( context , rules , childNode , subTreeRoot , i ) ; } } Node newSubTreeRoot ; if ( ! ApplyRulesToNode ( context , rules , subTreeRoot , out newSubTreeRoot ) ) { Debug . Assert ( subTreeRoot == newSubTreeRoot ) ; m_processedNodeMap [ subTreeId ] = subTreeId ; break ; } context . PostProcessSubTree ( subTreeRoot ) ; subTreeRoot = newSubTreeRoot ; } context . PostProcessSubTree ( subTreeRoot ) ; return subTreeRoot ; }
Apply rules to the current subtree in a bottom-up fashion.
Apply rules to the current subtree in a bottom - up fashion .
// Am I looping forever // // We may need to update state regardless of whether this subTree has  // changed after it has been processed last. For example, it may be  // affected by transformation in its siblings due to external references. // // Have I seen this subtree already? Just return, if so // Avoid endless loops here - avoid cycles of 2 or more // mark this subtree as processed // Keep track of this one // Walk my children // Apply rules to myself. If no transformations were performed,  // then mark this subtree as processed, and break out // mark this subtree as processed
the result of the transformation
the result of the transformation
context
RuleProcessingContext
Current rule processing context
Current rule processing context
rules
ReadOnlyCollection<ReadOnlyCollection<Rule>>
The look-up table with the rules to be applied
The look - up table with the rules to be applied
subTreeRoot
Node
None
parent
Node
None
childIndexInParent
int
Index of this child within the parent
Index of this child within the parent