private IEnumerable <SearchResult> DoTheWorkToSearchTheCallers(string query) { // We should move this in the UI var selectionStart = this.wpfTextView.Selection.Start.Position.Position; var selectionEnd = this.wpfTextView.Selection.End.Position.Position; var results = new List <SearchResult>(); if (selectionStart == selectionEnd) { Trace.WriteLine(string.Format("Selection: {0}", selectionStart)); var container = wpfTextView.TextBuffer.AsTextContainer(); Workspace workspace; Workspace.TryGetWorkspace(container, out workspace); if (workspace != null) { Document doc; var docIds = workspace.GetRelatedDocumentIds(container); if (docIds.Any()) { var docId = docIds.First(); doc = Helper.OpenDocument(workspace, docId); var span = new Microsoft.CodeAnalysis.Text.TextSpan(selectionStart, 0); var syntaxNode = doc.GetSyntaxTree().GetRoot() as SyntaxNode; if (syntaxNode != null) { var methodFinder = EnclosingMethodFinder.GetMethodSpans(syntaxNode); BaseMethodDeclarationSyntax method; if (methodFinder.TryGetValueContainingSpan(span, out method)) { // Add the precondition var preAsStr = string.Format(CLOUSOT_QUERY_PRECONDITION, query); var pre = SyntaxFactory.ParseStatement(preAsStr + Environment.NewLine + Environment.NewLine); // F: adding two newlines as Roslyn for some reason pretty print the text in a different way, and loses one line at the end of the file var newMethod = method.InsertStatements(pre, ContractKind.Precondition); var newRoot = ((SyntaxNode)doc.GetSyntaxTree().GetRoot()).ReplaceNode(method, newMethod); // Create the new Roslyn environment var newSolution = doc.Project.Solution.WithDocumentText(doc.Id, newRoot.GetText()); //var newSolution = doc.Project.Solution.UpdateDocument(doc.Id, newRoot.GetText()); var locDocument = newSolution.GetDocument(doc.Id); var newTree = (CompilationUnitSyntax)locDocument.GetSyntaxTree().GetRoot(); try { Trace.WriteLine(string.Format("Annotated tree for the state:\n{0}", newRoot.GetText())); var run = new RoslynToCCICodeModel.ClousotGlue().AnalyzeMeAUnit(locDocument, newTree, new System.Threading.CancellationToken(), this.options, new string[] { "-warnscores:false", "-sortwarns:false", "-suggest:!!", "-show", "validations" }, false ); if (run == null) { return(new SearchResult[0]); } var fullString = preAsStr + Environment.NewLine; var injectedPrecondition = newRoot.DescendantNodes().OfType <StatementSyntax>().Where(s => s.GetText().ToString().Equals(fullString)).FirstOrDefault(); if (injectedPrecondition == null) { return(new SearchResult[0]); } var injectedPreconditionSpan = injectedPrecondition.Span; var newCodeIsBiggerBy = newMethod.FullSpan.Length - method.FullSpan.Length; foreach (var r in run) { Trace.WriteLine(string.Format("{0}: {1}", r.Message, r.outcome)); if (r.outcome.HasValue && // it is not a suggestion r.startPoint != null && r.RelatedLocationsWithSourceContext != null && r.RelatedLocationsWithSourceContext.Count() == 1 && // Guess: we want to have to only related to be our new contract r.Message.Contains("requires") // HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK : We should understand why sometimes r.RelatedLocationsWithSourceContext.Count() == 1, but the proof obligation is a non-null. From debugger seems that the related pc is the same as the original ) { var pc = r.RelatedLocationsWithSourceContext.First(); var startIndex = pc.Block.SourceStartIndex(pc); var length = pc.Block.SourceLength(pc); if (!injectedPreconditionSpan.Contains(new Microsoft.CodeAnalysis.Text.TextSpan(startIndex, length))) { continue; } // But if the pc is after the injected precondition, then need to substract off the // length of the injected text from the start position var realSpan = (r.Span.Start < startIndex) ? r.Span : new Microsoft.CodeAnalysis.Text.TextSpan(r.Span.Start - newCodeIsBiggerBy, r.Span.Length); //BaseMethodDeclarationSyntax caller; var loc = doc.GetSyntaxTree().GetLocation(realSpan); var caller = syntaxNode.DescendantNodes().OfType <MethodDeclarationSyntax>().Where(m => m.Span.Contains(realSpan)).FirstOrDefault(); if (caller != null) { var startLine = doc.GetSyntaxTree().GetLineSpan(realSpan, true).StartLinePosition.Line + 1; var startColumn = doc.GetSyntaxTree().GetLineSpan(realSpan, true).StartLinePosition.Character + 1; results.Add(new SearchResult(startLine, startColumn, caller, r.outcome.Value)); } else { Trace.WriteLine("Failed to find the containing method"); } } } } catch (Exception e) { Trace.WriteLine(string.Format("Some exception was thrown inside Clousot...\nDetails:\n{0}", e.ToString())); } } } } } } return(results); }
private IEnumerable <SearchResult> DoTheWorkToSearchTheCallers(string query) { // We should move this in the UI var selectionStart = this.wpfTextView.Selection.Start.Position.Position; var selectionEnd = this.wpfTextView.Selection.End.Position.Position; var results = new List <SearchResult>(); if (selectionStart == selectionEnd) { Trace.WriteLine(string.Format("Selection: {0}", selectionStart)); var container = wpfTextView.TextBuffer.AsTextContainer(); EditorWorkspace workspace; EditorWorkspace.TryGetWorkspace(container, out workspace); if (workspace != null) { Document doc; DocumentId docId; if (workspace.TryGetDocumentId(container, out docId)) { doc = Helper.OpenDocument(workspace, docId); var span = new Microsoft.CodeAnalysis.Text.TextSpan(selectionStart, 0); var syntaxNode = doc.GetSyntaxTree().GetRoot() as SyntaxNode; if (syntaxNode != null) { var methodFinder = EnclosingMethodFinder.GetMethodSpans(syntaxNode); BaseMethodDeclarationSyntax method; if (methodFinder.TryGetValueContainingSpan(span, out method)) { // Add the precondition var preAsStr = string.Format(CLOUSOT_QUERY_PRECONDITION, query); var pre = SyntaxFactory.ParseStatement(preAsStr + Environment.NewLine + Environment.NewLine); // F: adding two newlines as Roslyn for some reason pretty print the text in a different way, and loses one line at the end of the file var newMethod = method.InsertStatements(pre, ContractKind.Precondition); var newRoot = ((SyntaxNode)doc.GetSyntaxTree().GetRoot()).ReplaceNode(method, newMethod); // Create the new Roslyn environment var newSolution = doc.Project.Solution.WithDocumentText(doc.Id, new StringText(newRoot.GetText().ToString())); //var newSolution = doc.Project.Solution.UpdateDocument(doc.Id, new StringText(newRoot.GetText())); var locDocument = newSolution.GetDocument(doc.Id); var newTree = (CompilationUnitSyntax)locDocument.GetSyntaxTree().GetRoot(); try { Trace.WriteLine(string.Format("Annotated tree for the state:\n{0}", newRoot.GetText())); var run = new RoslynToCCICodeModel.ClousotGlue().AnalyzeMeAUnit(locDocument, newTree, new System.Threading.CancellationToken(), this.options, new string[] { "-warnscores:false", "-sortwarns:false", "-suggest:!!", "-show", "validations" }, false ); foreach (var r in run) { Trace.WriteLine(string.Format("{0}: {1}", r.Message, r.outcome)); if (r.outcome.HasValue && // it is not a suggestion r.startPoint != null && r.Message.Contains("Contract.Requires") && r.Message.Contains(query)) // we should do better than chekcing the string. This is very weak { BaseMethodDeclarationSyntax caller; if (methodFinder.TryGetValueContainingSpan(r.Span, out caller)) { var pair = r.startPoint; results.Add(new SearchResult(pair.Item1, pair.Item2, caller, r.outcome.Value)); } else { Trace.WriteLine("Failed to find the containing method"); } } } } catch (Exception e) { Trace.WriteLine(string.Format("Some exception was thrown inside Clousot...\nDetails:\n{0}", e.ToString())); } } } } } } return(results.Distinct()); }