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
            private SyntaxNode ComputeReplacement(SyntaxNode old1, SyntaxNode old2)
            {
                // old1 is the original node in the tree
                // old2 is the (potentially) modified version of old1
                // that is, old1 is in dict_old_to_new but old2 wont be
                // if any of its chilrden have been modified
                if (dict_old_to_new.Keys.Contains(old1)) // this check is redundant?
                {
                    switch (old2.CSharpKind())
                    {
                    case SyntaxKind.GetAccessorDeclaration:
                    case SyntaxKind.SetAccessorDeclaration:
                    case SyntaxKind.ConstructorDeclaration:
                    case SyntaxKind.MethodDeclaration:
                    case SyntaxKind.AddAccessorDeclaration:    // who knew this was a thing? maybe this will work
                    case SyntaxKind.RemoveAccessorDeclaration: // who knew this was a thing? maybe this will work
                        //Console.WriteLine("Replacing {0} with {1}", old2, dict_old_to_new[old2]);
                        return(dict_old_to_new[old2]);

                    default:
                        RBLogger.Error("Unhandled syntax node kind {0}", old2.CSharpKind());
                        break;
                    }
                }
                return(old2); // don't replace
            }
Exemple #4
0
        private bool CheckRequiredArguments(ref string why)
        {
            #region CodeContracts
            Contract.Ensures(!Contract.Result <bool>() || this.ClousotXML != null);
            Contract.Ensures(!Contract.Result <bool>() || this.Project != null);
            Contract.Ensures(!Contract.Result <bool>() || this.Solution != null);
            Contract.Ensures(!Contract.Result <bool>() || this.Output != OutputOption.unintialized);
            // I have to think about this:
            //Contract.Ensures(Contract.Result<bool>() ^ !((this.Output == OutputOption.git && this.GitRoot == null) ^ this.Output == OutputOption.inplace));
            #endregion CodeContracts
            // I'm not positive this is correct:
            //Contract.Ensures(Contract.Result<bool>() == false || (this.Output != OutputOption.git && this.GitRoot != null) || this.Output != OutputOption.inplace);

            // right now, only support all options provided
            var ok = this.ClousotXML != null && this.Project != null && this.Solution != null && this.Output != OutputOption.unintialized;
            if (!ok)
            {
                why = "You need to specify all of: Clousot XML, Project, Solution, output";
                RBLogger.Error(why);
            }
            var ok2 = (this.Output == OutputOption.git && this.GitRoot != null) ^ this.Output == OutputOption.inplace;
            if (!ok2)
            {
                why = "You need to either: (1) give -output git -gitroot <some_path> (2) give -output inplace but not both";
                RBLogger.Error(why);
            }
            return(ok & ok2);
        }
Exemple #5
0
 internal static void PrintUsage(string error = null)
 {
     if (error != null)
     {
         RBLogger.Error("Error in parsing the command line: {0}", error);
     }
     RBLogger.Error("USAGE: $ ReviewBot.exe <cccheckoutput.xml> -project <projectfile> -solution <solutionfile> -output [inplace|git -gitroot <gitdirectory>]");
 }
Exemple #6
0
        public static ReplacementDictionary PrecomputeReplacementNodes(SyntaxDictionary annotationsByNode, Compilation compilation)
        {
            #region CodeContracts
            Contract.Requires(annotationsByNode != null);
            Contract.Requires(compilation != null);
            Contract.Ensures(Contract.Result <ReplacementDictionary>() != null);
            #endregion CodeContracts

            Output.WriteLine("Precomputing the replacement nodes");

            //GetContractRequiresSymbols(comp);
            var newdict = new ReplacementDictionary();
            foreach (var oldkvp in annotationsByNode)
            {
                var oldsubdict = oldkvp.Value;
                var oldfile    = oldkvp.Key;
                var newsubdict = new Dictionary <SyntaxNode, SyntaxNode>();
                if (!oldsubdict.Any())
                {
                    continue;              /* TODO is this right? we have a node with no annotations? */
                }
                SemanticModel = compilation.GetSemanticModel(oldsubdict.First().Key.SyntaxTree);
                Compilation   = compilation;
                foreach (var oldnode in oldsubdict.Keys)
                {
                    switch (oldnode.CSharpKind())
                    {
                    case SyntaxKind.MethodDeclaration:
                    case SyntaxKind.ConstructorDeclaration:
                    case SyntaxKind.SetAccessorDeclaration:
                    case SyntaxKind.GetAccessorDeclaration:
                    case SyntaxKind.AddAccessorDeclaration:    // who knew this was a thing? maybe this will work
                    case SyntaxKind.RemoveAccessorDeclaration: // who knew this was a thing? maybe this will work
                        //var oldmethod = oldnode as BaseMethodDeclarationSyntax;
                        //var newmethod = PrecomputeNewMethod(oldmethod, oldsubdict[oldnode]);
                        //if (oldnode.GetText().ToString().Contains("ObjectInvariant")) { int x; }
                        var newmethod = PrecomputeNewMethod(oldnode, oldsubdict[oldnode]);
                        newsubdict.Add(oldnode, newmethod);
                        continue;

                    case SyntaxKind.FieldDeclaration:
                        continue; // we don't need to do anything to read only fields at this point

                    default:
                        RBLogger.Error("Unhandled SyntaxNode kind {0}", oldnode.CSharpKind());
                        // Debug.Assert(false); // unhandled annotation type
                        continue;
                    }
                }
                newdict.Add(oldfile, newsubdict);
            }
            return(newdict);
        }
