private void BuildTryBody(YieldExceptionHandlerInfo handlerInfo)
 {
     this.newTryBody     = new HashSet <ILogicalConstruct>();
     dummyVar0           = this.newTryBody.Add(this.entryOfTry);
     this.newFinallyBody = null;
     V_0 = new HashSet <ILogicalConstruct>();
     V_1 = new Queue <ILogicalConstruct>();
     V_2 = this.entryOfTry.get_SameParentSuccessors().GetEnumerator();
     try
     {
         while (V_2.MoveNext())
         {
             V_3 = (ILogicalConstruct)V_2.get_Current();
             V_1.Enqueue(V_3);
         }
     }
     finally
     {
         ((IDisposable)V_2).Dispose();
     }
     while (V_1.get_Count() > 0)
     {
         V_4 = V_1.Dequeue();
         if (!V_0.Add(V_4) || this.finallyBlocks.Contains(V_4))
         {
             continue;
         }
         this.ProcessCurrentNode(handlerInfo, V_1, V_4);
     }
     return;
 }
 private void MapBlocks()
 {
     V_0 = this.logicalBuilderContext.get_CFG().get_Blocks();
     V_1 = 0;
     while (V_1 < (int)V_0.Length)
     {
         V_2                = V_0[V_1];
         V_3                = V_2.get_First().get_Offset();
         stackVariable17    = this.logicalBuilderContext.get_CFGBlockToLogicalConstructMap();
         stackVariable20    = new CFGBlockLogicalConstruct[1];
         stackVariable20[0] = new CFGBlockLogicalConstruct(V_2, this.methodContext.get_Expressions().get_BlockExpressions().get_Item(V_3));
         stackVariable17.Add(V_2, stackVariable20);
         V_1 = V_1 + 1;
     }
     V_0 = this.logicalBuilderContext.get_CFG().get_Blocks();
     V_1 = 0;
     while (V_1 < (int)V_0.Length)
     {
         V_4 = V_0[V_1];
         V_5 = this.logicalBuilderContext.get_CFGBlockToLogicalConstructMap().get_Item(V_4)[0];
         V_6 = V_4.get_Successors();
         V_7 = 0;
         while (V_7 < (int)V_6.Length)
         {
             V_8 = V_6[V_7];
             V_9 = this.logicalBuilderContext.get_CFGBlockToLogicalConstructMap().get_Item(V_8)[0];
             V_5.AddToSuccessors(V_9);
             V_9.AddToPredecessors(V_5);
             V_7 = V_7 + 1;
         }
         V_1 = V_1 + 1;
     }
     return;
 }
        /// <summary>
        /// Generates the try/finally construct that is represented by the specifed exception handler info and attaches it to the logical tree.
        /// </summary>
        /// <param name="handlerInfo"></param>
        private void GenerateTryFinallyHandler(YieldExceptionHandlerInfo handlerInfo)
        {
            finallyBlocks = new HashSet <ILogicalConstruct>();

            entryOfTry = GetStateBeginBlockConstruct(handlerInfo.TryStates);

            BuildTryBody(handlerInfo);

            BlockLogicalConstruct newFinally;

            if (handlerInfo.HandlerType == YieldExceptionHandlerType.Method)
            {
                if (newFinallyBody == null)
                {
                    throw new Exception("Could not determine the end ot the try block");
                }

                RemoveExcessNodesFromTheTryBlock();

                ProcessFinallyNodes();

                newFinally = new BlockLogicalConstruct(newFinallyBody, new ILogicalConstruct[] { newFinallyBody });
            }
            else
            {
                newFinally = GenerateFinallyBlock();
            }

            BlockLogicalConstruct      newTry = new BlockLogicalConstruct(entryOfTry, newTryBody);
            TryFinallyLogicalConstruct newTryFinallyConstruct = new TryFinallyLogicalConstruct(newTry, newFinally);

            createdConstructsToIntervalMap[newTryFinallyConstruct] = handlerInfo;

            CleanUpOrderedNodes(newTryFinallyConstruct);
        }
        /// <summary>
        /// Builds the try body of the specified exception handler starting from the given entry node.
        /// </summary>
        /// <remarks>
        /// We assume that all nodes before reaching the finally block are in the try construct.
        /// </remarks>
        /// <param name="handlerInfo"></param>
        /// <param name="entryOfTry"></param>
        private void BuildTryBody(YieldExceptionHandlerInfo handlerInfo)
        {
            newTryBody = new HashSet <ILogicalConstruct>();
            newTryBody.Add(entryOfTry);
            newFinallyBody = null;

            HashSet <ILogicalConstruct> traversedNodes = new HashSet <ILogicalConstruct>();
            Queue <ILogicalConstruct>   bfsQueue       = new Queue <ILogicalConstruct>();

            foreach (ILogicalConstruct successor in entryOfTry.SameParentSuccessors)
            {
                bfsQueue.Enqueue(successor);
            }

            while (bfsQueue.Count > 0)
            {
                ILogicalConstruct currentNode = bfsQueue.Dequeue();
                if (!traversedNodes.Add(currentNode) || finallyBlocks.Contains(currentNode))
                {
                    continue;
                }

                ProcessCurrentNode(handlerInfo, bfsQueue, currentNode);
            }
        }
 private void ProcessMultiWayCFGPredecessor(CFGBlockLogicalConstruct finallyBody, InstructionBlock theBlock, InstructionBlock theNewSuccessor)
 {
     V_0 = finallyBody.get_TheBlock();
     V_2 = 0;
     while (V_2 < (int)theBlock.get_Successors().Length)
     {
         if (InstructionBlock.op_Equality(theBlock.get_Successors()[V_2], V_0))
         {
             theBlock.get_Successors()[V_2] = theNewSuccessor;
         }
         V_2 = V_2 + 1;
     }
     if (this.methodContext.get_ControlFlowGraph().get_SwitchBlocksInformation().TryGetValue(theBlock, out V_1))
     {
         V_3 = V_1.get_OrderedCasesArray();
         V_4 = 0;
         while (V_4 < (int)V_3.Length)
         {
             if (InstructionBlock.op_Equality(V_3[V_4], V_0))
             {
                 V_3[V_4] = theNewSuccessor;
             }
             V_4 = V_4 + 1;
         }
         if (InstructionBlock.op_Equality(V_1.get_DefaultCase(), V_0))
         {
             V_1.set_DefaultCase(theNewSuccessor);
         }
     }
     return;
 }
        /// <summary>
        /// Gets the first found entry CFGBlockLogicalConstruct for a state from the tryStates.
        /// </summary>
        /// <remarks>
        /// We try to get the first CFGBlockLC, that is going to be reached by the control flow, in which the state field is assigned to a state of the
        /// <paramref name="tryStates"/>. If the assignment is not at the begining of the CFGConstruct then we need to split it, since the try begins
        /// at the assignment.
        /// </remarks>
        /// <param name="tryStates"></param>
        /// <returns></returns>
        private CFGBlockLogicalConstruct GetStateBeginBlockConstruct(HashSet <int> tryStates)
        {
            for (int i = 0; i < this.orderedCFGNodes.Count; i++)
            {
                CFGBlockLogicalConstruct currentCFGConstruct = this.orderedCFGNodes[i];

                List <Expression> blockExpressions = currentCFGConstruct.LogicalConstructExpressions;
                for (int j = 0; j < blockExpressions.Count; j++)
                {
                    int value;
                    if (TryGetStateAssignValue(blockExpressions[j], out value) && tryStates.Contains(value))
                    {
                        if (j != 0)
                        {
                            KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> newCFGConstructsPair =
                                LogicalFlowUtilities.SplitCFGBlockAt(this.logicalContext, currentCFGConstruct, j);

                            this.orderedCFGNodes[i] = newCFGConstructsPair.Key;
                            this.orderedCFGNodes.Insert(i + 1, newCFGConstructsPair.Value);

                            return(newCFGConstructsPair.Value);
                        }
                        else
                        {
                            return(currentCFGConstruct);
                        }
                    }
                }
            }

            throw new Exception("Invalid state value");
        }
 private void GenerateTryFinallyHandler(YieldExceptionHandlerInfo handlerInfo)
 {
     this.finallyBlocks = new HashSet <ILogicalConstruct>();
     this.entryOfTry    = this.GetStateBeginBlockConstruct(handlerInfo.get_TryStates());
     this.BuildTryBody(handlerInfo);
     if (handlerInfo.get_HandlerType() != YieldExceptionHandlerType.Method)
     {
         V_0 = this.GenerateFinallyBlock();
     }
     else
     {
         if (this.newFinallyBody == null)
         {
             throw new Exception("Could not determine the end ot the try block");
         }
         this.RemoveExcessNodesFromTheTryBlock();
         this.ProcessFinallyNodes();
         stackVariable31    = this.newFinallyBody;
         stackVariable33    = new ILogicalConstruct[1];
         stackVariable33[0] = this.newFinallyBody;
         V_0 = new BlockLogicalConstruct(stackVariable31, stackVariable33);
     }
     V_1 = new TryFinallyLogicalConstruct(new BlockLogicalConstruct(this.entryOfTry, this.newTryBody), V_0);
     this.createdConstructsToIntervalMap.set_Item(V_1, handlerInfo);
     this.CleanUpOrderedNodes(V_1);
     return;
 }
        /// <summary>
        /// Changes the successors of the given instruction block to reflect the changes in the logical tree.
        /// </summary>
        /// <remarks>
        /// Also modifies switch data.
        /// Done because later substeps of the LogicalFlowBuilderStep depend on the successor information of the CFG
        /// (e.g. Determining the true and false successors of a ConditionLogicalConstruct, determining the cases of a switch/NWayConditional construct).
        /// </remarks>
        /// <param name="theCFGConstruct"></param>
        /// <param name="theCFGSuccessor"></param>
        private void ProcessMultiWayCFGPredecessor(CFGBlockLogicalConstruct finallyBody, InstructionBlock theBlock, InstructionBlock theNewSuccessor)
        {
            InstructionBlock theFinallyBlock = finallyBody.TheBlock;

            for (int i = 0; i < theBlock.Successors.Length; i++)
            {
                if (theBlock.Successors[i] == theFinallyBlock)
                {
                    theBlock.Successors[i] = theNewSuccessor;
                }
            }

            SwitchData switchData;

            if (methodContext.ControlFlowGraph.SwitchBlocksInformation.TryGetValue(theBlock, out switchData))
            {
                InstructionBlock[] theConditionCases = switchData.OrderedCasesArray;
                for (int i = 0; i < theConditionCases.Length; i++)
                {
                    if (theConditionCases[i] == theFinallyBlock)
                    {
                        theConditionCases[i] = theNewSuccessor;
                    }
                }

                if (switchData.DefaultCase == theFinallyBlock)
                {
                    switchData.DefaultCase = theNewSuccessor;
                }
            }
        }
        /// <summary>
        /// Generates the finally block.
        /// </summary>
        /// <remarks>
        /// Since the condition block and the dispose invocation block should have a common successor, a new EmptyBlockLogicalConstruct
        /// is added to the logical tree.
        /// </remarks>
        /// <returns></returns>
        private BlockLogicalConstruct GenerateFinallyBlock()
        {
            CFGBlockLogicalConstruct finallySuccessor = ProcessFinallyNode(finallyEntryBlock, disposeCallBlock);

            finallySuccessor.RemoveFromPredecessors(conditionBlock);
            conditionBlock.RemoveFromSuccessors(finallySuccessor);

            EmptyBlockLogicalConstruct emptyCommonNode = new EmptyBlockLogicalConstruct(++logicalContext.MaxBlockIndex);

            emptyCommonNode.AddToPredecessors(disposeCallBlock);
            emptyCommonNode.AddToPredecessors(conditionBlock);
            disposeCallBlock.AddToSuccessors(emptyCommonNode);
            conditionBlock.AddToSuccessors(emptyCommonNode);

            emptyCommonNode.Parent = finallyEntryBlock.Parent;
            emptyCommonNode.Parent.Children.Add(emptyCommonNode);

            for (int i = 0; i < conditionBlock.TheBlock.Successors.Length; i++)
            {
                if (conditionBlock.TheBlock.Successors[i] == finallySuccessor.TheBlock)
                {
                    conditionBlock.TheBlock.Successors[i] = null;
                }
            }

            finallyBlocks.Add(emptyCommonNode);
            return(new BlockLogicalConstruct(finallyEntryBlock, finallyBlocks));
        }
        /// <summary>
        /// Gets a string representation of the instruction block offset that this CFG block logical construct node represents.
        /// </summary>
        /// <remarks>
        /// If the <paramref name="node"/> is partial CFG block logical construct then the string representing its offset is:
        /// "{offset of the instruction block}_{partial construct index}"
        /// Where the partial construct index is the index of the partial construct in the <paramref name="context"/>.CFGBlockToLogicalConstructMap.
        /// </remarks>
        /// <param name="context"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        protected string NodeILOffset(LogicalFlowBuilderContext context, CFGBlockLogicalConstruct node)
        {
            if (node == null)
            {
                return("null");
            }

            //If the CFG construct is a partial block, the offset is: "blockOffset_indexOfPartialBlock"
            PartialCFGBlockLogicalConstruct partialNode = node as PartialCFGBlockLogicalConstruct;

            if (partialNode != null)
            {
                int indexOfPartialConstruct = Array.IndexOf(context.CFGBlockToLogicalConstructMap[partialNode.TheBlock], partialNode);

                if (indexOfPartialConstruct == -1)
                {
                    //sanity check
                    throw new Exception("Invalid partial block data.");
                }

                return(string.Format("IL_{0}_{1}", partialNode.TheBlock.First.Offset.ToString("x4"), indexOfPartialConstruct));
            }
            else
            {
                return(string.Format("IL_{0}", node.TheBlock.First.Offset.ToString("x4")));
            }
        }
