public async Task AnalyzeDocumentAsync_SyntaxError_Change() { string source1 = @" class C { public static void Main() { System.Console.WriteLine(1) // syntax error } } "; string source2 = @" class C { public static void Main() { System.Console.WriteLine(2) // syntax error } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromLinesAsync(source1)) { var documentId = workspace.CurrentSolution.Projects.First().Documents.First().Id; var oldSolution = workspace.CurrentSolution; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var baseActiveStatements = ImmutableArray.Create <ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(oldSolution, baseActiveStatements, newSolution.GetDocument(documentId), default(CancellationToken)); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.True(result.HasChangesAndCompilationErrors); } }
public async Task AnalyzeDocumentAsync_SyntaxError_NoChange() { var source = @" class C { public static void Main() { System.Console.WriteLine(1) // syntax error } } "; using var workspace = TestWorkspace.CreateCSharp(source, composition: s_composition); var oldProject = workspace.CurrentSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var baseActiveStatements = ImmutableArray.Create <ActiveStatement>(); var analyzer = new CSharpEditAndContinueAnalyzer(); var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, ImmutableArray <TextSpan> .Empty, CancellationToken.None); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); Assert.False(result.HasChangesAndCompilationErrors); }
public async Task AnalyzeDocumentAsync_SyntaxError_NoChange() { string source = @" class C { public static void Main() { System.Console.WriteLine(1) // syntax error } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = TestWorkspace.CreateCSharp(source)) { var document = workspace.CurrentSolution.Projects.First().Documents.First(); var baseActiveStatements = ImmutableArray.Create <ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(workspace.CurrentSolution, baseActiveStatements, document, default(CancellationToken)); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); Assert.False(result.HasChangesAndCompilationErrors); } }
public async Task AnalyzeDocumentAsync_SyntaxError_Change() { var source1 = @" class C { public static void Main() { System.Console.WriteLine(1) // syntax error } } "; var source2 = @" class C { public static void Main() { System.Console.WriteLine(2) // syntax error } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using var workspace = TestWorkspace.CreateCSharp(source1); var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var baseActiveStatements = ImmutableArray.Create <ActiveStatement>(); var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), trackingService : null, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.True(result.HasChangesAndCompilationErrors); }
public async Task AnalyzeDocumentAsync_AddingNewFile() { string source1 = @" namespace N { class C { public static void Main() { } } } "; string source2 = @" "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync(source1)) { // fork the solution to introduce a change var project = workspace.CurrentSolution.Projects.Single(); var newDocId = DocumentId.CreateNewId(project.Id); var oldSolution = workspace.CurrentSolution; var newSolution = oldSolution.AddDocument(newDocId, "foo.cs", SourceText.From(source2)); workspace.TryApplyChanges(newSolution); var newProject = newSolution.Projects.Single(); var changes = newProject.GetChanges(project); Assert.Equal(2, newProject.Documents.Count()); Assert.Equal(0, changes.GetChangedDocuments().Count()); Assert.Equal(1, changes.GetAddedDocuments().Count()); var changedDocuments = changes.GetChangedDocuments().Concat(changes.GetAddedDocuments()); var result = new List<DocumentAnalysisResults>(); var baseActiveStatements = ImmutableArray.Create<ActiveStatementSpan>(); foreach (var changedDocumentId in changedDocuments) { result.Add(await analyzer.AnalyzeDocumentAsync(oldSolution, baseActiveStatements, newProject.GetDocument(changedDocumentId), default(CancellationToken))); } Assert.True(result.IsSingle()); Assert.Equal(1, result.Single().RudeEditErrors.Count()); Assert.Equal(RudeEditKind.InsertFile, result.Single().RudeEditErrors.Single().Kind); } }
public async Task AnalyzeDocumentAsync_SemanticError_Change() { string source1 = @" class C { public static void Main() { System.Console.WriteLine(1); Bar(); // semantic error } } "; string source2 = @" class C { public static void Main() { System.Console.WriteLine(2); Bar(); // semantic error } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync(source1)) { var documentId = workspace.CurrentSolution.Projects.First().Documents.First().Id; var oldSolution = workspace.CurrentSolution; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var baseActiveStatements = ImmutableArray.Create<ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(oldSolution, baseActiveStatements, newSolution.GetDocument(documentId), default(CancellationToken)); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.True(result.HasChangesAndCompilationErrors); } }
public async Task AnalyzeDocumentAsync_SemanticError_NoChange() { string source = @" class C { public static void Main() { System.Console.WriteLine(1); Bar(); // semantic error } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync(source)) { var document = workspace.CurrentSolution.Projects.First().Documents.First(); var baseActiveStatements = ImmutableArray.Create<ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(workspace.CurrentSolution, baseActiveStatements, document, default(CancellationToken)); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); Assert.False(result.HasChangesAndCompilationErrors); } }
public async Task AnalyzeDocumentAsync_Features_Change() { // these are all the experimental features currently implemented string[] experimentalFeatures = Array.Empty<string>(); foreach (var feature in experimentalFeatures) { string source1 = @" class C { public static void Main() { System.Console.WriteLine(1); } } "; string source2 = @" class C { public static void Main() { System.Console.WriteLine(2); } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); var featuresToEnable = new Dictionary<string, string>() { { feature, "enabled" } }; var experimental = TestOptions.Regular.WithFeatures(featuresToEnable); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync( source1, parseOptions: experimental, compilationOptions: null, exportProvider: null)) { var documentId = workspace.CurrentSolution.Projects.First().Documents.First().Id; var oldSolution = workspace.CurrentSolution; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var baseActiveStatements = ImmutableArray.Create<ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(oldSolution, baseActiveStatements, newSolution.GetDocument(documentId), default(CancellationToken)); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.False(result.HasChangesAndCompilationErrors); Assert.Equal(RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEditErrors.Single().Kind); } } }
public async Task AnalyzeDocumentAsync_Features_NoChange() { string source = @" class C { public static void Main() { System.Console.WriteLine(1); } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); var experimentalFeatures = new Dictionary<string, string>(); // no experimental features to enable var experimental = TestOptions.Regular.WithFeatures(experimentalFeatures); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync( source, parseOptions: experimental, compilationOptions: null, exportProvider: null)) { var document = workspace.CurrentSolution.Projects.First().Documents.First(); var baseActiveStatements = ImmutableArray.Create<ActiveStatementSpan>(); var result = await analyzer.AnalyzeDocumentAsync(workspace.CurrentSolution, baseActiveStatements, document, default(CancellationToken)); Assert.False(result.HasChanges); Assert.False(result.HasChangesAndErrors); Assert.False(result.HasChangesAndCompilationErrors); Assert.True(result.RudeEditErrors.IsDefaultOrEmpty); } }
public async Task AnalyzeDocumentAsync_InsignificantChangesInMethodBody() { string source1 = @" class C { public static void Main() { // comment System.Console.WriteLine(1); } } "; string source2 = @" class C { public static void Main() { System.Console.WriteLine(1); } } "; var analyzer = new CSharpEditAndContinueAnalyzer(); using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFileAsync(source1)) { var documentId = workspace.CurrentSolution.Projects.First().Documents.First().Id; var oldSolution = workspace.CurrentSolution; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var oldDocument = oldSolution.GetDocument(documentId); var oldText = await oldDocument.GetTextAsync(); var oldSyntaxRoot = await oldDocument.GetSyntaxRootAsync(); var newDocument = newSolution.GetDocument(documentId); var newText = await newDocument.GetTextAsync(); var newSyntaxRoot = await newDocument.GetSyntaxRootAsync(); const string oldStatementSource = "System.Console.WriteLine(1);"; var oldStatementPosition = source1.IndexOf(oldStatementSource, StringComparison.Ordinal); var oldStatementTextSpan = new TextSpan(oldStatementPosition, oldStatementSource.Length); var oldStatementSpan = oldText.Lines.GetLinePositionSpan(oldStatementTextSpan); var oldStatementSyntax = oldSyntaxRoot.FindNode(oldStatementTextSpan); var baseActiveStatements = ImmutableArray.Create(new ActiveStatementSpan(ActiveStatementFlags.LeafFrame, oldStatementSpan)); var result = await analyzer.AnalyzeDocumentAsync(oldSolution, baseActiveStatements, newDocument, default(CancellationToken)); Assert.True(result.HasChanges); Assert.True(result.SemanticEdits[0].PreserveLocalVariables); var syntaxMap = result.SemanticEdits[0].SyntaxMap; var newStatementSpan = result.ActiveStatements[0]; var newStatementTextSpan = newText.Lines.GetTextSpan(newStatementSpan); var newStatementSyntax = newSyntaxRoot.FindNode(newStatementTextSpan); var oldStatementSyntaxMapped = syntaxMap(newStatementSyntax); Assert.Same(oldStatementSyntax, oldStatementSyntaxMapped); } }
public async Task AnalyzeDocumentAsync_InsignificantChangesInMethodBody() { var source1 = @" class C { public static void Main() { // comment System.Console.WriteLine(1); } } "; var source2 = @" class C { public static void Main() { System.Console.WriteLine(1); } } "; using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var oldText = await oldDocument.GetTextAsync(); var oldSyntaxRoot = await oldDocument.GetSyntaxRootAsync(); var documentId = oldDocument.Id; var newSolution = workspace.CurrentSolution.WithDocumentText(documentId, SourceText.From(source2)); var newDocument = newSolution.GetDocument(documentId); var newText = await newDocument.GetTextAsync(); var newSyntaxRoot = await newDocument.GetSyntaxRootAsync(); const string oldStatementSource = "System.Console.WriteLine(1);"; var oldStatementPosition = source1.IndexOf(oldStatementSource, StringComparison.Ordinal); var oldStatementTextSpan = new TextSpan(oldStatementPosition, oldStatementSource.Length); var oldStatementSpan = oldText.Lines.GetLinePositionSpan(oldStatementTextSpan); var oldStatementSyntax = oldSyntaxRoot.FindNode(oldStatementTextSpan); var baseActiveStatements = ImmutableArray.Create(ActiveStatementsDescription.CreateActiveStatement(ActiveStatementFlags.IsLeafFrame, oldStatementSpan, DocumentId.CreateNewId(ProjectId.CreateNewId()))); var spanTracker = Assert.IsType <TestActiveStatementSpanTracker>(workspace.Services.GetRequiredService <IActiveStatementSpanTrackerFactory>().GetOrCreateActiveStatementSpanTracker()); var analyzer = new CSharpEditAndContinueAnalyzer(spanTracker); var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newDocument, CancellationToken.None); Assert.True(result.HasChanges); Assert.True(result.SemanticEdits[0].PreserveLocalVariables); var syntaxMap = result.SemanticEdits[0].SyntaxMap; var newStatementSpan = result.ActiveStatements[0].Span; var newStatementTextSpan = newText.Lines.GetTextSpan(newStatementSpan); var newStatementSyntax = newSyntaxRoot.FindNode(newStatementTextSpan); var oldStatementSyntaxMapped = syntaxMap(newStatementSyntax); Assert.Same(oldStatementSyntax, oldStatementSyntaxMapped); }
public CSharpEditAndContinueTestHelpers(Action <SyntaxNode>?faultInjector = null) { _analyzer = new CSharpEditAndContinueAnalyzer(faultInjector); }
public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) { var source1 = @"class C {}"; var source2 = @"class C { int x; }"; using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); var oldProject = workspace.CurrentSolution.Projects.Single(); var documentId = DocumentId.CreateNewId(oldProject.Id); var oldSolution = workspace.CurrentSolution; var newSolution = oldSolution.AddDocument( documentId, "goo.cs", SourceText.From(source2), filePath: "src.cs" ); var newProject = newSolution.Projects.Single(); var newDocument = newProject.GetDocument(documentId); var newSyntaxTree = await newDocument.GetSyntaxTreeAsync().ConfigureAwait(false); workspace.TryApplyChanges(newSolution); var baseActiveStatements = ImmutableArray.Create <ActiveStatement>(); var analyzer = new CSharpEditAndContinueAnalyzer( node => { if (node is CompilationUnitSyntax) { throw outOfMemory ? new OutOfMemoryException() : new NullReferenceException("NullRef!"); } } ); var result = await analyzer.AnalyzeDocumentAsync( oldProject, baseActiveStatements, newDocument, ImmutableArray <TextSpan> .Empty, CancellationToken.None ); var expectedDiagnostic = outOfMemory ? $"ENC0089: {string.Format(FeaturesResources.Modifying_source_file_will_prevent_the_debug_session_from_continuing_because_the_file_is_too_big, "src.cs")}" : // Because the error message that is formatted into this template string includes a stacktrace with newlines, we need to replicate that behavior // here so that any trailing punctuation is removed from the translated template string. $"ENC0080: {string.Format(FeaturesResources.Modifying_source_file_will_prevent_the_debug_session_from_continuing_due_to_internal_error, "src.cs", "System.NullReferenceException: NullRef!\n")}" .Split('\n') .First(); AssertEx.Equal( new[] { expectedDiagnostic }, result.RudeEditErrors .Select(d => d.ToDiagnostic(newSyntaxTree)) .Select( d => $"{d.Id}: {d.GetMessage().Split(new[] { Environment.NewLine }, StringSplitOptions.None).First()}" ) ); }
public async Task AnalyzeDocumentAsync_AddingNewFile() { var source1 = @" namespace N { class C { public static void Main() { } } } "; var source2 = @" class D { } "; using var workspace = TestWorkspace.CreateCSharp(source1, composition: s_composition); var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var newDocId = DocumentId.CreateNewId(oldProject.Id); var newSolution = oldSolution.AddDocument(newDocId, "goo.cs", SourceText.From(source2)); workspace.TryApplyChanges(newSolution); var newProject = newSolution.Projects.Single(); var changes = newProject.GetChanges(oldProject); Assert.Equal(2, newProject.Documents.Count()); Assert.Equal(0, changes.GetChangedDocuments().Count()); Assert.Equal(1, changes.GetAddedDocuments().Count()); var changedDocuments = changes .GetChangedDocuments() .Concat(changes.GetAddedDocuments()); var result = new List <DocumentAnalysisResults>(); var baseActiveStatements = ImmutableArray.Create <ActiveStatement>(); var analyzer = new CSharpEditAndContinueAnalyzer(); foreach (var changedDocumentId in changedDocuments) { result.Add( await analyzer.AnalyzeDocumentAsync( oldProject, baseActiveStatements, newProject.GetDocument(changedDocumentId), ImmutableArray <TextSpan> .Empty, CancellationToken.None ) ); } Assert.True(result.IsSingle()); Assert.Empty(result.Single().RudeEditErrors); }
public async Task AnalyzeDocumentAsync_Features_Change() { // these are all the experimental features currently implemented var experimentalFeatures = Array.Empty <string>(); foreach (var feature in experimentalFeatures) { var source1 = @" class C { public static void Main() { System.Console.WriteLine(1); } } "; var source2 = @" class C { public static void Main() { System.Console.WriteLine(2); } } "; var featuresToEnable = new Dictionary <string, string>() { { feature, "enabled" } }; var experimental = TestOptions.Regular.WithFeatures(featuresToEnable); using var workspace = TestWorkspace.CreateCSharp( source1, parseOptions: experimental, compilationOptions: null, exportProvider: null ); var oldSolution = workspace.CurrentSolution; var oldProject = oldSolution.Projects.Single(); var oldDocument = oldProject.Documents.Single(); var documentId = oldDocument.Id; var newSolution = workspace.CurrentSolution.WithDocumentText( documentId, SourceText.From(source2) ); var baseActiveStatements = ImmutableArray.Create <ActiveStatement>(); var analyzer = new CSharpEditAndContinueAnalyzer(); var result = await analyzer.AnalyzeDocumentAsync( oldProject, baseActiveStatements, newSolution.GetDocument(documentId), ImmutableArray <TextSpan> .Empty, CancellationToken.None ); Assert.True(result.HasChanges); Assert.True(result.HasChangesAndErrors); Assert.False(result.HasChangesAndSyntaxErrors); Assert.Equal( RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEditErrors.Single().Kind ); } }
public CSharpEditAndContinueTestHelpers(TargetFramework targetFramework, Action <SyntaxNode> faultInjector = null) { _fxReferences = TargetFrameworkUtil.GetReferences(targetFramework); _analyzer = new CSharpEditAndContinueAnalyzer(faultInjector); }