public virtual CatchList VisitCatchList(CatchList catchers, CatchList changes, CatchList deletions, CatchList insertions){ if (changes == null || deletions == null || insertions == null) return catchers; int n = catchers == null ? 0 : catchers.Count; if (n > changes.Count){Debug.Assert(false); n = changes.Count;} if (n > deletions.Count){Debug.Assert(false); n = deletions.Count;} if (n > insertions.Count){Debug.Assert(false); n = insertions.Count;} if (catchers != null) for (int i = 0; i < n; i++) catchers[i] = this.VisitCatch(catchers[i], changes[i], deletions[i], insertions[i]); CatchList result = new CatchList(insertions.Count-n); for (int i = n, m = insertions.Count; i < m; i++) result.Add(insertions[i]); return result; }
public virtual Catch GetClosestMatch(Catch/*!*/ nd1, CatchList/*!*/ list1, CatchList list2, int list1pos, ref int list2start, TrivialHashtable/*!*/ matchedNodes, out Differences closestDifferences, out int list2pos) { closestDifferences = null; list2pos = -1; if (list2 == null) return null; if (nd1 == null || list1 == null || matchedNodes == null || list1pos < 0 || list1pos >= list1.Count || list2start < 0 || list2start >= list2.Count) { Debug.Assert(false); return null; } Catch closest = null; Differences winnerSoFar = null; for (int j = list2start, m = list2.Count; j < m; j++){ Catch nd2 = list2[j]; if (list2start == j) list2start++; if (nd2 == null) continue; if (matchedNodes[nd2.UniqueKey] != null) continue; Differences diff = this.GetDifferences(nd1, nd2); if (diff == null){Debug.Assert(false); continue;} if (diff.Similarity <= 0.5){ //Not a good enough match if (list2start == j+1) list2start--; //The next call to GetClosestMatch will start looking at list2start, so this node will be considered then continue; //ignore it for the rest of this call } if (winnerSoFar != null && winnerSoFar.Similarity >= diff.Similarity) continue; winnerSoFar = closestDifferences = diff; closest = nd2; list2pos = j; if (diff.NumberOfDifferences == 0) return closest; //Perfect match, no need to look for other matches } if (closest != null){ //^ assert winnerSoFar != null; //closest is closer to nd1 than any other node in list2, but this is no good if some other node in list1 has a better claim on closest for (int i = list1pos+1, n = list1.Count; i < n; i++){ Catch nd1alt = list1[i]; if (nd1alt == null) continue; if (matchedNodes[nd1alt.UniqueKey] != null) continue; Differences diff = this.GetDifferences(nd1alt, closest); if (diff == null){Debug.Assert(false); continue;} if (diff.Similarity <= winnerSoFar.Similarity) continue; //nd1alt has a better claim on closest. See if it wants closest. Differences diff2; int j, k = list2start; Catch nd2alt = this.GetClosestMatch(nd1alt, list1, list2, i, ref k, matchedNodes, out diff2, out j); if (nd2alt != closest){ Debug.Assert(nd2alt != null && diff2 != null && diff2.Similarity >= diff.Similarity); continue; //nd1alt prefers nd2alt to closest, so closest is still available } //nd1alt wants closest, take it out of the running matchedNodes[closest.UniqueKey] = nd1alt; //Now that closest is out of the running, try again k = list2start; Catch newClosest = this.GetClosestMatch(nd1, list1, list2, i, ref k, matchedNodes, out winnerSoFar, out list2pos); //put closest back in the running so that the next call to this routine will pick it up matchedNodes[closest.UniqueKey] = closest; closest = newClosest; break; } } closestDifferences = winnerSoFar; return closest; }
public virtual Differences VisitCatchList(CatchList list1, CatchList list2, out CatchList changes, out CatchList deletions, out CatchList insertions){ changes = list1 == null ? null : list1.Clone(); deletions = list1 == null ? null : list1.Clone(); insertions = list1 == null ? new CatchList() : list1.Clone(); //^ assert insertions != null; Differences differences = new Differences(); for (int j = 0, n = list2 == null ? 0 : list2.Count; j < n; j++){ //^ assert list2 != null; Catch nd2 = list2[j]; if (nd2 == null) continue; insertions.Add(null); } TrivialHashtable savedDifferencesMapFor = this.differencesMapFor; this.differencesMapFor = null; TrivialHashtable matchedNodes = new TrivialHashtable(); for (int i = 0, k = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; Catch nd1 = list1[i]; if (nd1 == null) continue; Differences diff; int j; Catch nd2 = this.GetClosestMatch(nd1, list1, list2, i, ref k, matchedNodes, out diff, out j); if (nd2 == null || diff == null){Debug.Assert(nd2 == null && diff == null); continue;} matchedNodes[nd1.UniqueKey] = nd1; matchedNodes[nd2.UniqueKey] = nd2; changes[i] = diff.Changes as Catch; deletions[i] = diff.Deletions as Catch; insertions[i] = diff.Insertions as Catch; insertions[n+j] = nd1; //Records the position of nd2 in list2 in case the change involved a permutation Debug.Assert(diff.Changes == changes[i] && diff.Deletions == deletions[i] && diff.Insertions == insertions[i]); differences.NumberOfDifferences += diff.NumberOfDifferences; differences.NumberOfSimilarities += diff.NumberOfSimilarities; } //Find deletions for (int i = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; Catch nd1 = list1[i]; if (nd1 == null) continue; if (matchedNodes[nd1.UniqueKey] != null) continue; changes[i] = null; deletions[i] = nd1; insertions[i] = null; differences.NumberOfDifferences += 1; } //Find insertions for (int j = 0, n = list1 == null ? 0 : list1.Count, m = list2 == null ? 0 : list2.Count; j < m; j++){ //^ assert list2 != null; Catch nd2 = list2[j]; if (nd2 == null) continue; if (matchedNodes[nd2.UniqueKey] != null) continue; insertions[n+j] = nd2; //Records nd2 as an insertion into list1, along with its position in list2 differences.NumberOfDifferences += 1; //REVIEW: put the size of the tree here? } if (differences.NumberOfDifferences == 0){ changes = null; deletions = null; insertions = null; } this.differencesMapFor = savedDifferencesMapFor; return differences; }
public virtual void VisitCatchList(CatchList catchers) { if (catchers == null) return; for (int i = 0, n = catchers.Count; i < n; i++) this.VisitCatch(catchers[i]); }
public virtual CatchList VisitCatchList(CatchList catchers){ if (catchers == null) return null; for (int i = 0, n = catchers.Count; i < n; i++) catchers[i] = (Catch)this.VisitCatch(catchers[i]); return catchers; }
public virtual CatchList VisitCatchList(CatchList catchers1, CatchList catchers2) { if (catchers1 == null) return null; for (int i = 0, n = catchers1.Count, m = catchers2 == null ? 0 : catchers2.Count; i < n; i++) { //^ assert catchers2 != null; if (i >= m) catchers1[i] = (Catch)this.VisitCatch(catchers1[i], null); else catchers1[i] = (Catch)this.VisitCatch(catchers1[i], catchers2[i]); } return catchers1; }
public override CatchList VisitCatchList(CatchList catchers) { if (catchers == null) return null; return base.VisitCatchList(catchers.Clone()); }
public override Node VisitQueryTransact(QueryTransact qt) { if (qt == null || qt.Source == null || qt.Source.Type == null) return null; Block block = new Block(new StatementList(10)); qt.Transaction = this.NewClosureLocal(SystemTypes.IDbTransaction, this.currentMethod.Body.Scope); Expression locCommit = this.NewClosureLocal(SystemTypes.Boolean, this.currentMethod.Body.Scope); TypeNode txType = null; if (this.GetTypeView(qt.Source.Type).IsAssignableTo(SystemTypes.IDbConnection)) { txType = SystemTypes.IDbConnection; } else if (this.GetTypeView(qt.Source.Type).IsAssignableTo(SystemTypes.IDbTransactable)) { txType = SystemTypes.IDbTransactable; } Expression source = this.typeSystem.ExplicitCoercion(qt.Source, txType, this.TypeViewer); if (qt.Isolation != null) { Method mBegin = this.GetTypeView(txType).GetMethod(idBeginTransaction, SystemTypes.IsolationLevel); MethodCall mcBegin = new MethodCall(new MemberBinding(source, mBegin), new ExpressionList(qt.Isolation)); mcBegin.Type = mBegin.ReturnType; mcBegin.NodeType = NodeType.Callvirt; block.Statements.Add(new AssignmentStatement(qt.Transaction, mcBegin)); } else { Method mBegin = this.GetTypeView(txType).GetMethod(idBeginTransaction); MethodCall mcBegin = new MethodCall(new MemberBinding(source, mBegin), null); mcBegin.Type = mBegin.ReturnType; mcBegin.NodeType = NodeType.Callvirt; block.Statements.Add(new AssignmentStatement(qt.Transaction, mcBegin)); } block.Statements.Add(new AssignmentStatement(locCommit, Literal.True)); // prepare finally block Block finBlock = new Block(new StatementList(10)); Method mRollback = SystemTypes.IDbTransaction.GetMethod(idRollback); MethodCall mcRollback = new MethodCall(new MemberBinding(qt.Transaction, mRollback), null); mcRollback.Type = mRollback.ReturnType; mcRollback.NodeType = NodeType.Callvirt; Method mCommit = SystemTypes.IDbTransaction.GetMethod(idCommit); MethodCall mcCommit = new MethodCall(new MemberBinding(qt.Transaction, mCommit), null); mcCommit.Type = mCommit.ReturnType; mcCommit.NodeType = NodeType.Callvirt; Method mDispose = SystemTypes.IDisposable.GetMethod(StandardIds.Dispose); MethodCall mcDispose = new MethodCall(new MemberBinding(qt.Transaction, mDispose), null); mcDispose.Type = mDispose.ReturnType; mcDispose.NodeType = NodeType.Callvirt; Block bCommitStart = new Block(); Block bCommitBody = new Block(qt.CommitBody.Statements); Block bRollbackBody = new Block(qt.RollbackBody.Statements); Block finExit = new Block(); finBlock.Statements.Add(new Branch(locCommit, bCommitStart)); finBlock.Statements.Add(new ExpressionStatement(mcRollback)); finBlock.Statements.Add(bRollbackBody); finBlock.Statements.Add(new Branch(null, finExit)); finBlock.Statements.Add(bCommitStart); finBlock.Statements.Add(new ExpressionStatement(mcCommit)); finBlock.Statements.Add(bCommitBody); finBlock.Statements.Add(finExit); finBlock.Statements.Add(new ExpressionStatement(mcDispose)); finBlock.Statements.Add(new AssignmentStatement(qt.Transaction, Literal.Null)); // prepare catcher Local locEx = new Local(SystemTypes.Object); Block catchBlock = new Block(new StatementList(2)); catchBlock.Statements.Add(new AssignmentStatement(locCommit, Literal.False)); Throw _throw = new Throw(locEx); _throw.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(_throw); CatchList catchers = new CatchList(1); catchers.Add(new Catch(catchBlock, locEx, SystemTypes.Object)); // prepare try block Block tryBlock = new Block(new StatementList(4)); qt.CommitBody.Statements = null;; qt.RollbackBody.Statements = null; tryBlock.Statements.Add(qt.Body); tryBlock.Statements.Add(new Branch(null, qt.CommitBody)); tryBlock.Statements.Add(qt.RollbackBody); tryBlock.Statements.Add(new AssignmentStatement(locCommit, Literal.False)); tryBlock.Statements.Add(qt.CommitBody); this.exceptionBlockFor[qt.CommitBody.UniqueKey] = tryBlock; this.exceptionBlockFor[qt.RollbackBody.UniqueKey] = tryBlock; // add try-finally to block block.Statements.Add(new Try(tryBlock, catchers, null, null, new Finally(finBlock))); this.currentTransaction = qt; Node result = this.VisitBlock(block); this.currentTransaction = null; return result; }
private Try ParseTry(TokenSet followers){ object catchContext = null; object finallyContext = null; bool savedUnmatchedTry = this.unmatchedTry; Try Try = new Try(); Try.SourceContext = this.scanner.CurrentSourceContext; Debug.Assert(this.currentToken == Token.Try || this.currentToken == Token.Catch || this.currentToken == Token.Finally); TokenSet tryBlockFollowers = followers|Parser.CatchOrFinally; if (this.currentToken == Token.Try){ this.unmatchedTry = true; this.GetNextToken(); if (this.currentToken == Token.LeftBrace) Try.TryBlock = this.ParseBlock(tryBlockFollowers); else{ this.HandleError(Error.ExpectedLeftBrace); if (Parser.StatementStart[this.currentToken]){ Block block = new Block(); block.Checked = this.insideCheckedBlock; block.IsUnsafe = this.inUnsafeCode; block.SuppressCheck = this.insideUncheckedBlock; SourceContext ctx = this.scanner.CurrentSourceContext; block.SourceContext = this.scanner.CurrentSourceContext; block.Statements = this.ParseStatements(tryBlockFollowers|Token.RightBrace); block.SourceContext.EndPos = this.scanner.CurrentSourceContext.StartPos; Try.TryBlock = block; this.Skip(Token.RightBrace); } } }else{ if (savedUnmatchedTry && ((this.currentToken == Token.Catch && followers[Token.Catch]) || (this.currentToken == Token.Finally && followers[Token.Finally]))) return null; else this.HandleError(Error.SyntaxError, "try"); } CatchList catchers = new CatchList(); bool seenEmptyCatch = false; while (this.currentToken == Token.Catch){ if (seenEmptyCatch) this.HandleError(Error.TooManyCatches); catchContext = this.scanner.CurrentSourceContext; Catch c = this.ParseCatch(tryBlockFollowers); if (c == null) continue; if (c.TypeExpression == null) seenEmptyCatch = true; catchers.Add(c); } Try.Catchers = catchers; if (this.currentToken == Token.Finally){ finallyContext = this.scanner.CurrentSourceContext; this.GetNextToken(); Try.Finally = new Finally(this.ParseBlock(followers)); }else if (catchers.Count == 0) this.SkipTo(followers, Error.ExpectedEndTry); if (this.sink != null){ if (finallyContext != null) if (catchContext != null) this.sink.MatchTriple(Try.SourceContext, (SourceContext)catchContext, (SourceContext)finallyContext); else this.sink.MatchPair(Try.SourceContext, (SourceContext)finallyContext); else if (catchContext != null) this.sink.MatchPair(Try.SourceContext, (SourceContext)catchContext); } this.unmatchedTry = savedUnmatchedTry; return Try; }
public virtual Statement MarkAsInstrumentationCode(Block block){ Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; Catch catchClause = new Catch(new Block(new StatementList(rethrow)), new Local(SystemTypes.ContractMarkerException), SystemTypes.ContractMarkerException); CatchList catchers = new CatchList(1); catchers.Add(catchClause); return new Try(block, catchers, null, null, null); }
public override Statement VisitExpose(Expose Expose){ if (Expose == null) return null; if (Expose.Instance == null) return this.VisitBlock(Expose.Body); TypeNode exposeInstanceType = TypeNode.StripModifiers(Expose.Instance.Type); if (exposeInstanceType == null) return this.VisitBlock(Expose.Body); SourceContext endContext = new SourceContext(Expose.SourceContext.Document, Expose.SourceContext.EndPos - 1, Expose.SourceContext.EndPos); string startMethodName = null; string endMethodName = null; Method startMethod = null; Method endMethod = null; InvariantList justToForceDeserialization = exposeInstanceType.Contract != null ? exposeInstanceType.Contract.Invariants : null; if (exposeInstanceType.Contract == null || exposeInstanceType.Contract.FramePropertyGetter == null ) { // If we're exposing an expression E of type T where T is not a guarded class, // then for the sake of downstream analysis tools (such as the Spec# Program Verifier) we emit the following code: // // write|expose (E) S [alternatively, "write|expose (E at T) S"] // // is translated into // // T target = E; // Guard.StartWritingFrame(target, typeof(T)); [alternatively, Guard.StartWritingAtNop] // try{ // S // }finally{ // Guard.EndWritingFrame(target, typeof(T)); [alternatively, Guard.EndWritingAtNop] // } // // These methods are no-ops. For this reason, // combined with the fact that Boogie considers unchecked exceptions to be the end of the world, // we don't need to distinguish between checked and unchecked exceptions here. Block block = new Block(new StatementList()); Local target = new Local(Identifier.Empty, exposeInstanceType, block); Literal typeArgument = null; if (Expose.IsLocal) { startMethodName = "StartWritingAtNop"; endMethodName = "EndWritingAtNop"; } else { startMethodName = "StartWritingFrame"; endMethodName = "EndWritingFrame"; } typeArgument = new Literal(exposeInstanceType, SystemTypes.Type); startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Object), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Object), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); block.Statements.Add(new AssignmentStatement(target, Expose.Instance, Expose.Instance.SourceContext)); block.Statements.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, startMethod), new ExpressionList(target, new UnaryExpression(typeArgument, NodeType.Typeof)), NodeType.Call, SystemTypes.Void), Expose.Instance.SourceContext)); block.Statements.Add(new Try( Expose.Body, null, null, null, new Finally(new Block(new StatementList(new ExpressionStatement(new MethodCall( new MemberBinding(null, endMethod), new ExpressionList(target, new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)), NodeType.Call, SystemTypes.Void), endContext)))) )); return (Statement) this.Visit(block); } // write|additive expose (E) S [alternatively: expose (E) S] // // is translated into // // Guard! rootFrame = E.FrameGuard.StartWritingTransitively(); [alternatively "StartWritingAtTransitively"] // Exception exception = null; // try { // S // } catch (Exception e) { // exception = e; // throw; // } finally { // if (exception == null || exception is ICheckedException) // rootFrame.EndWritingTransitively(); [alternatively "EndWritingAtTransitively"] // } // // This is a hack; it would be better to statically have different code paths for // the normal completion case and the exceptional completion case. // However, that requires transforming returns, gotos, continues, breaks, etc. // Of course, all of the above can first be transformed into gotos. // // The "throw" in the catch clause is needed to allow the definite assignment // analysis to know that things assigned to in S are really assigned to // in the code following the finally block. // More importantly, who are we to eat up an exception, unless the exception // is checked and the object invariant doesn't hold. TypeNode staticInstanceType = exposeInstanceType; if (Expose.IsLocal) { startMethodName = "StartWritingAtTransitively"; endMethodName = "EndWritingAtTransitively"; startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName), OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)); } else { if (Expose.NodeType == NodeType.Read) { startMethodName = "StartReadingTransitively"; endMethodName = "EndReadingTransitively"; } else { startMethodName = "StartWritingTransitively"; endMethodName = "EndWritingTransitively"; } startMethod = SystemTypes.Guard.GetMethod(Identifier.For(startMethodName)); endMethod = SystemTypes.Guard.GetMethod(Identifier.For(endMethodName)); } TypeNode guardType = OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Guard); Method frameGetter = staticInstanceType.Contract.FramePropertyGetter; Block newBody = new Block(); Local rootFrame = new Local(Identifier.For("SS$rootFrame"), guardType, newBody); Expression frameGetterCall = new MethodCall(new MemberBinding(Expose.Instance, frameGetter), null); // Need two independent argument lists. Otherwise, the processing of the first one disrupts the // second one. ExpressionList startFrameGetterExprArgs; ExpressionList endFrameGetterExprArgs; if (Expose.IsLocal) { startFrameGetterExprArgs = new ExpressionList(new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)); endFrameGetterExprArgs = new ExpressionList(new UnaryExpression(new Literal(exposeInstanceType, SystemTypes.Type), NodeType.Typeof)); } else { startFrameGetterExprArgs = null; endFrameGetterExprArgs = null; } Expression frameGetterExpr = new MethodCall(new MemberBinding(frameGetterCall, startMethod), startFrameGetterExprArgs, NodeType.Call, startMethod.ReturnType); Statement startCall = new AssignmentStatement(rootFrame, frameGetterExpr, Expose.Instance.SourceContext); // rootFrame.End(Reading|Writing)Transitively(); Statement endCall = new ExpressionStatement(new MethodCall(new MemberBinding(rootFrame, endMethod), endFrameGetterExprArgs, NodeType.Call, SystemTypes.Void), endContext); Local exception = new Local(SystemTypes.Exception); CatchList catchList = new CatchList(1); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; Local e = new Local(SystemTypes.Exception); catchList.Add(new Catch(new Block(new StatementList(new AssignmentStatement(exception, e), rethrow)), e, SystemTypes.Exception)); newBody.Statements = new StatementList( startCall, new AssignmentStatement(exception, new Literal(null, SystemTypes.Exception)), new Try( Expose.Body, catchList, null, null, new Finally(new Block(new StatementList( new If( new BinaryExpression( new BinaryExpression(exception, new Literal(null, SystemTypes.Exception), NodeType.Eq, SystemTypes.Boolean), new BinaryExpression(exception, new Literal(SystemTypes.ICheckedException, SystemTypes.Type), NodeType.Is, SystemTypes.Boolean), NodeType.LogicalOr, SystemTypes.Boolean), new Block(new StatementList(endCall)), null)))))); return this.VisitBlock(newBody); }
public Try(Block tryBlock, CatchList catchers, FilterList filters, FaultHandlerList faultHandlers, Finally Finally) : base(NodeType.Try) { this.catchers = catchers; this.faultHandlers = faultHandlers; this.filters = filters; this.finallyClause = Finally; this.tryBlock = tryBlock; }
private CatchList Translate(CodeCatchClauseCollection catchers){ if (catchers == null) return null; int n = catchers.Count; CatchList catchList = new CatchList(n); for (int i = 0; i < n; i++) catchList.Add(this.Translate(catchers[i])); return catchList; }
public EventingVisitor(Action<CatchList> visitCatchList) { VisitedCatchList += visitCatchList; } public event Action<CatchList> VisitedCatchList; public override CatchList VisitCatchList(CatchList catchers) { if (VisitedCatchList != null) VisitedCatchList(catchers); return base.VisitCatchList(catchers); }