Ejemplo n.º 11
0
 public PartialCFGBlockLogicalConstruct(CFGBlockLogicalConstruct originalCFGConstruct, IEnumerable <Expression> expressions)
 {
     base(originalCFGConstruct.get_TheBlock(), expressions);
     this.set_OriginalCFGConstruct(originalCFGConstruct);
     this.RedirectParent();
     return;
 }
 public static KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> SplitCFGBlockAt(LogicalFlowBuilderContext logicalContext, CFGBlockLogicalConstruct cfgBlock, int expressionIndex)
 {
     V_0 = cfgBlock.get_LogicalConstructExpressions();
     if (V_0 == null)
     {
         throw new ArgumentNullException("blockExpressions");
     }
     if (expressionIndex <= 0 || expressionIndex >= V_0.get_Count())
     {
         throw new ArgumentOutOfRangeException("expressionIndex");
     }
     V_1 = logicalContext.get_CFGBlockToLogicalConstructMap().get_Item(cfgBlock.get_TheBlock());
     V_2 = (int)V_1.Length;
     V_3 = 0;
     while (V_3 < V_2 && cfgBlock != V_1[V_3])
     {
         V_3 = V_3 + 1;
     }
     if (V_3 == V_2)
     {
         throw new ArgumentException("cfgBlock");
     }
     V_4 = cfgBlock.get_LogicalConstructExpressions().GetRange(0, expressionIndex);
     V_5 = new PartialCFGBlockLogicalConstruct(cfgBlock, V_4);
     V_5.RedirectPredecessors();
     V_6 = cfgBlock.get_LogicalConstructExpressions().GetRange(expressionIndex, V_0.get_Count() - expressionIndex);
     V_7 = new PartialCFGBlockLogicalConstruct(cfgBlock, V_6);
     V_7.RedirectSuccessors();
     V_5.AddToSuccessors(V_7);
     V_7.AddToPredecessors(V_5);
     V_8  = new CFGBlockLogicalConstruct[V_2 + 1];
     V_9  = 0;
     V_10 = 0;
     while (V_9 < V_2)
     {
         if (V_9 == V_3)
         {
             V_8[V_10]            = V_5;
             stackVariable68      = V_10 + 1;
             V_10                 = stackVariable68;
             V_8[stackVariable68] = V_7;
         }
         else
         {
             V_8[V_10] = V_1[V_9];
         }
         V_9  = V_9 + 1;
         V_10 = V_10 + 1;
     }
     logicalContext.get_CFGBlockToLogicalConstructMap().set_Item(cfgBlock.get_TheBlock(), V_8);
     return(new KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct>(V_5, V_7));
 }
        /// <summary>
        /// Gets the CFGBlockLC children of theBlock sorted in reverse post order.
        /// </summary>
        private void GetOrderedCFGNodes()
        {
            DFSTree dfsTree = DFSTBuilder.BuildTree(theBlock);

            foreach (DFSTNode node in dfsTree.ReversePostOrder)
            {
                CFGBlockLogicalConstruct cfgConstruct = node.Construct as CFGBlockLogicalConstruct;
                if (cfgConstruct != null)
                {
                    orderedCFGNodes.Add(cfgConstruct);
                }
            }
        }
        /// <summary>
        /// Redirect the predecessors and successors of the finally block.
        /// </summary>
        /// <remarks>
        /// Check if the finallyBlockEntry is only reachable by nodes in the try block.
        /// Make the successor of the finallyBlockEnd successor to all of the predecessors of the finallyBlockEntry.
        /// This will detach the finally block from the subgraph, which is a desired result since every normal finally block is not reachable from any where
        /// (the CLR takes care of executing the code in the finally block).
        /// </remarks>
        /// <param name="finallyBlockEntry"></param>
        /// <param name="finallyBlockEnd"></param>
        /// <returns>The successor of the finally block.</returns>
        private CFGBlockLogicalConstruct ProcessFinallyNode(CFGBlockLogicalConstruct finallyBlockEntry, CFGBlockLogicalConstruct finallyBlockEnd)
        {
            foreach (ILogicalConstruct predecessor in finallyBlockEntry.SameParentPredecessors)
            {
                if (!newTryBody.Contains(predecessor))
                {
                    throw new Exception("Invalid entry to the finally block");
                }
            }

            CFGBlockLogicalConstruct finallySuccessor;

            using (IEnumerator <CFGBlockLogicalConstruct> enumerator = finallyBlockEnd.CFGSuccessors.GetEnumerator())
            {
                enumerator.MoveNext();
                finallySuccessor = enumerator.Current;

                if (enumerator.MoveNext())
                {
                    throw new Exception("Invalid count of successors");
                }
            }

            HashSet <CFGBlockLogicalConstruct> finallyCFGPredecessors = new HashSet <CFGBlockLogicalConstruct>(finallyBlockEntry.CFGPredecessors);

            foreach (CFGBlockLogicalConstruct cfgPredecessor in finallyCFGPredecessors)
            {
                if (cfgPredecessor.TheBlock != finallyBlockEntry.TheBlock && cfgPredecessor.TheBlock.Successors.Length > 1)
                {
                    ProcessMultiWayCFGPredecessor(finallyBlockEntry, cfgPredecessor.TheBlock, finallySuccessor.TheBlock);
                }

                LogicalConstructBase currenConstruct = cfgPredecessor;
                while (currenConstruct != finallyBlockEntry.Parent)
                {
                    currenConstruct.RemoveFromSuccessors(finallyBlockEntry);
                    currenConstruct.AddToSuccessors(finallySuccessor);

                    currenConstruct = currenConstruct.Parent as LogicalConstructBase;
                }

                finallySuccessor.AddToPredecessors(cfgPredecessor);
                finallyBlockEntry.RemoveFromPredecessors(cfgPredecessor);
            }

            finallySuccessor.RemoveFromPredecessors(finallyBlockEnd);
            finallyBlockEnd.RemoveFromSuccessors(finallySuccessor);

            return(finallySuccessor);
        }
        /// <summary>
        /// Initializes the block logical construct representing the method body.
        /// </summary>
        private void InitializeTheBlock()
        {
            MapBlocks();

            CFGBlockLogicalConstruct entry = logicalBuilderContext.CFGBlockToLogicalConstructMap[logicalBuilderContext.CFG.Blocks[0]][0];

            HashSet <ILogicalConstruct> blockContents = new HashSet <ILogicalConstruct>();

            foreach (CFGBlockLogicalConstruct[] cfgBlocks in logicalBuilderContext.CFGBlockToLogicalConstructMap.Values)
            {
                blockContents.UnionWith(cfgBlocks);
            }

            theBlockLogicalConstruct = new BlockLogicalConstruct(entry, blockContents);
        }
