public async Task AnalyzeDocumentAsync_SemanticError_NoChange()
        {
            var source   = @"
class C
{
    public static void Main()
    {
        System.Console.WriteLine(1);
        Bar(); // semantic error
    }
}
";
            var analyzer = new CSharpEditAndContinueAnalyzer();

            using var workspace = TestWorkspace.CreateCSharp(source);

            var oldSolution = workspace.CurrentSolution;
            var oldProject  = oldSolution.Projects.Single();
            var oldDocument = oldProject.Documents.Single();
            var documentId  = oldDocument.Id;

            var baseActiveStatements = ImmutableArray.Create <ActiveStatement>();
            var spanTracker          = new TestActiveStatementSpanTracker();

            var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, spanTracker, CancellationToken.None);

            Assert.False(result.HasChanges);
            Assert.False(result.HasChangesAndErrors);
            Assert.False(result.HasChangesAndCompilationErrors);
        }
        public async Task AnalyzeDocumentAsync_Features_NoChange()
        {
            var 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 = TestWorkspace.CreateCSharp(
                      source, 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 baseActiveStatements = ImmutableArray.Create <ActiveStatement>();
            var spanTracker          = new TestActiveStatementSpanTracker();

            var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, oldDocument, spanTracker, CancellationToken.None);

            Assert.False(result.HasChanges);
            Assert.False(result.HasChangesAndErrors);
            Assert.False(result.HasChangesAndCompilationErrors);
            Assert.True(result.RudeEditErrors.IsEmpty);
        }
        public async Task AnalyzeDocumentAsync_AddingNewFileHavingRudeEdits()
        {
            var source1  = @"
namespace N
{
    class C
    {
        public static void Main()
        {
        }
    }
}
";
            var source2  = @"
namespace N
{
    public class D
    {
    }
}
";
            var analyzer = new CSharpEditAndContinueAnalyzer();

            using var workspace = TestWorkspace.CreateCSharp(source1);
            // fork the solution to introduce a change
            var oldProject  = workspace.CurrentSolution.Projects.Single();
            var newDocId    = DocumentId.CreateNewId(oldProject.Id);
            var oldSolution = workspace.CurrentSolution;
            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 spanTracker          = new TestActiveStatementSpanTracker();

            foreach (var changedDocumentId in changedDocuments)
            {
                result.Add(await analyzer.AnalyzeDocumentAsync(oldProject.GetDocument(changedDocumentId), baseActiveStatements, newProject.GetDocument(changedDocumentId), spanTracker, CancellationToken.None));
            }

            Assert.True(result.IsSingle());
            Assert.Equal(1, result.Single().RudeEditErrors.Count());
            Assert.Equal(RudeEditKind.Insert, result.Single().RudeEditErrors.Single().Kind);
        }
        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 analyzer = new CSharpEditAndContinueAnalyzer();

                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 spanTracker          = new TestActiveStatementSpanTracker();

                var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);

                Assert.True(result.HasChanges);
                Assert.True(result.HasChangesAndErrors);
                Assert.False(result.HasChangesAndCompilationErrors);
                Assert.Equal(RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEditErrors.Single().Kind);
            }
        }
        public async Task AnalyzeDocumentAsync_SemanticErrorInMethodBody_Change()
        {
            var source1  = @"
class C
{
    public static void Main()
    {
        System.Console.WriteLine(1);
        Bar(); // semantic error
    }
}
";
            var source2  = @"
class C
{
    public static void Main()
    {
        System.Console.WriteLine(2);
        Bar(); // semantic 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 spanTracker          = new TestActiveStatementSpanTracker();

            var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newSolution.GetDocument(documentId), spanTracker, CancellationToken.None);

            Assert.True(result.HasChanges);

            // no declaration errors (error in method body is only reported when emitting):
            Assert.False(result.HasChangesAndErrors);
            Assert.False(result.HasChangesAndCompilationErrors);
        }
        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);
    }
}
";
            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 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          = new TestActiveStatementSpanTracker();

            var result = await analyzer.AnalyzeDocumentAsync(oldDocument, baseActiveStatements, newDocument, spanTracker, 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);
        }