protected void TestSelection(string codeWithMarker, bool expectedFail = false, CSharpParseOptions parseOptions = null) { using (var workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines(new[] { codeWithMarker }, parseOptions: parseOptions)) { var testDocument = workspace.Documents.Single(); var namedSpans = testDocument.AnnotatedSpans; var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = document.Project.Solution.Workspace.Options .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, true); var semanticDocument = SemanticDocument.CreateAsync(document, CancellationToken.None).Result; var validator = new CSharpSelectionValidator(semanticDocument, namedSpans["b"].Single(), options); var result = validator.GetValidSelectionAsync(CancellationToken.None).Result; Assert.True(expectedFail ? result.Status.Failed() : result.Status.Succeeded()); if ((result.Status.Succeeded() || result.Status.Flag.HasBestEffort()) && result.Status.Flag.HasSuggestion()) { Assert.Equal(namedSpans["r"].Single(), result.FinalSpan); } } }
protected static async Task IterateAllAsync(string code) { using var workspace = TestWorkspace.CreateCSharp(code, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); Assert.NotNull(document); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var root = await document.GetSyntaxRootAsync(); var iterator = root.DescendantNodesAndSelf().Cast <SyntaxNode>(); var originalOptions = await document.GetOptionsAsync(); foreach (var node in iterator) { var validator = new CSharpSelectionValidator(semanticDocument, node.Span, localFunction: false, originalOptions); var result = await validator.GetValidSelectionAsync(CancellationToken.None); // check the obvious case if (!(node is ExpressionSyntax) && !node.UnderValidContext()) { Assert.True(result.Status.FailedWithNoBestEffortSuggestion()); } } }
protected void IterateAll(string code) { using (var workspace = CSharpWorkspaceFactory.CreateWorkspaceFromLines(new string[] { code }, CodeAnalysis.CSharp.Test.Utilities.TestOptions.Regular)) { var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); Assert.NotNull(document); var semanticDocument = SemanticDocument.CreateAsync(document, CancellationToken.None).Result; var tree = document.GetSyntaxTreeAsync().Result; var iterator = tree.GetRoot().DescendantNodesAndSelf().Cast <SyntaxNode>(); var options = document.Project.Solution.Workspace.Options .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, true); foreach (var node in iterator) { try { var validator = new CSharpSelectionValidator(semanticDocument, node.Span, options); var result = validator.GetValidSelectionAsync(CancellationToken.None).Result; // check the obvious case if (!(node is ExpressionSyntax) && !node.UnderValidContext()) { Assert.True(result.Status.FailedWithNoBestEffortSuggestion()); } } catch (ArgumentException) { // catch and ignore unknown issue. currently control flow analysis engine doesn't support field initializer. } } } }
public static async Task <bool> IsValid(MonoDevelop.Ide.Gui.Document doc, CancellationToken cancellationToken = default(CancellationToken)) { if (doc == null) { return(false); } if (doc.Editor == null || !doc.Editor.IsSomethingSelected) { return(false); } var ad = doc.AnalysisDocument; if (ad == null) { return(false); } var selectionRange = doc.Editor.SelectionRange; try { var selection = new CSharpSelectionValidator(await SemanticDocument.CreateAsync(ad, cancellationToken).ConfigureAwait(false), new TextSpan(selectionRange.Offset, selectionRange.Length), doc.GetOptionSet()); var result = await selection.GetValidSelectionAsync(cancellationToken).ConfigureAwait(false); return(result.ContainsValidContext); } catch (Exception) { return(false); } }
protected static async Task <SyntaxNode> ExtractMethodAsync( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool dontPutOutOrRefOnStruct = true, bool allowBestEffort = false ) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var originalOptions = await document.GetOptionsAsync(); var options = originalOptions.WithChangedOption( ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct ); var semanticDocument = await SemanticDocument.CreateAsync( document, CancellationToken.None ); var validator = new CSharpSelectionValidator( semanticDocument, testDocument.SelectedSpans.Single(), options ); var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None); if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) { return(null); } Assert.True(selectedCode.ContainsValidContext); // extract method var extractor = new CSharpMethodExtractor( (CSharpSelectionResult)selectedCode, localFunction: false ); var result = await extractor.ExtractMethodAsync(CancellationToken.None); Assert.NotNull(result); Assert.Equal( succeed, result.Succeeded || result.SucceededWithSuggestion || (allowBestEffort && result.Status.HasBestEffort()) ); var doc = result.Document; return(doc == null ? null : await doc.GetSyntaxRootAsync()); }
public async static Task Run(MonoDevelop.Ide.Gui.Document doc) { if (!doc.Editor.IsSomethingSelected) { return; } var ad = doc.AnalysisDocument; if (ad == null || !await IsValid(doc)) { return; } try { var selectionRange = doc.Editor.SelectionRange; var token = default(CancellationToken); var selection = new CSharpSelectionValidator(await SemanticDocument.CreateAsync(ad, token).ConfigureAwait(false), new TextSpan(selectionRange.Offset, selectionRange.Length), doc.GetOptionSet()); var result = await selection.GetValidSelectionAsync(token).ConfigureAwait(false); if (!result.ContainsValidContext) { return; } var extractor = new CSharpMethodExtractor((CSharpSelectionResult)result); var extractionResult = await extractor.ExtractMethodAsync(token).ConfigureAwait(false); var changes = await extractionResult.Document.GetTextChangesAsync(ad, token); using (var undo = doc.Editor.OpenUndoGroup()) { foreach (var change in changes.OrderByDescending(ts => ts.Span.Start)) { doc.Editor.ReplaceText(change.Span.Start, change.Span.Length, change.NewText); } // hack to remove the redundant private modifier. if (doc.Editor.GetTextAt(extractionResult.MethodDeclarationNode.SpanStart, "private ".Length) == "private ") { doc.Editor.RemoveText(extractionResult.MethodDeclarationNode.SpanStart, "private ".Length); } } await doc.UpdateParseDocument(); var info = RefactoringSymbolInfo.GetSymbolInfoAsync(doc, extractionResult.InvocationNameToken.Span.Start).Result; var sym = info.DeclaredSymbol ?? info.Symbol; if (sym != null) { await new MonoDevelop.Refactoring.Rename.RenameRefactoring().Rename(sym); } } catch (Exception e) { LoggingService.LogError("Error while extracting method", e); } }
protected static async Task <SyntaxNode> ExtractMethodAsync( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool dontPutOutOrRefOnStruct = true, bool allowBestEffort = false) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = new ExtractMethodGenerationOptions( ExtractOptions: new ExtractMethodOptions(dontPutOutOrRefOnStruct), CodeGenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), AddImportOptions: AddImportPlacementOptions.Default, NamingPreferences: _ => NamingStylePreferences.Default); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options.ExtractOptions, localFunction: false); var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None); if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) { return(null); } Assert.True(selectedCode.ContainsValidContext); // extract method var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, options, localFunction: false); var result = await extractor.ExtractMethodAsync(CancellationToken.None); Assert.NotNull(result); Assert.Equal(succeed, result.Succeeded || result.SucceededWithSuggestion || (allowBestEffort && result.Status.HasBestEffort())); var(doc, _) = await result.GetFormattedDocumentAsync(CodeCleanupOptions.GetDefault(document.Project.LanguageServices), CancellationToken.None); return(doc == null ? null : await doc.GetSyntaxRootAsync()); }
protected static async Task TestSelectionAsync( string codeWithMarker, bool expectedFail = false, CSharpParseOptions parseOptions = null, TextSpan?textSpanOverride = null ) { using var workspace = TestWorkspace.CreateCSharp( codeWithMarker, parseOptions: parseOptions ); var testDocument = workspace.Documents.Single(); var namedSpans = testDocument.AnnotatedSpans; var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = await document.GetOptionsAsync(CancellationToken.None); var semanticDocument = await SemanticDocument.CreateAsync( document, CancellationToken.None ); var validator = new CSharpSelectionValidator( semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), options ); var result = await validator.GetValidSelectionAsync(CancellationToken.None); Assert.True(expectedFail ? result.Status.Failed() : result.Status.Succeeded()); if ( (result.Status.Succeeded() || result.Status.Flag.HasBestEffort()) && result.Status.Flag.HasSuggestion() ) { Assert.Equal(namedSpans["r"].Single(), result.FinalSpan); } }
protected static SyntaxNode ExtractMethod( TestWorkspace workspace, TestHostDocument testDocument, bool succeed = true, bool allowMovingDeclaration = true, bool dontPutOutOrRefOnStruct = true) { var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); var options = document.Project.Solution.Workspace.Options .WithChangedOption(ExtractMethodOptions.AllowMovingDeclaration, document.Project.Language, allowMovingDeclaration) .WithChangedOption(ExtractMethodOptions.DontPutOutOrRefOnStruct, document.Project.Language, dontPutOutOrRefOnStruct); var semanticDocument = SemanticDocument.CreateAsync(document, CancellationToken.None).Result; var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options); var selectedCode = validator.GetValidSelectionAsync(CancellationToken.None).Result; if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) { return(null); } Assert.True(selectedCode.ContainsValidContext); // extract method var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode); var result = extractor.ExtractMethodAsync(CancellationToken.None).Result; Assert.NotNull(result); Assert.Equal(succeed, result.Succeeded || result.SucceededWithSuggestion); return((SyntaxNode)result.Document.GetSyntaxRootAsync().Result); }