protected internal override bool Walk(TryStatement node) { ExceptionBlock block = new ExceptionBlock(node); _tryBlocks.Push(block); WalkNode(node.Body); IList<CatchBlock> handlers = node.Handlers; if (handlers != null) { block.State = ExceptionBlock.TryStatementState.Handler; for (int handler = 0; handler < handlers.Count; handler++) { block.Handler = handler; WalkNode(handlers[handler].Body); } } if (node.FinallyStatement != null) { block.State = ExceptionBlock.TryStatementState.Finally; WalkNode(node.FinallyStatement); } Debug.Assert((object)block == (object)_tryBlocks.Peek()); _tryBlocks.Pop(); return false; }
// TryStatement protected internal override bool Walk(TryStatement node) { // The try body is guaranteed to be entered, but not completed, // the catch blocks are not guaranteed to be entered at all, // the finally block is guaranteed to be entered // // Any catch can be preceded by partial execution of try block, // so any 'damage' (deletes) the try block does must be affected // in the entry to the catch block. All catches have identical // starting situation. // // The finally can be preceded by partial execution of the try, // and at most one of the catches (any of them) so again, the // 'damage' the try and catch blocks do to the local state // affects the entry to the finally block. BitArray entry = _bits; _bits = new BitArray(_bits); // 1. Flow the body WalkNode(node.Body); entry.And(_bits); // 2. Flow the catch clauses, starting always with the initial state, // but also including the 'damage' that try block could have done. int handlerCount; if (node.Handlers != null && (handlerCount = node.Handlers.Count) > 0) { for (int i = 0; i < handlerCount; i++) { // Initialize the bits for flowing the catch clause _bits.SetAll(false); _bits.Or(entry); // Flow the catch clause and propagate the 'damage' to the state we'll use for finally. WalkNode(node.Handlers[i]); entry.And(_bits); } } // 3. Restore the state to the original (including the effects the body and catch clauses had) _bits = entry; // 4. Flow the finally clause, if present. if (node.FinallyStatement != null) { WalkNode(node.FinallyStatement); } return(false); }
// TryStatement private void DefaultWalk(TryStatement node) { if (Walk(node)) { WalkNode(node.Body); if (node.Handlers != null) { foreach (CatchBlock handler in node.Handlers) { WalkNode(handler); } } WalkNode(node.FinallyStatement); } PostWalk(node); }
// TryStatement private Statement Rewrite(TryStatement node) { Statement body = RewriteStatement(node.Body); ReadOnlyCollection <CatchBlock> handlers = node.Handlers; CatchBlock[] clone = null; if (handlers != null) { for (int i = 0; i < handlers.Count; i++) { CatchBlock handler = handlers[i]; CatchBlock rhandler = Rewrite(handler); if (((object)rhandler != (object)handler) && (clone == null)) { clone = Clone(handlers, i); } if (clone != null) { clone[i] = rhandler; } } } Statement @finally = RewriteStatement(node.FinallyStatement); if ((clone != null) || ((object)body != (object)node.Body) || ((object)@finally != (object)node.FinallyStatement)) { if (clone != null) { handlers = CollectionUtils.ToReadOnlyCollection(clone); } return(new TryStatement(node.Span, node.Header, body, handlers, @finally)); } else { return(node); } }
// TryStatement protected internal override bool Walk(TryStatement node) { // The try body is guaranteed to be entered, but not completed, // the catch blocks are not guaranteed to be entered at all, // the finally block is guaranteed to be entered // // Any catch can be preceded by partial execution of try block, // so any 'damage' (deletes) the try block does must be affected // in the entry to the catch block. All catches have identical // starting situation. // // The finally can be preceded by partial execution of the try, // and at most one of the catches (any of them) so again, the // 'damage' the try and catch blocks do to the local state // affects the entry to the finally block. BitArray entry = _bits; _bits = new BitArray(_bits); // 1. Flow the body WalkNode(node.Body); entry.And(_bits); // 2. Flow the catch clauses, starting always with the initial state, // but also including the 'damage' that try block could have done. int handlerCount; if (node.Handlers != null && (handlerCount = node.Handlers.Count) > 0) { for (int i = 0; i < handlerCount; i++) { // Initialize the bits for flowing the catch clause _bits.SetAll(false); _bits.Or(entry); // Flow the catch clause and propagate the 'damage' to the state we'll use for finally. WalkNode(node.Handlers[i]); entry.And(_bits); } } // 3. Restore the state to the original (including the effects the body and catch clauses had) _bits = entry; // 4. Flow the finally clause, if present. if (node.FinallyStatement != null) { WalkNode(node.FinallyStatement); } return false; }
public ExceptionBlock(TryStatement statement) { Debug.Assert(statement != null); _state = TryStatementState.Try; _statement = statement; }
protected internal override void PostWalk(TryStatement node) { _temps += node.GetGeneratorTempCount(); }