Ejemplo n.º 16
0
 protected string NodeILOffset(LogicalFlowBuilderContext context, CFGBlockLogicalConstruct node)
 {
     if (node == null)
     {
         return("null");
     }
     V_0 = node as PartialCFGBlockLogicalConstruct;
     if (V_0 == null)
     {
         V_2 = node.get_TheBlock().get_First().get_Offset();
         return(String.Format("IL_{0}", V_2.ToString("x4")));
     }
     V_1 = Array.IndexOf <CFGBlockLogicalConstruct>(context.get_CFGBlockToLogicalConstructMap().get_Item(V_0.get_TheBlock()), V_0);
     if (V_1 == -1)
     {
         throw new Exception("Invalid partial block data.");
     }
     V_2 = V_0.get_TheBlock().get_First().get_Offset();
     return(String.Format("IL_{0}_{1}", V_2.ToString("x4"), V_1));
 }
        /// <summary>
        /// Splits each CFG construct that has more than one successor (i.e. condition block) and holds more than one expression.
        /// </summary>
        public void SplitConditionalCFGBlocks()
        {
            //We need to copy the dictionary, since the LogicalFlowUtilities.SplitCFGBlockAt method modifies it (and the enumerator explodes).
            //Also we copy it in a list, since we don't need the functionality of the dictionary.
            List <KeyValuePair <InstructionBlock, CFGBlockLogicalConstruct[]> > blockToConstructsPairList =
                new List <KeyValuePair <InstructionBlock, CFGBlockLogicalConstruct[]> >(logicalContext.CFGBlockToLogicalConstructMap);

            foreach (KeyValuePair <InstructionBlock, CFGBlockLogicalConstruct[]> blockToConstructsPair in blockToConstructsPairList)
            {
                if (blockToConstructsPair.Key.Successors.Length > 1)
                {
                    //For each instruction block there can be more than one partial CFG LC, so we take the last one, since it will hold the condition expression.
                    CFGBlockLogicalConstruct cfgConstruct = blockToConstructsPair.Value[blockToConstructsPair.Value.Length - 1];
                    if (cfgConstruct.LogicalConstructExpressions.Count > 1)
                    {
                        //If the last construct for this block holds more than one expression we split it at the last expression.
                        LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, cfgConstruct, cfgConstruct.LogicalConstructExpressions.Count - 1);
                    }
                }
            }
        }
 private void DetachFromLogicalTree(CFGBlockLogicalConstruct node)
 {
     if (node.get_CFGPredecessors().get_Count() > 0 || node.get_CFGSuccessors().get_Count() > 0)
     {
         throw new Exception("This node cannot be detached from the logical tree.");
     }
     dummyVar0 = node.get_Parent().get_Children().Remove(node);
     V_0       = this.logicalContext.get_CFGBlockToLogicalConstructMap().get_Item(node.get_TheBlock());
     if ((int)V_0.Length == 1)
     {
         if (V_0[0] != node)
         {
             throw new Exception("Logical tree is inconsistent.");
         }
         dummyVar1 = this.logicalContext.get_CFGBlockToLogicalConstructMap().Remove(node.get_TheBlock());
     }
     V_1 = new CFGBlockLogicalConstruct[(int)V_0.Length - 1];
     V_2 = 0;
     V_3 = 0;
     while (V_2 < (int)V_0.Length)
     {
         if (V_0[V_2] != node)
         {
             if (V_3 == (int)V_0.Length)
             {
                 throw new Exception("Logical tree is inconsistent.");
             }
             V_1[V_3] = V_0[V_2];
         }
         else
         {
             V_3 = V_3 - 1;
         }
         V_2 = V_2 + 1;
         V_3 = V_3 + 1;
     }
     this.logicalContext.get_CFGBlockToLogicalConstructMap().set_Item(node.get_TheBlock(), V_1);
     return;
 }
        private void DetachFromLogicalTree(CFGBlockLogicalConstruct node)
        {
            if (node.CFGPredecessors.Count > 0 || node.CFGSuccessors.Count > 0)
            {
                throw new Exception("This node cannot be detached from the logical tree.");
            }

            node.Parent.Children.Remove(node);
            CFGBlockLogicalConstruct[] cfgConstructsArray = logicalContext.CFGBlockToLogicalConstructMap[node.TheBlock];

            if (cfgConstructsArray.Length == 1)
            {
                if (cfgConstructsArray[0] != node)
                {
                    throw new Exception("Logical tree is inconsistent.");
                }

                logicalContext.CFGBlockToLogicalConstructMap.Remove(node.TheBlock);
            }

            CFGBlockLogicalConstruct[] newCFGConstructsArray = new CFGBlockLogicalConstruct[cfgConstructsArray.Length - 1];
            for (int i = 0, j = 0; i < cfgConstructsArray.Length; i++, j++)
            {
                if (cfgConstructsArray[i] == node)
                {
                    --j;
                    continue;
                }

                if (j == cfgConstructsArray.Length)
                {
                    throw new Exception("Logical tree is inconsistent.");
                }

                newCFGConstructsArray[j] = cfgConstructsArray[i];
            }

            logicalContext.CFGBlockToLogicalConstructMap[node.TheBlock] = newCFGConstructsArray;
        }
        /// <summary>
        /// Maps each CFG instruction blocks to a new CFGBlockLogicalConstruct, creating the relations between the new constructs and updating the logical builder
        /// context.
        /// </summary>
        private void MapBlocks()
        {
            //The new CFG logical constructs hold the block that they represent, and all the expressions that are for this block.
            foreach (InstructionBlock instructionBlock in logicalBuilderContext.CFG.Blocks)
            {
                int offset = instructionBlock.First.Offset;
                logicalBuilderContext.CFGBlockToLogicalConstructMap.Add(instructionBlock,
                                                                        new CFGBlockLogicalConstruct[] { new CFGBlockLogicalConstruct(instructionBlock, methodContext.Expressions.BlockExpressions[offset]) });
            }

            //After creating all the blocks, we can add the relations between them.
            foreach (InstructionBlock instructionBlock in logicalBuilderContext.CFG.Blocks)
            {
                CFGBlockLogicalConstruct logicalConstruct = logicalBuilderContext.CFGBlockToLogicalConstructMap[instructionBlock][0];

                foreach (InstructionBlock successorBlock in instructionBlock.Successors)
                {
                    CFGBlockLogicalConstruct successorConstruct = logicalBuilderContext.CFGBlockToLogicalConstructMap[successorBlock][0];
                    logicalConstruct.AddToSuccessors(successorConstruct);
                    successorConstruct.AddToPredecessors(logicalConstruct);
                }
            }
        }
        /// <summary>
        /// Determines whether or not there is a conditional dispose starting from this block.
        /// </summary>
        /// <remarks>
        /// Since the conditional dispose is the same as in the Dispose method, we are trying to find the same pattern.
        /// <code>
        /// this.stateField = nextState;
        /// (this.disposableField = this.enumeratorField as IDisposable;)   -- this might be missing
        /// if(this.disposableField != null)
        /// {
        ///     this.disposableField.Dispose();
        /// }
        /// </code>
        /// </remarks>
        /// <param name="yieldExceptionHandler"></param>
        /// <param name="startBlock"></param>
        /// <returns></returns>
        private bool TryProcessConditionalDisposeHandler(YieldExceptionHandlerInfo yieldExceptionHandler, CFGBlockLogicalConstruct startBlock)
        {
            if (finallyBlocks.Count > 0)
            {
                return(false);
            }

            if (!(startBlock is PartialCFGBlockLogicalConstruct) || startBlock.CFGSuccessors.Count != 1)
            {
                return(false);
            }

            if (startBlock.LogicalConstructExpressions.Count == 0)
            {
                return(false);
            }

            BinaryExpression stateAssignExpression = startBlock.LogicalConstructExpressions[0] as BinaryExpression;

            if (stateAssignExpression == null || !stateAssignExpression.IsAssignmentExpression ||
                stateAssignExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                (stateAssignExpression.Left as FieldReferenceExpression).Field.Resolve() != stateFieldRef ||
                stateAssignExpression.Right.CodeNodeType != CodeNodeType.LiteralExpression ||
                (int)((stateAssignExpression.Right as LiteralExpression).Value) != yieldExceptionHandler.NextState)
            {
                return(false);
            }

            if (startBlock.LogicalConstructExpressions.Count == 2 && yieldExceptionHandler.HandlerType == YieldExceptionHandlerType.ConditionalDispose)
            {
                BinaryExpression disposableAssignExpression = startBlock.LogicalConstructExpressions[1] as BinaryExpression;
                if (disposableAssignExpression == null || !disposableAssignExpression.IsAssignmentExpression ||
                    disposableAssignExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                    (disposableAssignExpression.Left as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField ||
                    disposableAssignExpression.Right.CodeNodeType != CodeNodeType.SafeCastExpression ||
                    (disposableAssignExpression.Right as SafeCastExpression).Expression.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                    ((disposableAssignExpression.Right as SafeCastExpression).Expression as FieldReferenceExpression).Field != yieldExceptionHandler.EnumeratorField)
                {
                    return(false);
                }
            }
            else if (startBlock.LogicalConstructExpressions.Count != 1 || yieldExceptionHandler.HandlerType != YieldExceptionHandlerType.SimpleConditionalDispose)
            {
                return(false);
            }


            CFGBlockLogicalConstruct conditionBlock;
            IEnumerator <CFGBlockLogicalConstruct> enumerator = startBlock.CFGSuccessors.GetEnumerator();

            using (enumerator)
            {
                enumerator.MoveNext();
                conditionBlock = enumerator.Current;
            }

            if (conditionBlock.LogicalConstructExpressions.Count != 1)
            {
                return(false);
            }

            BinaryExpression isNullCheckExpression = conditionBlock.LogicalConstructExpressions[0] as BinaryExpression;

            if (isNullCheckExpression == null || isNullCheckExpression.Operator != BinaryOperator.ValueEquality ||
                isNullCheckExpression.Left.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                (isNullCheckExpression.Left as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField ||
                isNullCheckExpression.Right.CodeNodeType != CodeNodeType.LiteralExpression ||
                (isNullCheckExpression.Right as LiteralExpression).Value != null)
            {
                return(false);
            }

            CFGBlockLogicalConstruct disposeCallBlock = null;

            foreach (ILogicalConstruct successor in conditionBlock.CFGSuccessors)
            {
                CFGBlockLogicalConstruct cfgSuccessor = successor as CFGBlockLogicalConstruct;
                if (cfgSuccessor != null && cfgSuccessor.CFGPredecessors.Count == 1)
                {
                    disposeCallBlock = cfgSuccessor;
                    break;
                }
            }

            if (disposeCallBlock == null || disposeCallBlock.LogicalConstructExpressions.Count != 1)
            {
                return(false);
            }

            MethodInvocationExpression disposeMethodInvocation = disposeCallBlock.LogicalConstructExpressions[0] as MethodInvocationExpression;

            if (disposeMethodInvocation == null || !disposeMethodInvocation.VirtualCall ||
                disposeMethodInvocation.MethodExpression.Target.CodeNodeType != CodeNodeType.FieldReferenceExpression ||
                (disposeMethodInvocation.MethodExpression.Target as FieldReferenceExpression).Field != yieldExceptionHandler.DisposableField ||
                disposeMethodInvocation.MethodExpression.Method.Name != "Dispose")
            {
                return(false);
            }

            this.finallyEntryBlock = startBlock;
            finallyBlocks.Add(startBlock);

            this.conditionBlock = conditionBlock;
            finallyBlocks.Add(conditionBlock);

            this.disposeCallBlock = disposeCallBlock;
            finallyBlocks.Add(disposeCallBlock);

            return(true);
        }
 /// <summary>
 /// Redirect the predecessors and successors of the finally node.
 /// </summary>
 /// <remarks>
 /// Check if the finally node is only reachable by nodes in the try block.
 /// Make the successor of the finally node successor to all of the predecessors of the finally node.
 /// This will detach the finally node from the subgraph, which is a desired result since every normal finally block is not reachable from any where
 /// (the CLR takes care of executing the code in the finally block).
 /// </remarks>
 /// <param name="finallyCFGBlock"></param>
 private void ProcessFinallyNode(CFGBlockLogicalConstruct finallyCFGBlock)
 {
     ProcessFinallyNode(finallyCFGBlock, finallyCFGBlock);
 }
        private bool TryProcessConditionalDisposeHandler(YieldExceptionHandlerInfo yieldExceptionHandler, CFGBlockLogicalConstruct startBlock)
        {
            if (this.finallyBlocks.get_Count() > 0)
            {
                return(false);
            }
            if (startBlock as PartialCFGBlockLogicalConstruct == null || startBlock.get_CFGSuccessors().get_Count() != 1)
            {
                return(false);
            }
            if (startBlock.get_LogicalConstructExpressions().get_Count() == 0)
            {
                return(false);
            }
            V_0 = startBlock.get_LogicalConstructExpressions().get_Item(0) as BinaryExpression;
            if (V_0 == null || !V_0.get_IsAssignmentExpression() || V_0.get_Left().get_CodeNodeType() != 30 || (V_0.get_Left() as FieldReferenceExpression).get_Field().Resolve() != this.stateFieldRef || V_0.get_Right().get_CodeNodeType() != 22 || (Int32)(V_0.get_Right() as LiteralExpression).get_Value() != yieldExceptionHandler.get_NextState())
            {
                return(false);
            }
            if (startBlock.get_LogicalConstructExpressions().get_Count() != 2 || yieldExceptionHandler.get_HandlerType() != 2)
            {
                if (startBlock.get_LogicalConstructExpressions().get_Count() != 1 || yieldExceptionHandler.get_HandlerType() != 1)
                {
                    return(false);
                }
            }
            else
            {
                V_6 = startBlock.get_LogicalConstructExpressions().get_Item(1) as BinaryExpression;
                if (V_6 == null || !V_6.get_IsAssignmentExpression() || V_6.get_Left().get_CodeNodeType() != 30 || (object)(V_6.get_Left() as FieldReferenceExpression).get_Field() != (object)yieldExceptionHandler.get_DisposableField() || V_6.get_Right().get_CodeNodeType() != 33 || (V_6.get_Right() as SafeCastExpression).get_Expression().get_CodeNodeType() != 30 || (object)((V_6.get_Right() as SafeCastExpression).get_Expression() as FieldReferenceExpression).get_Field() != (object)yieldExceptionHandler.get_EnumeratorField())
                {
                    return(false);
                }
            }
            V_2 = startBlock.get_CFGSuccessors().GetEnumerator();
            V_7 = V_2;
            try
            {
                dummyVar0 = V_2.MoveNext();
                V_1       = V_2.get_Current();
            }
            finally
            {
                if (V_7 != null)
                {
                    V_7.Dispose();
                }
            }
            if (V_1.get_LogicalConstructExpressions().get_Count() != 1)
            {
                return(false);
            }
            V_3 = V_1.get_LogicalConstructExpressions().get_Item(0) as BinaryExpression;
            if (V_3 == null || V_3.get_Operator() != 9 || V_3.get_Left().get_CodeNodeType() != 30 || (object)(V_3.get_Left() as FieldReferenceExpression).get_Field() != (object)yieldExceptionHandler.get_DisposableField() || V_3.get_Right().get_CodeNodeType() != 22 || (V_3.get_Right() as LiteralExpression).get_Value() != null)
            {
                return(false);
            }
            V_4 = null;
            V_8 = V_1.get_CFGSuccessors().GetEnumerator();
            try
            {
                while (V_8.MoveNext())
                {
                    V_9 = V_8.get_Current() as CFGBlockLogicalConstruct;
                    if (V_9 == null || V_9.get_CFGPredecessors().get_Count() != 1)
                    {
                        continue;
                    }
                    V_4 = V_9;
                    goto Label0;
                }
            }
            finally
            {
                ((IDisposable)V_8).Dispose();
            }
Label0:
            if (V_4 == null || V_4.get_LogicalConstructExpressions().get_Count() != 1)
            {
                return(false);
            }
            V_5 = V_4.get_LogicalConstructExpressions().get_Item(0) as MethodInvocationExpression;
            if (V_5 == null || !V_5.get_VirtualCall() || V_5.get_MethodExpression().get_Target().get_CodeNodeType() != 30 || (object)(V_5.get_MethodExpression().get_Target() as FieldReferenceExpression).get_Field() != (object)yieldExceptionHandler.get_DisposableField() || String.op_Inequality(V_5.get_MethodExpression().get_Method().get_Name(), "Dispose"))
            {
                return(false);
            }
            this.finallyEntryBlock = startBlock;
            dummyVar1             = this.finallyBlocks.Add(startBlock);
            this.conditionBlock   = V_1;
            dummyVar2             = this.finallyBlocks.Add(V_1);
            this.disposeCallBlock = V_4;
            dummyVar3             = this.finallyBlocks.Add(V_4);
            return(true);
        }
        /// <summary>
        /// Checks each a node before adding its successors to the <paramref name="bfsQueue"/>.
        /// </summary>
        /// <remarks>
        /// If the node is a CFGBlockLC and it contains the invocation of the finally method, or the entry of the finally block,
        /// then we should not continue the traversal.
        /// </remarks>
        /// <param name="handlerInfo"></param>
        /// <param name="bfsQueue"></param>
        /// <param name="currentNode"></param>
        private void ProcessCurrentNode(YieldExceptionHandlerInfo handlerInfo, Queue <ILogicalConstruct> bfsQueue, ILogicalConstruct currentNode)
        {
            if (currentNode is CFGBlockLogicalConstruct)
            {
                CFGBlockLogicalConstruct currentCFGNode = currentNode as CFGBlockLogicalConstruct;
                for (int i = 0; i < currentCFGNode.LogicalConstructExpressions.Count; i++)
                {
                    Expression currentExpression = currentCFGNode.LogicalConstructExpressions[i];

                    int value;
                    if (TryGetStateAssignValue(currentExpression, out value))
                    {
                        if (!handlerInfo.TryStates.Contains(value)) //sanity check
                        {
                            if (handlerInfo.HandlerType != YieldExceptionHandlerType.Method &&
                                TryProcessConditionalDisposeHandler(handlerInfo, currentCFGNode))
                            {
                                return;
                            }
                            throw new Exception("Invalid state value");
                        }
                    }
                    else if (handlerInfo.HandlerType == YieldExceptionHandlerType.Method &&
                             currentExpression.CodeNodeType == CodeNodeType.MethodInvocationExpression &&
                             (currentExpression as MethodInvocationExpression).MethodExpression.MethodDefinition == handlerInfo.FinallyMethodDefinition)
                    {
                        //For the finally block we need the CFGBlockLC that contains only the invocation of the finally method.
                        //That's why we need to split the CFGBlockLC, if there are other expressions besides the invocation.
                        CFGBlockLogicalConstruct currentFinallyBlock;
                        if (currentCFGNode.LogicalConstructExpressions.Count == 1)
                        {
                            if (newFinallyBody == null)
                            {
                                newFinallyBody = currentCFGNode;
                            }
                            finallyBlocks.Add(newFinallyBody);
                            orderedCFGNodes.Remove(currentCFGNode);
                            return;
                        }

                        if (i == 0)
                        {
                            KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> newConstructsPair =
                                LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i + 1);

                            currentFinallyBlock = newConstructsPair.Key;
                            orderedCFGNodes[orderedCFGNodes.IndexOf(currentCFGNode)] = newConstructsPair.Value;
                        }
                        else if (i < currentCFGNode.LogicalConstructExpressions.Count - 1)
                        {
                            KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> endOfTryPair =
                                LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i);
                            newTryBody.Add(endOfTryPair.Key);

                            KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> finallyRestOfBlockPair =
                                LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, endOfTryPair.Value, 1);

                            currentFinallyBlock = finallyRestOfBlockPair.Key;
                            orderedCFGNodes[orderedCFGNodes.IndexOf(currentCFGNode)] = finallyRestOfBlockPair.Value;
                        }
                        else // i == count - 1
                        {
                            KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> tryFinallyPair =
                                LogicalFlowUtilities.SplitCFGBlockAt(logicalContext, currentCFGNode, i);

                            newTryBody.Add(tryFinallyPair.Key);
                            currentFinallyBlock = tryFinallyPair.Value;

                            orderedCFGNodes.Remove(currentCFGNode);
                        }

                        if (newFinallyBody == null)
                        {
                            newFinallyBody = currentFinallyBlock;
                        }
                        finallyBlocks.Add(currentFinallyBlock);

                        return;
                    }
                }
            }
            else if (currentNode is TryFinallyLogicalConstruct)
            {
                TryFinallyLogicalConstruct tryFinallyConstruct = currentNode as TryFinallyLogicalConstruct;
                YieldExceptionHandlerInfo  oldHandlerInfo;
                if (createdConstructsToIntervalMap.TryGetValue(tryFinallyConstruct, out oldHandlerInfo) &&
                    oldHandlerInfo.TryStates.IsProperSupersetOf(handlerInfo.TryStates))
                {
                    throw new Exception("This try/finally construct cannot be nested in the current construct");
                }
            }

            newTryBody.Add(currentNode);
            foreach (ILogicalConstruct successor in currentNode.SameParentSuccessors)
            {
                bfsQueue.Enqueue(successor);
            }
        }