Exemple #7
0
 private static void ReplaceStatement(StatementSyntax original,
                                      StatementSyntax replacement,
                                      IEnumerable <StatementSyntax> requires,
                                      IEnumerable <StatementSyntax> ensures,
                                      IEnumerable <StatementSyntax> assumes,
                                      IEnumerable <StatementSyntax> other,
                                      out IEnumerable <StatementSyntax> newrequires,
                                      out IEnumerable <StatementSyntax> newensures,
                                      out IEnumerable <StatementSyntax> newassumes,
                                      out IEnumerable <StatementSyntax> newother)
 {
     newassumes  = assumes;
     newrequires = requires;
     newensures  = ensures;
     newother    = other;
     if (IsEnsures(original))
     {
         newensures = ensures.Select(x => x == original ? replacement : x);
     }
     else if (IsRequires(original))
     {
         newrequires = requires.Select(x => x == original ? replacement : x);
     }
     else if (IsAssumes(original))
     {
         newassumes = assumes.Select(x => x == original ? replacement : x);
     }
     else if (other.Contains(original))
     {
         newother = other.Select(x => x == original ? replacement : x);
     }
     else
     {
         RBLogger.Error("The original statement should have been an ensure, require, or assume");
         Debug.Assert(false);
     }
 }
Exemple #8
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 #9
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 #10
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);
        }
Exemple #11
0
        /// <summary>
        /// Parse the args into an Option object
        /// </summary>
        /// <param name="args">the args param to Main</param>
        /// <param name="options">the parsed arguements, valid if return is ture</param>
        /// <param name="why">an error message if parsing fails and the return is false</param>
        /// <returns>true if parsing succeeded, false otherwise</returns>
        internal static bool TryParseOptions(string[] args, out Options options, out string why)
        {
            #region CodeContracts
            Contract.Requires(Contract.ForAll(args, arg => arg != null));
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out options) != null);
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out options).Project != null);
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out options).Solution != null);
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out options).ClousotXML != null);
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out options).Output != OutputOption.unintialized);
            Contract.Ensures(Contract.Result <bool>() || Contract.ValueAtReturn(out why) != null);
            // there should be a contract for the output option, but it's complicated
            //Contract.Ensures(
            //    !Contract.Result<bool>()
            // || ((Contract.ValueAtReturn(out options).Output == OutputOption.git && Contract.ValueAtReturn(out options).GitRoot != null)
            //    ^ (Contract.ValueAtReturn(out options).Output == OutputOption.inplace))
            //);
            #endregion CodeContracts

            options = new Options();
            why     = null;

            for (var i = 0; i < args.Length; i++)
            {
                var arg = args[i];
                if (IsOption(arg, out arg))
                {
                    switch (arg)
                    {
                    case "project":
                        if (i == args.Length - 1)
                        {
                            why = "The last argument can't be a keyword";
                            return(false);
                        }
                        options.Project = args[++i];
                        break;

                    case "source":
                        if (i == args.Length - 1)
                        {
                            why = "The last argument can't be a keyword";
                            return(false);
                        }
                        options.SourceFile = args[++i];
                        break;

                    case "break":
                        System.Diagnostics.Debugger.Launch();
                        break;

                    case "solution":
                        if (i == args.Length - 1)
                        {
                            why = "The last argument can't be a keyword";
                            return(false);
                        }
                        options.Solution = args[++i];
                        break;

                    case "output":
                        if (i == args.Length - 1)
                        {
                            why = "The last argument can't be a keyword";
                            return(false);
                        }
                        OutputOption oo;
                        if (Enum.TryParse(args[++i], true, out oo))
                        {
                            options.Output = oo;
                        }
                        else
                        {
                            why = "Unrecognized output option: " + args[i];
                            return(false);
                        }
                        break;

                    case "gitroot":
                        if (i == args.Length - 1)
                        {
                            why = "The last argument can't be a keyword";
                            return(false);
                        }
                        options.GitRoot = args[++i];
                        if (!Directory.Exists(options.GitRoot))
                        {
                            why = "git root directory must exist";
                            return(false);
                        }
                        break;

                    default:
                        options = null;
                        why     = "Unrecognized option " + arg;
                        RBLogger.Error("Invalid option {0}", arg);
                        return(false);
                    }
                }
                else
                {
                    if (options.ClousotXML != null)
                    {
                        why = "Cannot express two (or more) .xml files";
                        return(false);
                    }
                    else
                    {
                        options.ClousotXML = args[0];
                    }
                }
            }

            return(options.CheckRequiredArguments(ref why));
        }