Exemple #1
0
        /// <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();
            }
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        /// <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);
        }
Exemple #5
0
        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);
        }