Ejemplo n.º 25
0
 public PartialCFGBlockLogicalConstruct(CFGBlockLogicalConstruct originalCFGConstruct, IEnumerable <Expression> expressions)
     : base(originalCFGConstruct.TheBlock, expressions)
 {
     OriginalCFGConstruct = originalCFGConstruct;
     RedirectParent();
 }
Ejemplo n.º 26
0
        /// <summary>
        /// Splits the given CFG construct into two partial constructs. The first containing the expressions with indices 0 to expressionIndex - 1, the second -
        /// expressionIndex to end. This method modifies the logicalContext.CFGBlockToLogicalConstructMap
        /// </summary>
        /// <param name="logicalContext"></param>
        /// <param name="cfgBlock"></param>
        /// <param name="expressionIndex"></param>
        /// <returns>A key value pair containing the first partial construct as key and the second as value.</returns>
        public static KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct> SplitCFGBlockAt(LogicalFlowBuilderContext logicalContext,
                                                                                                        CFGBlockLogicalConstruct cfgBlock, int expressionIndex)
        {
            List <Expression> blockExpressions = cfgBlock.LogicalConstructExpressions;

            if (blockExpressions == null)
            {
                throw new ArgumentNullException("blockExpressions");
            }

            if (expressionIndex <= 0 || expressionIndex >= blockExpressions.Count)
            {
                throw new ArgumentOutOfRangeException("expressionIndex");
            }

            CFGBlockLogicalConstruct[] instructionBlockConstructs = logicalContext.CFGBlockToLogicalConstructMap[cfgBlock.TheBlock];
            int cfgBlockArrayLength = instructionBlockConstructs.Length;

            int cfgBlockIndex;

            for (cfgBlockIndex = 0; cfgBlockIndex < cfgBlockArrayLength; cfgBlockIndex++)
            {
                if (cfgBlock == instructionBlockConstructs[cfgBlockIndex])
                {
                    break;
                }
            }

            if (cfgBlockIndex == cfgBlockArrayLength)
            {
                throw new ArgumentException("cfgBlock");
            }

            List <Expression> firstExpressionsList       = cfgBlock.LogicalConstructExpressions.GetRange(0, expressionIndex);
            PartialCFGBlockLogicalConstruct firstPartial = new PartialCFGBlockLogicalConstruct(cfgBlock, firstExpressionsList);

            firstPartial.RedirectPredecessors();

            List <Expression> secondExpressionsList       = cfgBlock.LogicalConstructExpressions.GetRange(expressionIndex, blockExpressions.Count - expressionIndex);
            PartialCFGBlockLogicalConstruct secondPartial = new PartialCFGBlockLogicalConstruct(cfgBlock, secondExpressionsList);

            secondPartial.RedirectSuccessors();

            firstPartial.AddToSuccessors(secondPartial);
            secondPartial.AddToPredecessors(firstPartial);

            CFGBlockLogicalConstruct[] updatedCollection = new CFGBlockLogicalConstruct[cfgBlockArrayLength + 1];
            for (int i = 0, j = 0; i < cfgBlockArrayLength; i++, j++)
            {
                if (i != cfgBlockIndex)
                {
                    updatedCollection[j] = instructionBlockConstructs[i];
                }
                else
                {
                    updatedCollection[j]   = firstPartial;
                    updatedCollection[++j] = secondPartial;
                }
            }

            logicalContext.CFGBlockToLogicalConstructMap[cfgBlock.TheBlock] = updatedCollection;

            return(new KeyValuePair <CFGBlockLogicalConstruct, CFGBlockLogicalConstruct>(firstPartial, secondPartial));
        }
 /// <summary>
 /// Adds the given CFG construct as a predecessor of this construct. This is the only legal way to do so.
 /// </summary>
 /// <param name="predecessor"></param>
 public void AddToPredecessors(CFGBlockLogicalConstruct predecessor)
 {
     predecessors.Add(predecessor);
 }
