/// <summary> /// Begins a catch block for the given exception type in the given exception block. /// /// The given exception block must still be open. /// </summary> public CatchBlock BeginCatchBlock(ExceptionBlock forTry, Type exceptionType) { if (exceptionType == null) { throw new ArgumentNullException("exceptionType"); } if (forTry == null) { throw new ArgumentNullException("forTry"); } if (((IOwned)forTry).Owner != this) { FailOwnership(forTry); } if (CurrentExceptionBlock.Count > 0 && forTry != CurrentExceptionBlock.Peek()) { throw new InvalidOperationException("Cannot start CatchBlock on " + forTry + " while inner ExceptionBlock is still open"); } if (!typeof(Exception).IsAssignableFrom(exceptionType)) { throw new ArgumentException("BeginCatchBlock expects a type descending from Exception, found " + exceptionType, "exceptionType"); } var currentlyOpen = CatchBlocks.Where(c => c.Key.ExceptionBlock == forTry && c.Value.Item2 == -1).Select(s => s.Key).SingleOrDefault(); if (currentlyOpen != null) { throw new InvalidOperationException("Cannot start a new catch block, " + currentlyOpen + " has not been ended"); } if (MustMark) { MarkLabel(DefineLabel(AutoNamer.Next(this, "__autolabel"))); } UpdateState(Wrap(new[] { new StackTransition(0) }, "BeginCatchBlock")); var tryBlock = TryBlocks[forTry]; if (tryBlock.Item2 != -1) { throw new SigilVerificationException("BeginCatchBlock expects an unclosed exception block, but " + forTry + " is already closed", IL.Instructions(AllLocals)); } IL.BeginCatchBlock(exceptionType); UpdateState(Wrap(StackTransition.Push(exceptionType), "BeginCatchBlock")); var ret = new CatchBlock(exceptionType, forTry); CatchBlocks[ret] = SigilTuple.Create(IL.Index, -1); return(ret); }
private void ValidateTryCatchFinallyBranches() { foreach (var branch in Branches.AsEnumerable()) { var instr = BranchPatches[branch.Item3]; var toLabel = branch.Item2; var fromIndex = branch.Item3; var toIndex = Marks[toLabel]; var fromTryBlocks = TryBlocks.Where(t => fromIndex >= t.Value.Item1 && fromIndex <= t.Value.Item2).ToList(); var fromCatchBlocks = CatchBlocks.Where(c => fromIndex >= c.Value.Item1 && fromIndex <= c.Value.Item2).ToList(); var fromFinallyBlocks = FinallyBlocks.Where(f => fromIndex >= f.Value.Item1 && fromIndex <= f.Value.Item2).ToList(); var toTryBlocks = TryBlocks.Where(t => toIndex >= t.Value.Item1 && toIndex <= t.Value.Item2).ToList(); var toCatchBlocks = CatchBlocks.Where(c => toIndex >= c.Value.Item1 && toIndex <= c.Value.Item2).ToList(); var toFinallyBlocks = FinallyBlocks.Where(f => toIndex >= f.Value.Item1 && toIndex <= f.Value.Item2).ToList(); var fromTryBlock = fromTryBlocks.OrderByDescending(t => t.Value.Item1).Select(t => t.Key).FirstOrDefault(); var fromCatchBlock = fromCatchBlocks.OrderByDescending(c => c.Value.Item1).Select(c => c.Key).FirstOrDefault(); var fromFinallyBlock = fromFinallyBlocks.OrderByDescending(f => f.Value.Item1).Select(f => f.Key).FirstOrDefault(); var toTryBlock = toTryBlocks.OrderByDescending(t => t.Value.Item1).Select(t => t.Key).FirstOrDefault(); var toCatchBlock = toCatchBlocks.OrderByDescending(c => c.Value.Item1).Select(c => c.Key).FirstOrDefault(); var toFinallyBlock = toFinallyBlocks.OrderByDescending(f => f.Value.Item1).Select(f => f.Key).FirstOrDefault(); // Nothing funky going on, carry on if (fromTryBlock == null && fromCatchBlock == null && fromFinallyBlock == null && toTryBlock == null && toCatchBlock == null && toFinallyBlock == null) { continue; } if (fromCatchBlock != null && toCatchBlock != fromCatchBlock) { if (instr.Item3 != OpCodes.Leave) { throw new SigilVerificationException( "Cannot branch from inside " + fromCatchBlock + " to outside, exit the ExceptionBlock first", IL.Instructions(AllLocals) ); } } if (fromFinallyBlock != null && toFinallyBlock != fromFinallyBlock) { throw new SigilVerificationException( "Cannot branch from inside " + fromFinallyBlock + " to outside, exit the ExceptionBlock first", IL.Instructions(AllLocals) ); } if (toFinallyBlock != null && fromFinallyBlock != toFinallyBlock) { throw new SigilVerificationException( "Cannot branch into a FinallyBlock", IL.Instructions(AllLocals) ); } if (fromTryBlock != null && toTryBlock != fromTryBlock) { if (instr.Item3 != OpCodes.Leave) { throw new SigilVerificationException( "Cannot branch from inside " + fromTryBlock + " to outside, exit the ExceptionBlock first", IL.Instructions(AllLocals) ); } } } }