/// <summary> /// Prints all the diagnostics generated by the compilation /// </summary> /// <param name="compilation"></param> internal static void PrintDiagnostics(IEnumerable <Diagnostic> diagnostics) { #region CodeContracts Contract.Requires(diagnostics != null); #endregion CodeContracts var errors = diagnostics.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); //errors = errors.Where(error => error.Id != "CS7027"); RBLogger.Indent(); foreach (var d in errors.Where(error => error.Location.SourceTree == null)) { RBLogger.Info(d); } RBLogger.Unindent(); errors = errors.Where(error => error.Location.SourceTree != null); foreach (var filegroup in errors.GroupBy(error => error.Location.SourceTree.FilePath)) { var first = filegroup.First(); RBLogger.Info(first.Location.SourceTree.FilePath); RBLogger.Indent(); foreach (var d in filegroup) { RBLogger.Info(d); } RBLogger.Unindent(); } }
private static void DebugParsing(IEnumerable <BaseAnnotation> annotations) { var total_sugs = 0; foreach (var filegroup in annotations.GroupBy(x => x.FileName)) { if (filegroup.Any()) { RBLogger.Info("Annotations for file " + filegroup.First()); RBLogger.Indent(); foreach (var methodgroup in filegroup.GroupBy(x => x.MethodName)) { if (methodgroup.Any()) { RBLogger.Info("Annotations for method " + methodgroup.First().MethodName); RBLogger.Indent(); foreach (var sug in methodgroup) { total_sugs++; RBLogger.Info(sug.Annotation); } } RBLogger.Unindent(); } RBLogger.Unindent(); } } RBLogger.Info("Total suggestions: {0}", total_sugs); }
public static SyntaxDictionary GetSyntaxNodeToAnnotationDict(Compilation compilation, IEnumerable <BaseAnnotation> annotations) { #region CodeContracts Contract.Requires(compilation != null); Contract.Requires(annotations != null); Contract.Ensures(Contract.Result <SyntaxDictionary>() != null); #endregion CodeContracts Output.WriteLine("Creating the SyntaxNode to annotations dictionary"); var annotations_by_node = new SyntaxDictionary(); foreach (var st in compilation.SyntaxTrees) { var fp = st.FilePath; var curr_anns = annotations.Where(x => x.FileName.Equals(fp, StringComparison.OrdinalIgnoreCase)); var fields = curr_anns.OfType <ReadonlyField>(); curr_anns = curr_anns.Except(fields); //Dictionary<MethodNameId, List<BaseAnnotation>> curr_anns; //if (annotations.TryGetValue(fp, out curr_anns)) // does the syntax tree have any annotations? if (curr_anns.Any()) { annotations_by_node.Add(fp, new Dictionary <SyntaxNode, List <BaseAnnotation> >()); var sm = compilation.GetSemanticModel(st); var mf = new MethodsFinder(curr_anns, sm); var before = curr_anns.Count(); var after = mf.methods_to_annotate.Count; if (before != after) { Output.WriteWarning("Didn't match all methods for " + fp + " There were " + before + " but now " + after, "ERROR"); Output.WriteLine("Next the list of those we failed to match"); foreach (var orig in curr_anns.Select(x => x.MethodName)) { var matched = false; foreach (var newguy in mf.methods_to_annotate.Keys) { if (newguy is FieldDeclarationSyntax) { continue; } // this way of finding missing annotations doesn't really work for readonly fields var sym = sm.GetDeclaredSymbol(newguy) as ISymbol; var dci = sym.GetDocumentationCommentId(); if (dci.Equals(orig)) { matched = true; } } if (!matched) { Output.WriteLine("Failed to find {0}", orig); } } } else { Output.WriteLine("Matched all methods in {0}", fp); } //before = DictionaryHelpers.CountTotalItems(curr_anns); before = curr_anns.Count(); after = DictionaryHelpers.CountTotalItems(mf.methods_to_annotate); if (before != after) { Output.WriteWarning("Lost some annotations for " + fp + " There were " + before + " but now " + after, "ERROR"); } else { Output.WriteLine("Matched all annotations in {0}", fp); } foreach (var key in mf.methods_to_annotate.Keys) { annotations_by_node[fp].Add(key, mf.methods_to_annotate[key]); } } } int total = 0; foreach (var dict in annotations_by_node.Values) { total += DictionaryHelpers.CountTotalItems(dict); } Output.WriteLine("I started with {0} annotations and I found {1}", annotations.Count().ToString(), total.ToString()); if (annotations.Count() != total) { var interfaces = annotations.OfType <ResolvedInterfaceAnnotation>(); var fields = annotations.OfType <ReadonlyField>(); var invariants = annotations.OfType <ResolvedObjectInvariant>(); var other = annotations.OfType <Precondition>(); var found = new List <BaseAnnotation>(); foreach (var file in annotations_by_node) { foreach (var sugs in file.Value.Values) { found = found.Concat(sugs).ToList(); } } var interfacesFound = found.OfType <ResolvedInterfaceAnnotation>(); var fieldsFound = found.OfType <ReadonlyField>(); var invariantsFound = found.OfType <ResolvedObjectInvariant>(); var otherFound = found.OfType <Precondition>(); RBLogger.Info("Interfaces found {0} of {1}", interfacesFound.Count(), interfaces.Count()); RBLogger.Info("fields found {0} of {1}", fieldsFound.Count(), fields.Count()); RBLogger.Info("invariants found {0} of {1}", invariantsFound.Count(), invariants.Count()); RBLogger.Info("other found {0} of {1}", otherFound.Count(), other.Count()); var lost = other.Except(otherFound); RBLogger.Info("Missing annotations:"); RBLogger.Indent(); foreach (var group in lost.GroupBy(x => x.MethodName)) { RBLogger.Info(group.First().MethodName); RBLogger.Indent(); foreach (var ann in group) { RBLogger.Info(ann); } RBLogger.Unindent(); } RBLogger.Unindent(); //RBLogger.Info("Found annotations {0}", found.Count()); //RBLogger.Info("Unmatched annotations:"); //RBLogger.Indent(); //foreach (var annotation in other) //{ // RBLogger.Info(annotation.MethodName); // RBLogger.Indent(); // RBLogger.Info(annotation); // RBLogger.Unindent(); //} //RBLogger.Unindent(); } return(annotations_by_node); }
/// <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); }