Ejemplo n.º 1
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
            }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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>]");
 }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
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);
     }
 }
Ejemplo n.º 6
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);
        }
Ejemplo n.º 7
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));
        }