Esempio n. 1
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);
        }
Esempio n. 2
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);
        }