Ejemplo n.º 28
0
 public bool RemoveFromPredecessors(CFGBlockLogicalConstruct predecessor)
 {
     return(this.predecessors.Remove(predecessor));
 }
Ejemplo n.º 29
0
 public void AddToPredecessors(CFGBlockLogicalConstruct predecessor)
 {
     dummyVar0 = this.predecessors.Add(predecessor);
     return;
 }
        /// <summary>
        /// Gets a string representation of this logical construct.
        /// </summary>
        /// <remarks>
        /// Used for testing purposes.
        /// </remarks>
        /// <param name="constructName">The name of the construct.</param>
        /// <param name="printedCFGBlocks">A set containing all of the CFG block logical constructs that are already traversed.</param>
        /// <param name="context">The current logical flow builder context.</param>
        /// <returns></returns>
        protected virtual string ToString(string constructName, HashSet <CFGBlockLogicalConstruct> printedCFGBlocks, LogicalFlowBuilderContext context)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(constructName);
            sb.AppendLine("{");

            ILogicalConstruct[] cfgBlocksArray = GetSortedArrayFromCollection(this.CFGBlocks);

            Stack <CFGBlockLogicalConstruct> printingStack = new Stack <CFGBlockLogicalConstruct>();

            for (int i = 0; i < cfgBlocksArray.Length; i++)
            {
                CFGBlockLogicalConstruct currentCFGBlock = cfgBlocksArray[i] as CFGBlockLogicalConstruct;

                //If the current node is already printed we skip it.
                if (printedCFGBlocks.Contains(currentCFGBlock))
                {
                    continue;
                }

                //We use a stack to print the constructs in preorder.
                printingStack.Push(currentCFGBlock);
                while (printingStack.Count > 0)
                {
                    CFGBlockLogicalConstruct blockToPrint = printingStack.Pop();
                    if (printedCFGBlocks.Contains(blockToPrint))
                    {
                        continue;
                    }

                    //Foreach CFG construct that is not printed we get the parent (not necessarily direct) logical construct that is child of this construct
                    //(i.e. childConstructToPrint is the child of this construct that contains the blockToPrint).
                    ILogicalConstruct childConstructToPrint;
                    if (!LogicalFlowUtilities.TryGetParentConstructWithGivenParent(blockToPrint, this, out childConstructToPrint))
                    {
                        continue;
                    }

                    string childString = ((LogicalConstructBase)childConstructToPrint).ToString(childConstructToPrint.GetType().Name, printedCFGBlocks, context);

                    //Indent each line of child's strings by one tab, so that they appear visually better
                    string[] childStringLines = childString.Split(new String[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string line in childStringLines)
                    {
                        sb.AppendLine(string.Format("\t{0}", line));
                    }

                    //We get a sorted array ot the child's same parent successors and we push their CFG logical construct entries in reverse order on the
                    //printing stack, so that the closest successor is going to be printed next.
                    ILogicalConstruct[] sameParentSuccessors = GetSortedArrayFromCollection(childConstructToPrint.SameParentSuccessors);

                    for (int j = sameParentSuccessors.Length - 1; j >= 0; j--)
                    {
                        if (!printedCFGBlocks.Contains(sameParentSuccessors[j].FirstBlock))
                        {
                            printingStack.Push(sameParentSuccessors[j].FirstBlock);
                        }
                    }
                }
            }

            string followNodeString = string.Format("\tFollowNode: {0}", NodeILOffset(context, CFGFollowNode));

            sb.AppendLine(followNodeString);
            sb.AppendLine("}");
            return(sb.ToString());
        }