protected override void VisitFinallyBlock(BoundStatement finallyBlock, ref LocalState endState) { var oldPending1 = SavePending(); // we do not support branches into a finally block var oldPending2 = SavePending(); // track only the branches out of the finally block base.VisitFinallyBlock(finallyBlock, ref endState); RestorePending(oldPending2); // resolve branches that remain within the finally block foreach (var branch in PendingBranches.AsEnumerable()) { if (branch.Branch == null) { continue; // a tracked exception } var location = new SourceLocation(branch.Branch.Syntax.GetFirstToken()); switch (branch.Branch.Kind) { case BoundKind.YieldBreakStatement: case BoundKind.YieldReturnStatement: // ERR_BadYieldInFinally reported during initial binding break; default: Diagnostics.Add(ErrorCode.ERR_BadFinallyLeave, location); break; } } RestorePending(oldPending1); }
protected override void LeaveRegion() { foreach (var pending in PendingBranches.AsEnumerable()) { if (pending.Branch == null || !RegionContains(pending.Branch.Syntax.Span)) { continue; } switch (pending.Branch.Kind) { case BoundKind.GotoStatement: if (_labelsInside.Contains(((BoundGotoStatement)pending.Branch).Label)) { continue; } break; case BoundKind.BreakStatement: if (_labelsInside.Contains(((BoundBreakStatement)pending.Branch).Label)) { continue; } break; case BoundKind.ContinueStatement: if (_labelsInside.Contains(((BoundContinueStatement)pending.Branch).Label)) { continue; } break; case BoundKind.YieldBreakStatement: case BoundKind.ReturnStatement: // Return statements are included break; case BoundKind.YieldReturnStatement: case BoundKind.AwaitExpression: case BoundKind.UsingStatement: case BoundKind.ForEachStatement when((BoundForEachStatement)pending.Branch).AwaitOpt != null: // We don't do anything with yield return statements, async using statement, async foreach statement, or await expressions; // they are treated as if they are not jumps. continue; default: throw ExceptionUtilities.UnexpectedValue(pending.Branch.Kind); } _branchesOutOf.Add((StatementSyntax)pending.Branch.Syntax); } base.LeaveRegion(); }
protected override void LeaveRegion() { if (this.IsConditionalState) { // If the region is in a condition, then the state will be split and state.Assigned will // be null. Merge to get sensible results. _endOfRegionState = StateWhenTrue.Clone(); Join(ref _endOfRegionState, ref StateWhenFalse); } else { _endOfRegionState = this.State.Clone(); } foreach (var branch in PendingBranches.AsEnumerable()) { if (branch.Branch != null && RegionContains(branch.Branch.Syntax.Span) && !_labelsInside.Contains(branch.Label)) { Join(ref _endOfRegionState, ref branch.State); } } base.LeaveRegion(); }