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);
            }
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
 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
                    );
            }
        }
Esempio n. 16
0
 public CSharpEditAndContinueTestHelpers(TargetFramework targetFramework, Action <SyntaxNode> faultInjector = null)
 {
     _fxReferences = TargetFrameworkUtil.GetReferences(targetFramework);
     _analyzer     = new CSharpEditAndContinueAnalyzer(faultInjector);
 }