/// <summary> /// Get the compilation's errors (ignore warnings, info) /// </summary> /// <param name="compilation">The compilation you want to get the errors for</param> /// <returns></returns> //internal static Dictionary<SyntaxTree, List<Diagnostic>> GetDiagnostics(Compilation compilation) //{ // #region CodeContracts // Contract.Requires(compilation != null); // Contract.Ensures(Contract.Result<Dictionary<SyntaxTree, List<Diagnostic>>>() != null); // #endregion CodeContracts // Contract.Assume(compilation.SyntaxTrees != null); // var diags = new Dictionary<SyntaxTree, List<Diagnostic>>(); // foreach (var st in compilation.SyntaxTrees) // { // //Debug.WriteLine(st.FilePath); // //RBLogger.Info(st.FilePath); // var sm = compilation.GetSemanticModel(st); // var ds = sm.GetDiagnostics(); // foreach (var d in ds) // { // if (d.Severity == DiagnosticSeverity.Error) // { // List<Diagnostic> oldDiagnostics; // if (diags.TryGetValue(st, out oldDiagnostics)) // { // Contract.Assume(oldDiagnostics != null); // this is the semantics of dictionary.TryGetValue right? // oldDiagnostics.Add(d); // } // else // { // diags.Add(st, new List<Diagnostic>()); // diags[st].Add(d); // } // } // } // } // return diags; //} /// <summary> /// Remove the annotations from orig_suggestions that cause diagnostics /// </summary> /// <param name="compilation"></param> /// <param name="origcomp"></param> /// <param name="orig_suggestions"></param> /// <returns></returns> //internal static IEnumerable<BaseAnnotation> FilterBadSuggestions(Compilation newcomp, Compilation origcomp, IEnumerable<BaseAnnotation> orig_suggestions) internal static IEnumerable <BaseAnnotation> FilterBadSuggestions(Compilation compilation, IEnumerable <BaseAnnotation> orig_suggestions) { #region CodeContracts Contract.Requires(compilation != null); Contract.Requires(orig_suggestions != null); Contract.Requires(Contract.ForAll(orig_suggestions, suggestion => suggestion != null)); Contract.Requires(Contract.ForAll(orig_suggestions, suggestion => suggestion.MethodName != null)); Contract.Requires(Contract.ForAll(orig_suggestions, suggestion => suggestion.FileName != null)); #endregion CodeContracts var badSuggestions = new List <BaseAnnotation>(); //foreach (var pair in origcomp.SyntaxTrees.Zip(newcomp.SyntaxTrees, (SyntaxTree a, SyntaxTree b) => Tuple.Create(a,b))) foreach (var syntaxTree in compilation.SyntaxTrees) { var sm = compilation.GetSemanticModel(syntaxTree); var diags = sm.GetDiagnostics(); if (diags.Any()) { var errors = new List <Diagnostic>(); foreach (var d in diags) { if (d.Severity == DiagnosticSeverity.Error) { errors.Add(d); } } if (errors.Any()) { RBLogger.Info("Found the following errors in " + syntaxTree.FilePath + ":"); RBLogger.Indent(); foreach (var e in errors) { RBLogger.Info(e.ToString().Replace(syntaxTree.FilePath, "")); } RBLogger.Unindent(); var thistreessugs = orig_suggestions.Where(x => x.FileName.Equals(syntaxTree.FilePath, StringComparison.OrdinalIgnoreCase)); //Dictionary<MethodNameId, List<BaseAnnotation>> thistreessugs; //if (orig_suggestions.TryGetValue(oldst.FilePath, out thistreessugs)) var dr = new DiagnosticFinder(errors, sm, thistreessugs); dr.Visit(syntaxTree.GetRoot()); //var bad2 = dr.sugs.Where(x => x.isBad); badSuggestions.AddRange(dr.BadSuggestions); RBLogger.ErrorIf(dr.BadSuggestions.Count() != errors.Count(), "Failed to find some bad suggestions in {0}", syntaxTree.FilePath); //Console.WriteLine("bad suggestions:"); //foreach (var b in bad2) { Console.WriteLine(b); } //if (oldst.FilePath.Contains("RuleBuilder")) { Debugger.Break(); } } } } //return FilterDictionary(orig_suggestions); //var good = orig_suggestions.Where(x => !x.isBad); //var bad = orig_suggestions.Where(x => x.isBad); var bad = badSuggestions; var good = orig_suggestions.Except(bad, new AnnotationEqualitiyComparer()); //RBLogger.Info("Suggestions that caused errors: {0}", bad.Count()); //RBLogger.Indent(); //RBLogger.Info("bad count: {0}", bad.Count()); //RBLogger.Info("good count: {0}", good.Count()); //RBLogger.Info("orig count: {0}", orig_suggestions.Count()); //foreach (var b in bad) //{ // RBLogger.Info(b); //} //RBLogger.Unindent(); //var not_found = bad.Except(good, new AnnotationEqualitiyComparer()); //RBLogger.Info("unfound bad suggestions count: {0}", not_found.Count()); //RBLogger.Info("unfound bad suggestions:"); //foreach (var nf in not_found) { RBLogger.Info(nf); } //var goodinv = good.OfType<ObjectInvariant>(); //RBLogger.Indent(); //RBLogger.Info("Good object invariants: {0}", goodinv.Count()); //foreach (var b in goodinv) //{ // RBLogger.Info(b); // if (b.FileName.Contains("RuleBuilder")) { int x; } //} //RBLogger.Unindent(); //RBLogger.Indent(); //RBLogger.Info("Good suggestions: {0}", good.Count()); //foreach (var b in good) //{ // RBLogger.Info(b); //} //RBLogger.Unindent(); return(good); }
private static SyntaxNode PrecomputeNewMethod(SyntaxNode oldmethod, List <BaseAnnotation> anns, bool useRegion = true) { SyntaxList <StatementSyntax> oldstmts; if (oldmethod is BaseMethodDeclarationSyntax) { var casted = oldmethod as BaseMethodDeclarationSyntax; oldstmts = casted.Body.Statements; } else if (oldmethod is AccessorDeclarationSyntax) { var casted = oldmethod as AccessorDeclarationSyntax; oldstmts = casted.Body.Statements; } else { RBLogger.Error("Unhandled syntax node kind {0}", oldmethod.CSharpKind()); } var newstmtlist = SyntaxFactory.Block(); var newObjectInvariants = anns.Where(x => x.Kind == ClousotSuggestion.Kind.ObjectInvariant).Select(x => x.statement_syntax as StatementSyntax); var oldObjectInvariants = oldstmts.Where(IsInvariant); var new_requires = anns.Where(x => x.Kind == ClousotSuggestion.Kind.Requires).Select(x => x.statement_syntax as StatementSyntax); var old_requires = oldstmts.Where(IsRequires); var new_ensures = anns.Where(x => x.Kind == ClousotSuggestion.Kind.Ensures || x.Kind == ClousotSuggestion.Kind.EnsuresNecessary) .Select(x => x.statement_syntax as StatementSyntax); var old_ensures = oldstmts.Where(IsEnsures); var new_assumes = anns.Where(x => x.Kind == ClousotSuggestion.Kind.AssumeOnEntry).Select(x => x.statement_syntax as StatementSyntax); //var old_eveything_else = oldstmts.Where(x => !IsEnsures(x) && !IsRequires(x) && !IsAssumes(x)); //var old_eveything_else = oldstmts.Where(x => !IsEnsures(x) && !IsRequires(x)); //var old_assumes = oldstmts.Where(IsAssumes); var old_assumes_list = new List <StatementSyntax>(); // we only want to consider the old assumes to be the ones at the start of the method // assumes can be anywhere, but its incorrect to move ones that use declared variables foreach (var stmt in oldstmts) { if (IsEnsures(stmt)) { continue; } if (IsRequires(stmt)) { continue; } if (IsAssumes(stmt)) { old_assumes_list.Add(stmt); continue; } break; } var old_assumes = old_assumes_list.AsEnumerable(); var old_eveything_else = oldstmts.Except(old_ensures.Concat(old_requires).Concat(old_assumes)); var objectInvariants = newObjectInvariants.Union(oldObjectInvariants, new ContractEqualityComparer()); //if (objectInvariants.Any()) { Debugger.Break(); } SyntaxTrivia regionStart, regionEnd; regionEnd = regionStart = SyntaxFactory.Comment(""); // a dummy initial value if (useRegion && !objectInvariants.Any()) { if (TryFindContractsRegion(old_requires, old_ensures, old_assumes, out regionStart, out regionEnd)) { var first = oldstmts.First(x => x.GetLeadingTrivia().Contains(regionStart)); //var last = oldstmts.First(x => x.GetTrailingTrivia().Contains(regionEnd)); //var last = oldstmts.First(x => x.GetLeadingTrivia().Contains(regionEnd)); //Console.WriteLine(first.Parent.DescendantTrivia().Contains(regionEnd)); // it seems like the #endregion can be essentially anywhere var statements = oldstmts.Where(x => x.GetLeadingTrivia().Contains(regionEnd) || x.GetTrailingTrivia().Contains(regionEnd)); StatementSyntax last, lastModified; last = lastModified = null; if (oldstmts.Any(x => x.GetLeadingTrivia().Contains(regionEnd))) { last = oldstmts.First(x => x.GetLeadingTrivia().Contains(regionEnd)); var lastTrivia = last.GetLeadingTrivia().Where(x => x != regionEnd); lastModified = last.WithLeadingTrivia(lastTrivia); } else if (oldstmts.Any(x => x.GetTrailingTrivia().Contains(regionEnd))) { last = oldstmts.First(x => x.GetTrailingTrivia().Contains(regionEnd)); var lastTrivia = last.GetTrailingTrivia().Where(x => x != regionEnd); lastModified = last.WithTrailingTrivia(lastTrivia); } else if (first.Parent.DescendantTrivia().Contains(regionEnd)) { oldmethod = first.Parent.Parent.ReplaceTrivia(regionEnd, SyntaxFactory.Comment("")); } var firstTrivia = first.GetLeadingTrivia().Where(x => x != regionStart); var firstModified = first.WithLeadingTrivia(firstTrivia); ReplaceStatement(first, firstModified, old_requires, old_ensures, old_assumes, old_eveything_else, out old_requires, out old_ensures, out old_assumes, out old_eveything_else); if (last != null) { ReplaceStatement(last, lastModified, old_requires, old_ensures, old_assumes, old_eveything_else, out old_requires, out old_ensures, out old_assumes, out old_eveything_else); } } else { var addNewLine = !old_requires.Any() && !old_requires.Any(); GetNewRegionTrivia("CodeContracts", addNewLine, out regionStart, out regionEnd); } } var requires = new_requires.Union(old_requires, new ContractEqualityComparer()); var ensures = new_ensures.Union(old_ensures, new ContractEqualityComparer()); var assumes = new_assumes.Union(old_assumes, new ContractEqualityComparer()); RBLogger.ErrorIf(requires.Count() < new_requires.Count(), "Union deleted some items!?"); RBLogger.ErrorIf(ensures.Count() < new_ensures.Count(), "Union deleted some items!?"); RBLogger.ErrorIf(assumes.Count() < new_assumes.Count(), "Union deleted some items!?"); // Scott: there is some weird case where we get duplicate ensures // I haven't tracked it down // this is for debugging: if (ensures.Count() < new_ensures.Count()) { RBLogger.Info("new ensures:"); RBLogger.Indent(); foreach (var ensure in new_ensures) { RBLogger.Info(ensure); } RBLogger.Unindent(); } //foreach(var r in requires) //{ // Console.WriteLine(r); //} //Console.WriteLine(requires.Count()); // the if x.Any()'s are unnecesary (IMHO) but there is a roslyn bug for // adding an empty StatementSyntax[] to an empty BlockSyntax if (requires.Any()) { newstmtlist = newstmtlist.AddStatements(requires.ToArray()); } if (ensures.Any()) { newstmtlist = newstmtlist.AddStatements(ensures.ToArray()); } if (assumes.Any()) { newstmtlist = newstmtlist.AddStatements(assumes.ToArray()); } if (old_eveything_else.Any()) { newstmtlist = newstmtlist.AddStatements(old_eveything_else.ToArray()); } if (objectInvariants.Any()) { newstmtlist = newstmtlist.AddStatements(objectInvariants.ToArray()); // object invariant methods should only have these, so order doesn't matter } if (useRegion && !objectInvariants.Any()) { var first = newstmtlist.Statements.First(); var oldTrivia = first.GetLeadingTrivia(); var newTrivia = SyntaxFactory.TriviaList(regionStart).Concat(oldTrivia); var firstModified = first.WithLeadingTrivia(newTrivia); newstmtlist = newstmtlist.ReplaceNode(first, firstModified); var index = requires.Count() + ensures.Count() + assumes.Count(); var last = newstmtlist.Statements[index - 1]; oldTrivia = last.GetTrailingTrivia(); newTrivia = oldTrivia.Concat(SyntaxFactory.TriviaList(new[] { regionEnd })); var lastModified = last.WithTrailingTrivia(newTrivia); newstmtlist = newstmtlist.ReplaceNode(last, lastModified); } SyntaxNode newmethod = null; if (oldmethod is MethodDeclarationSyntax) { var casted = oldmethod as MethodDeclarationSyntax; //newmethod = casted.WithBody(newstmtlist); // the awful line below is partly so awful to preserve the trivia around the method newmethod = casted.WithBody(casted.Body.WithStatements(newstmtlist.Statements)); } if (oldmethod is ConstructorDeclarationSyntax) { var casted = oldmethod as ConstructorDeclarationSyntax; //newmethod = casted.WithBody(newstmtlist); newmethod = casted.WithBody(casted.Body.WithStatements(newstmtlist.Statements)); } if (oldmethod is AccessorDeclarationSyntax) { var casted = oldmethod as AccessorDeclarationSyntax; //newmethod = casted.WithBody(newstmtlist); newmethod = casted.WithBody(casted.Body.WithStatements(newstmtlist.Statements)); } //var newmethod = oldmethod is MethodDeclarationSyntax ? (BaseMethodDeclarationSyntax)((MethodDeclarationSyntax)oldmethod).WithBody(newstmtlist) : // (BaseMethodDeclarationSyntax)((ConstructorDeclarationSyntax)oldmethod).WithBody(newstmtlist); //Console.WriteLine("Annotated Method: {0}", newmethod); return(newmethod); }