/// <summary> /// Apply the annotations, optionally remove errorenous annotations /// </summary> /// <param name="annotations">annotations to be applied</param> /// <param name="originalCompilation">compilation to annotate</param> /// <param name="project">originalCompilation's project</param> /// <param name="check_for_errors">if true, will remove annotations cause errors (according to Roslyn)</param> /// <returns>A modified version of originalCompilation with the annotations added</returns> private static Compilation ApplyAnnotations(IEnumerable <BaseAnnotation> annotations, Compilation originalCompilation, Project project, bool check_for_errors = true) { #region CodeContracts Contract.Requires(originalCompilation != null); Contract.Requires(annotations != null); Contract.Ensures(Contract.Result <Compilation>() != null); #endregion CodeContracts IEnumerable <BaseAnnotation> annotations2, annotations3; var newCompilation = originalCompilation; newCompilation = InterfaceAnnotationHelpers.CreateOrFindContractsClasses(annotations, project, newCompilation, out annotations2); newCompilation = ReadonlyHelpers.ReadonlyPass(annotations2, newCompilation); newCompilation = ObjectInvariantHelpers.ObjectInvariantPass(newCompilation, annotations2, out annotations3); var syntosugdict = Searcher.GetSyntaxNodeToAnnotationDict(newCompilation, annotations3); var syntosyndict = Replacer.PrecomputeReplacementNodes(syntosugdict, newCompilation); var comp2 = Replacer.RewriteCompilation(newCompilation, syntosyndict); var diagnostics = comp2.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error); if (diagnostics.Any() && check_for_errors) { Output.WriteLine("Fix the errors introduced by bad contracts"); Contract.Assert(annotations3.Count() == annotations.Count()); var filteredAnnotations = HelperForDiagnostics.FilterBadSuggestions(comp2, annotations3); // unresolve interface annotations, we're reverting to the original compilation and forgetting everything filteredAnnotations = filteredAnnotations.Select(x => x is ResolvedInterfaceAnnotation ? (x as ResolvedInterfaceAnnotation).OriginalAnnotation : x); filteredAnnotations = filteredAnnotations.Select(x => x is ResolvedObjectInvariant ? (x as ResolvedObjectInvariant).OriginalAnnotation : x); comp2 = ApplyAnnotations(filteredAnnotations, originalCompilation, project, false); } return(comp2); }
public static int DoAnnotate(string[] args) { #region CodeContracts Contract.Requires(args != null); Contract.Requires(Contract.ForAll(0, args.Length, i => args[i] != null)); Contract.Ensures(-1 <= Contract.Result <int>()); // we return 0 on success, -1 on failure #endregion CodeContracts // 1. parse the command line options Options options; String error; if (!Options.TryParseOptions(args, out options, out error)) { Options.PrintUsage(error); Output.WriteError("Can't parse the options"); return(-1); } // 2. Create a compilation using Roslyn Task <Compilation> compilationAsync; Compilation compilation; MSBuildWorkspace workspace; Project project; if (!RoslynInterface.TryCreateCompilation(options, out compilationAsync, out workspace, out project)) { Output.WriteError("Unable to create compilation"); return(-1); } // 3. Read Clousot XML CCCheckOutput xml; if (!XmlDoc.TryReadXml(options.ClousotXML, out xml)) { Output.WriteError("Unable to read XML"); return(-1); } compilation = compilationAsync.Result; // 4. Check for diagnostics in the solution Output.WritePhase("Checking whether the original project has errors"); var existingDiagnostics = compilation.GetDiagnostics(); if (existingDiagnostics.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error).Any()) { Output.WriteWarning("The original project has some errors"); HelperForDiagnostics.PrintDiagnostics(existingDiagnostics); } // 5. Annotate Output.WritePhase("Reading the Contracts from Clousot"); var annotations = Parser.GetAnnotationDictionary(xml); Output.WritePhase("Applying the annotations to the source code"); var newcomp = ApplyAnnotations(annotations, compilation, project, true); // 6. Pretty print result Output.WritePhase("Cleaning up the code"); newcomp = UsingHelpers.CleanImports(project, newcomp); // 7. Write result to disk Output.WritePhase("Writing result back to disk"); newcomp = Writer.WriteChanges(compilation, newcomp, options.Output == OutputOption.inplace); //CommentHelpers.WriteCommentsFile(xml, compilation, newcomp, options.GitRoot); return(0); }