Example #1
0
            private IEnumerable <DiagnosticData> ConvertToLocalDiagnosticsWithCompilation(Document targetDocument, IEnumerable <Diagnostic> diagnostics, TextSpan?span = null)
            {
                var project = targetDocument.Project;

                Contract.ThrowIfFalse(project.SupportsCompilation);

                foreach (var diagnostic in diagnostics)
                {
                    var document = project.GetDocument(diagnostic.Location.SourceTree);
                    if (document == null || document != targetDocument)
                    {
                        continue;
                    }

                    if (span.HasValue && !span.Value.Contains(diagnostic.Location.SourceSpan))
                    {
                        continue;
                    }

                    yield return(DiagnosticData.Create(document, diagnostic));
                }
            }
Example #2
0
        internal DiagnosticData GetPrimaryDiagnosticData()
        {
            var diagnostic = PrimaryDiagnostic;

            if (diagnostic.Location.IsInSource)
            {
                var document = Project.GetDocument(diagnostic.Location.SourceTree);
                if (document != null)
                {
                    return(DiagnosticData.Create(diagnostic, document));
                }
            }
            else if (diagnostic.Location.Kind == LocationKind.ExternalFile)
            {
                var document = Project.Documents.FirstOrDefault(d => d.FilePath == diagnostic.Location.GetLineSpan().Path);
                if (document != null)
                {
                    return(DiagnosticData.Create(diagnostic, document));
                }
            }

            return(DiagnosticData.Create(diagnostic, Project));
        }
Example #3
0
            private void AddDiagnostics(
                ref Dictionary <DocumentId, List <DiagnosticData> > lazyLocals, SyntaxTree tree, IEnumerable <Diagnostic> diagnostics)
            {
                foreach (var diagnostic in diagnostics)
                {
                    // REVIEW: what is our plan for additional locations?
                    switch (diagnostic.Location.Kind)
                    {
                    case LocationKind.ExternalFile:
                    {
                        // TODO: currently additional file location is not supported.
                        break;
                    }

                    case LocationKind.None:
                    {
                        _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                        _lazyOthers.Add(DiagnosticData.Create(_project, diagnostic));
                        break;
                    }

                    case LocationKind.SourceFile:
                    {
                        if (tree != null && diagnostic.Location.SourceTree == tree)
                        {
                            var document = GetDocument(diagnostic);
                            if (document != null)
                            {
                                // local diagnostics to a file
                                lazyLocals = lazyLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                                lazyLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                                AddDocumentToSet(document);
                            }
                        }
                        else if (diagnostic.Location.SourceTree != null)
                        {
                            var document = _project.GetDocument(diagnostic.Location.SourceTree);
                            if (document != null)
                            {
                                // non local diagnostics to a file
                                _lazyNonLocals = _lazyNonLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                                _lazyNonLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                                AddDocumentToSet(document);
                            }
                        }
                        else
                        {
                            // non local diagnostics without location
                            _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                            _lazyOthers.Add(DiagnosticData.Create(_project, diagnostic));
                        }

                        break;
                    }

                    case LocationKind.MetadataFile:
                    case LocationKind.XmlFile:
                    {
                        // something we don't care
                        continue;
                    }

                    default:
                    {
                        Contract.Fail("should not reach");
                        break;
                    }
                    }
                }
            }
Example #4
0
            private void AddExternalDiagnostics(
                ref Dictionary <DocumentId, List <DiagnosticData> > lazyLocals, DocumentId documentId, IEnumerable <Diagnostic> diagnostics)
            {
                Contract.ThrowIfTrue(_project.SupportsCompilation);

                foreach (var diagnostic in diagnostics)
                {
                    // REVIEW: what is our plan for additional locations?
                    switch (diagnostic.Location.Kind)
                    {
                    case LocationKind.ExternalFile:
                    {
                        var diagnosticDocumentId = GetExternalDocumentId(diagnostic);
                        if (documentId == diagnosticDocumentId)
                        {
                            var document = _project.GetDocument(diagnosticDocumentId);
                            if (document != null)
                            {
                                // local diagnostics to a file
                                lazyLocals = lazyLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                                lazyLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                                AddDocumentToSet(document);
                            }
                        }
                        else if (diagnosticDocumentId != null)
                        {
                            var document = _project.GetDocument(diagnosticDocumentId);
                            if (document != null)
                            {
                                // non local diagnostics to a file
                                _lazyNonLocals = _lazyNonLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                                _lazyNonLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                                AddDocumentToSet(document);
                            }
                        }
                        else
                        {
                            // non local diagnostics without location
                            _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                            _lazyOthers.Add(DiagnosticData.Create(_project, diagnostic));
                        }

                        break;
                    }

                    case LocationKind.None:
                    {
                        _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                        _lazyOthers.Add(DiagnosticData.Create(_project, diagnostic));
                        break;
                    }

                    case LocationKind.SourceFile:
                    case LocationKind.MetadataFile:
                    case LocationKind.XmlFile:
                    {
                        // something we don't care
                        continue;
                    }

                    default:
                    {
                        Contract.Fail("should not reach");
                        break;
                    }
                    }
                }
            }
Example #5
0
 private static IEnumerable <DiagnosticData> GetDiagnosticData(Document document, SyntaxTree tree, TextSpan?span, IEnumerable <Diagnostic> diagnostics)
 {
     return(diagnostics != null?diagnostics.Where(dx => ShouldIncludeDiagnostic(dx, tree, span)).Select(d => DiagnosticData.Create(document, d)) : null);
 }
Example #6
0
            public async Task AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
            {
                // if closed file diagnostic is off and document is not opened, then don't do anything
                if (!_workspace.Options.GetOption(ServiceFeatureOnOffOptions.ClosedFileDiagnostic, document.Project.Language) && !document.IsOpen())
                {
                    return;
                }

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                var diagnostics = tree.GetDiagnostics(cancellationToken);

                Contract.Requires(document.Project.Solution.Workspace == _workspace);

                var diagnosticData = diagnostics == null ? ImmutableArray <DiagnosticData> .Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty();

                _service.RaiseDiagnosticsUpdated(
                    new DiagnosticsUpdatedArgs(new MiscUpdateArgsId(document.Id),
                                               _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData));
            }
Example #7
0
                                    DiagnosticData?syntaxError)> EmitSolutionUpdateAsync(
            Solution solution,
            ActiveStatementSpanProvider activeStatementSpanProvider,
            IDiagnosticAnalyzerService diagnosticService,
            EditAndContinueDiagnosticUpdateSource diagnosticUpdateSource,
            CancellationToken cancellationToken)
        {
            ManagedModuleUpdates            moduleUpdates;
            ImmutableArray <DiagnosticData> diagnosticData;
            ImmutableArray <(DocumentId DocumentId, ImmutableArray <RudeEditDiagnostic> Diagnostics)> rudeEdits;
            DiagnosticData?syntaxError;

            try
            {
                var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false);

                if (client == null)
                {
                    var results = await GetLocalService().EmitSolutionUpdateAsync(_sessionId, solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false);

                    moduleUpdates  = results.ModuleUpdates;
                    diagnosticData = results.GetDiagnosticData(solution);
                    rudeEdits      = results.RudeEdits;
                    syntaxError    = results.GetSyntaxErrorData(solution);
                }
                else
                {
                    var result = await client.TryInvokeAsync <IRemoteEditAndContinueService, EmitSolutionUpdateResults.Data>(
                        solution,
                        (service, solutionInfo, callbackId, cancellationToken) => service.EmitSolutionUpdateAsync(solutionInfo, callbackId, _sessionId, cancellationToken),
                        callbackTarget : new ActiveStatementSpanProviderCallback(activeStatementSpanProvider),
                        cancellationToken).ConfigureAwait(false);

                    if (result.HasValue)
                    {
                        moduleUpdates  = result.Value.ModuleUpdates;
                        diagnosticData = result.Value.Diagnostics;
                        rudeEdits      = result.Value.RudeEdits;
                        syntaxError    = result.Value.SyntaxError;
                    }
                    else
                    {
                        moduleUpdates  = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray <ManagedModuleUpdate> .Empty);
                        diagnosticData = ImmutableArray <DiagnosticData> .Empty;
                        rudeEdits      = ImmutableArray <(DocumentId DocumentId, ImmutableArray <RudeEditDiagnostic> Diagnostics)> .Empty;
                        syntaxError    = null;
                    }
                }
            }
            catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
            {
                var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(RudeEditKind.InternalError);

                var diagnostic = Diagnostic.Create(
                    descriptor,
                    Location.None,
                    string.Format(descriptor.MessageFormat.ToString(), "", e.Message));

                diagnosticData = ImmutableArray.Create(DiagnosticData.Create(diagnostic, project: null));
                rudeEdits      = ImmutableArray <(DocumentId DocumentId, ImmutableArray <RudeEditDiagnostic> Diagnostics)> .Empty;
                moduleUpdates  = new ManagedModuleUpdates(ManagedModuleUpdateStatus.RestartRequired, ImmutableArray <ManagedModuleUpdate> .Empty);
                syntaxError    = null;
            }

            // clear emit/apply diagnostics reported previously:
            diagnosticUpdateSource.ClearDiagnostics(isSessionEnding: false);

            // clear all reported rude edits:
            diagnosticService.Reanalyze(_workspace, documentIds: rudeEdits.Select(d => d.DocumentId));

            // report emit/apply diagnostics:
            diagnosticUpdateSource.ReportDiagnostics(_workspace, solution, diagnosticData, rudeEdits);

            return(moduleUpdates, diagnosticData, rudeEdits, syntaxError);
        }
        /// <summary>
        /// Gets <see cref="DiagnosticData"/> objects for error list entries, filtered based on the given parameters.
        /// </summary>
        public async Task <ImmutableArray <DiagnosticData> > GetItemsAsync(bool selectedEntriesOnly, bool isAddSuppression, bool isSuppressionInSource, bool onlyCompilerDiagnostics, CancellationToken cancellationToken)
        {
            var builder = ImmutableArray.CreateBuilder <DiagnosticData>();
            Dictionary <string, Project> projectNameToProjectMapOpt = null;
            Dictionary <Project, ImmutableDictionary <string, Document> > filePathToDocumentMapOpt = null;

            var entries = selectedEntriesOnly ? _tableControl.SelectedEntries : _tableControl.Entries;

            foreach (var entryHandle in entries)
            {
                cancellationToken.ThrowIfCancellationRequested();

                DiagnosticData diagnosticData = null;
                int            index;
                var            roslynSnapshot = GetEntriesSnapshot(entryHandle, out index);
                if (roslynSnapshot != null)
                {
                    diagnosticData = roslynSnapshot.GetItem(index)?.Primary;
                }
                else if (!isAddSuppression)
                {
                    // For suppression removal, we also need to handle FxCop entries.
                    bool isSuppressedEntry;
                    if (!IsNonRoslynEntrySupportingSuppressionState(entryHandle, out isSuppressedEntry) ||
                        !isSuppressedEntry)
                    {
                        continue;
                    }

                    string errorCode = null, category = null, message = null, filePath = null, projectName = null;
                    int    line     = -1; // FxCop only supports line, not column.
                    var    location = Location.None;

                    if (entryHandle.TryGetValue(StandardTableColumnDefinitions.ErrorCode, out errorCode) && !string.IsNullOrEmpty(errorCode) &&
                        entryHandle.TryGetValue(StandardTableColumnDefinitions.ErrorCategory, out category) && !string.IsNullOrEmpty(category) &&
                        entryHandle.TryGetValue(StandardTableColumnDefinitions.Text, out message) && !string.IsNullOrEmpty(message) &&
                        entryHandle.TryGetValue(StandardTableColumnDefinitions.ProjectName, out projectName) && !string.IsNullOrEmpty(projectName))
                    {
                        if (projectNameToProjectMapOpt == null)
                        {
                            projectNameToProjectMapOpt = new Dictionary <string, Project>();
                            foreach (var p in _workspace.CurrentSolution.Projects)
                            {
                                projectNameToProjectMapOpt[p.Name] = p;
                            }
                        }

                        cancellationToken.ThrowIfCancellationRequested();

                        Project project;
                        if (!projectNameToProjectMapOpt.TryGetValue(projectName, out project))
                        {
                            // bail out
                            continue;
                        }

                        Document document    = null;
                        var      hasLocation = (entryHandle.TryGetValue(StandardTableColumnDefinitions.DocumentName, out filePath) && !string.IsNullOrEmpty(filePath)) &&
                                               (entryHandle.TryGetValue(StandardTableColumnDefinitions.Line, out line) && line >= 0);
                        if (hasLocation)
                        {
                            if (string.IsNullOrEmpty(filePath) || line < 0)
                            {
                                // bail out
                                continue;
                            }

                            ImmutableDictionary <string, Document> filePathMap;
                            filePathToDocumentMapOpt = filePathToDocumentMapOpt ?? new Dictionary <Project, ImmutableDictionary <string, Document> >();
                            if (!filePathToDocumentMapOpt.TryGetValue(project, out filePathMap))
                            {
                                filePathMap = await GetFilePathToDocumentMapAsync(project, cancellationToken).ConfigureAwait(false);

                                filePathToDocumentMapOpt[project] = filePathMap;
                            }

                            if (!filePathMap.TryGetValue(filePath, out document))
                            {
                                // bail out
                                continue;
                            }

                            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                            var linePosition     = new LinePosition(line, 0);
                            var linePositionSpan = new LinePositionSpan(start: linePosition, end: linePosition);
                            var textSpan         = (await tree.GetTextAsync(cancellationToken).ConfigureAwait(false)).Lines.GetTextSpan(linePositionSpan);
                            location = tree.GetLocation(textSpan);
                        }

                        Contract.ThrowIfNull(project);
                        Contract.ThrowIfFalse((document != null) == location.IsInSource);

                        // Create a diagnostic with correct values for fields we care about: id, category, message, isSuppressed, location
                        // and default values for the rest of the fields (not used by suppression fixer).
                        var diagnostic = Diagnostic.Create(
                            id: errorCode,
                            category: category,
                            message: message,
                            severity: DiagnosticSeverity.Warning,
                            defaultSeverity: DiagnosticSeverity.Warning,
                            isEnabledByDefault: true,
                            warningLevel: 1,
                            isSuppressed: isSuppressedEntry,
                            title: message,
                            location: location,
                            customTags: SuppressionHelpers.SynthesizedExternalSourceDiagnosticCustomTags);

                        diagnosticData = document != null?
                                         DiagnosticData.Create(document, diagnostic) :
                                             DiagnosticData.Create(project, diagnostic);
                    }
                }

                if (IsEntryWithConfigurableSuppressionState(diagnosticData))
                {
                    var isCompilerDiagnostic = SuppressionHelpers.IsCompilerDiagnostic(diagnosticData);
                    if (onlyCompilerDiagnostics && !isCompilerDiagnostic)
                    {
                        continue;
                    }

                    if (isAddSuppression)
                    {
                        // Compiler diagnostics can only be suppressed in source.
                        if (!diagnosticData.IsSuppressed &&
                            (isSuppressionInSource || !isCompilerDiagnostic))
                        {
                            builder.Add(diagnosticData);
                        }
                    }
                    else if (diagnosticData.IsSuppressed)
                    {
                        builder.Add(diagnosticData);
                    }
                }
            }

            return(builder.ToImmutable());
        }
Example #9
0
 private static IEnumerable <DiagnosticData> GetDiagnosticData(Project project, IEnumerable <Diagnostic> diagnostics)
 {
     return(diagnostics != null?diagnostics.Select(d => DiagnosticData.Create(project, d)) : null);
 }
        public async Task Proxy(TestHost testHost)
        {
            var localComposition = EditorTestCompositions.EditorFeatures.WithTestHostParts(testHost);

            if (testHost == TestHost.InProcess)
            {
                localComposition = localComposition.AddParts(typeof(MockEncServiceFactory));
            }

            using var localWorkspace = new TestWorkspace(composition: localComposition);

            MockEditAndContinueWorkspaceService mockEncService;
            var clientProvider = (InProcRemoteHostClientProvider?)localWorkspace.Services.GetService <IRemoteHostClientProvider>();

            if (testHost == TestHost.InProcess)
            {
                Assert.Null(clientProvider);

                mockEncService = (MockEditAndContinueWorkspaceService)localWorkspace.Services.GetRequiredService <IEditAndContinueWorkspaceService>();
            }
            else
            {
                Assert.NotNull(clientProvider);
                clientProvider !.AdditionalRemoteParts = new[] { typeof(MockEncServiceFactory) };

                var client = await InProcRemoteHostClient.GetTestClientAsync(localWorkspace).ConfigureAwait(false);

                var remoteWorkspace = client.TestData.WorkspaceManager.GetWorkspace();
                mockEncService = (MockEditAndContinueWorkspaceService)remoteWorkspace.Services.GetRequiredService <IEditAndContinueWorkspaceService>();
            }

            localWorkspace.ChangeSolution(localWorkspace.CurrentSolution.
                                          AddProject("proj", "proj", LanguageNames.CSharp).
                                          AddMetadataReferences(TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib40)).
                                          AddDocument("test.cs", SourceText.From("class C { }", Encoding.UTF8), filePath: "test.cs").Project.Solution);

            var solution = localWorkspace.CurrentSolution;
            var project  = solution.Projects.Single();
            var document = project.Documents.Single();

            var mockDiagnosticService = new Mock <IDiagnosticAnalyzerService>(MockBehavior.Strict);

            mockDiagnosticService.Setup(s => s.Reanalyze(It.IsAny <Workspace>(), It.IsAny <IEnumerable <ProjectId> >(), It.IsAny <IEnumerable <DocumentId> >(), It.IsAny <bool>()));

            void VerifyReanalyzeInvocation(ImmutableArray <DocumentId> documentIds)
            => mockDiagnosticService.Invocations.VerifyAndClear((nameof(IDiagnosticAnalyzerService.Reanalyze), new object?[] { localWorkspace, null, documentIds, false }));

            var diagnosticUpdateSource      = new EditAndContinueDiagnosticUpdateSource();
            var emitDiagnosticsUpdated      = new List <DiagnosticsUpdatedArgs>();
            var emitDiagnosticsClearedCount = 0;

            diagnosticUpdateSource.DiagnosticsUpdated += (object sender, DiagnosticsUpdatedArgs args) => emitDiagnosticsUpdated.Add(args);
            diagnosticUpdateSource.DiagnosticsCleared += (object sender, EventArgs args) => emitDiagnosticsClearedCount++;

            var span1          = new LinePositionSpan(new LinePosition(1, 2), new LinePosition(1, 5));
            var moduleId1      = new Guid("{44444444-1111-1111-1111-111111111111}");
            var methodId1      = new ManagedMethodId(moduleId1, token: 0x06000003, version: 2);
            var instructionId1 = new ManagedInstructionId(methodId1, ilOffset: 10);

            var as1 = new ManagedActiveStatementDebugInfo(
                instructionId1,
                documentName: "test.cs",
                span1.ToSourceSpan(),
                flags: ActiveStatementFlags.IsLeafFrame | ActiveStatementFlags.PartiallyExecuted);

            var methodId2 = new ManagedModuleMethodId(token: 0x06000002, version: 1);

            var exceptionRegionUpdate1 = new ManagedExceptionRegionUpdate(
                methodId2,
                delta: 1,
                newSpan: new SourceSpan(1, 2, 1, 5));

            var document1 = localWorkspace.CurrentSolution.Projects.Single().Documents.Single();

            var activeSpans1 = ImmutableArray.Create(TextSpan.FromBounds(1, 2), TextSpan.FromBounds(3, 4));

            var solutionActiveStatementSpanProvider = new SolutionActiveStatementSpanProvider((documentId, cancellationToken) =>
            {
                Assert.Equal(document1.Id, documentId);
                return(new(activeSpans1));
            });

            var documentActiveStatementSpanProvider = new DocumentActiveStatementSpanProvider(cancellationToken => new(activeSpans1));

            var proxy = new RemoteEditAndContinueServiceProxy(localWorkspace);

            // StartDebuggingSession

            var called = false;

            mockEncService.StartDebuggingSessionImpl = solution =>
            {
                Assert.Equal("proj", solution.Projects.Single().Name);
                called = true;
            };

            await proxy.StartDebuggingSessionAsync(localWorkspace.CurrentSolution, CancellationToken.None).ConfigureAwait(false);

            Assert.True(called);

            // StartEditSession

            IManagedEditAndContinueDebuggerService?remoteDebuggeeModuleMetadataProvider = null;

            mockEncService.StartEditSessionImpl = (IManagedEditAndContinueDebuggerService debuggerService, out ImmutableArray <DocumentId> documentsToReanalyze) =>
            {
                remoteDebuggeeModuleMetadataProvider = debuggerService;
                documentsToReanalyze = ImmutableArray <DocumentId> .Empty;
            };

            await proxy.StartEditSessionAsync(
                mockDiagnosticService.Object,
                debuggerService : new MockManagedEditAndContinueDebuggerService()
            {
                IsEditAndContinueAvailable = _ => new ManagedEditAndContinueAvailability(ManagedEditAndContinueAvailabilityStatus.NotAllowedForModule, "can't do enc"),
                GetActiveStatementsImpl    = () => ImmutableArray.Create(as1)
            },
                CancellationToken.None).ConfigureAwait(false);

            VerifyReanalyzeInvocation(ImmutableArray <DocumentId> .Empty);

            var activeStatement = (await remoteDebuggeeModuleMetadataProvider !.GetActiveStatementsAsync(CancellationToken.None).ConfigureAwait(false)).Single();

            Assert.Equal(as1.ActiveInstruction, activeStatement.ActiveInstruction);
            Assert.Equal(as1.SourceSpan, activeStatement.SourceSpan);
            Assert.Equal(as1.Flags, activeStatement.Flags);

            var availability = await remoteDebuggeeModuleMetadataProvider !.GetAvailabilityAsync(moduleId1, CancellationToken.None).ConfigureAwait(false);

            Assert.Equal(new ManagedEditAndContinueAvailability(ManagedEditAndContinueAvailabilityStatus.NotAllowedForModule, "can't do enc"), availability);

            // EndEditSession

            mockEncService.EndEditSessionImpl = (out ImmutableArray <DocumentId> documentsToReanalyze) =>
            {
                documentsToReanalyze = ImmutableArray.Create(document.Id);
            };

            await proxy.EndEditSessionAsync(mockDiagnosticService.Object, CancellationToken.None).ConfigureAwait(false);

            VerifyReanalyzeInvocation(ImmutableArray.Create(document.Id));

            // EndDebuggingSession

            mockEncService.EndDebuggingSessionImpl = (out ImmutableArray <DocumentId> documentsToReanalyze) =>
            {
                documentsToReanalyze = ImmutableArray.Create(document.Id);
            };

            await proxy.EndDebuggingSessionAsync(diagnosticUpdateSource, mockDiagnosticService.Object, CancellationToken.None).ConfigureAwait(false);

            VerifyReanalyzeInvocation(ImmutableArray.Create(document.Id));
            Assert.Equal(1, emitDiagnosticsClearedCount);
            emitDiagnosticsClearedCount = 0;
            Assert.Empty(emitDiagnosticsUpdated);

            // HasChanges

            mockEncService.HasChangesImpl = (solution, activeStatementSpanProvider, sourceFilePath) =>
            {
                Assert.Equal("proj", solution.Projects.Single().Name);
                Assert.Equal("test.cs", sourceFilePath);
                AssertEx.Equal(activeSpans1, activeStatementSpanProvider(document1.Id, CancellationToken.None).Result);
                return(true);
            };

            Assert.True(await proxy.HasChangesAsync(localWorkspace.CurrentSolution, solutionActiveStatementSpanProvider, "test.cs", CancellationToken.None).ConfigureAwait(false));

            // EmitSolutionUpdate

            var diagnosticDescriptor1 = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile);

            mockEncService.EmitSolutionUpdateImpl = (solution, activeStatementSpanProvider) =>
            {
                var project = solution.Projects.Single();
                Assert.Equal("proj", project.Name);
                AssertEx.Equal(activeSpans1, activeStatementSpanProvider(document1.Id, CancellationToken.None).Result);

                var deltas = ImmutableArray.Create(new ManagedModuleUpdate(
                                                       module: moduleId1,
                                                       ilDelta: ImmutableArray.Create <byte>(1, 2),
                                                       metadataDelta: ImmutableArray.Create <byte>(3, 4),
                                                       pdbDelta: ImmutableArray.Create <byte>(5, 6),
                                                       updatedMethods: ImmutableArray.Create(0x06000001),
                                                       sequencePoints: ImmutableArray.Create(new SequencePointUpdates("file.cs", ImmutableArray.Create(new SourceLineUpdate(1, 2)))),
                                                       activeStatements: ImmutableArray.Create(new ManagedActiveStatementUpdate(instructionId1.Method.Method, instructionId1.ILOffset, span1.ToSourceSpan())),
                                                       exceptionRegions: ImmutableArray.Create(exceptionRegionUpdate1)));

                var syntaxTree = project.Documents.Single().GetSyntaxTreeSynchronously(CancellationToken.None) !;

                var documentDiagnostic = DiagnosticData.Create(Diagnostic.Create(diagnosticDescriptor1, Location.Create(syntaxTree, TextSpan.FromBounds(1, 2)), new[] { "doc", "some error" }), document);
                var projectDiagnostic  = DiagnosticData.Create(Diagnostic.Create(diagnosticDescriptor1, Location.None, new[] { "proj", "some error" }), project);
                var solutionDiagnostic = DiagnosticData.Create(Diagnostic.Create(diagnosticDescriptor1, Location.None, new[] { "sol", "some error" }), solution.Options);

                return(new(ManagedModuleUpdateStatus.Ready, deltas), ImmutableArray.Create(documentDiagnostic, projectDiagnostic, solutionDiagnostic));
            };

            var updates = await proxy.EmitSolutionUpdateAsync(localWorkspace.CurrentSolution, solutionActiveStatementSpanProvider, diagnosticUpdateSource, CancellationToken.None).ConfigureAwait(false);

            Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status);

            Assert.Equal(1, emitDiagnosticsClearedCount);
            emitDiagnosticsClearedCount = 0;

            AssertEx.Equal(new[]
            {
                $"[{project.Id}] Error ENC1001: test.cs(0, 1, 0, 2): {string.Format(FeaturesResources.ErrorReadingFile, "doc", "some error")}",
                $"[{project.Id}] Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, "proj", "some error")}",
                $"[] Error ENC1001: {string.Format(FeaturesResources.ErrorReadingFile, "sol", "some error")}",
            },
                           emitDiagnosticsUpdated.Select(update =>
            {
                var d = update.GetPushDiagnostics(localWorkspace, InternalDiagnosticsOptions.NormalDiagnosticMode).Single();
                return($"[{d.ProjectId}] {d.Severity} {d.Id}:" +
                       (d.DataLocation != null ? $" {d.DataLocation.OriginalFilePath}({d.DataLocation.OriginalStartLine}, {d.DataLocation.OriginalStartColumn}, {d.DataLocation.OriginalEndLine}, {d.DataLocation.OriginalEndColumn}):" : "") +
                       $" {d.Message}");
            }));

            var delta = updates.Updates.Single();

            Assert.Equal(moduleId1, delta.Module);
            AssertEx.Equal(new byte[] { 1, 2 }, delta.ILDelta);
            AssertEx.Equal(new byte[] { 3, 4 }, delta.MetadataDelta);
            AssertEx.Equal(new byte[] { 5, 6 }, delta.PdbDelta);
            AssertEx.Equal(new[] { 0x06000001 }, delta.UpdatedMethods);

            var lineEdit = delta.SequencePoints.Single();

            Assert.Equal("file.cs", lineEdit.FileName);
            AssertEx.Equal(new[] { new SourceLineUpdate(1, 2) }, lineEdit.LineUpdates);
            Assert.Equal(exceptionRegionUpdate1, delta.ExceptionRegions.Single());

            var activeStatements = delta.ActiveStatements.Single();

            Assert.Equal(instructionId1.Method.Method, activeStatements.Method);
            Assert.Equal(instructionId1.ILOffset, activeStatements.ILOffset);
            Assert.Equal(span1, activeStatements.NewSpan.ToLinePositionSpan());

            // CommitSolutionUpdate

            called = false;
            mockEncService.CommitSolutionUpdateImpl = () => called = true;
            await proxy.CommitSolutionUpdateAsync(CancellationToken.None).ConfigureAwait(false);

            Assert.True(called);

            // DiscardSolutionUpdate

            called = false;
            mockEncService.DiscardSolutionUpdateImpl = () => called = true;
            await proxy.DiscardSolutionUpdateAsync(CancellationToken.None).ConfigureAwait(false);

            Assert.True(called);

            // GetCurrentActiveStatementPosition

            mockEncService.GetCurrentActiveStatementPositionImpl = (solution, activeStatementSpanProvider, instructionId) =>
            {
                Assert.Equal("proj", solution.Projects.Single().Name);
                Assert.Equal(instructionId1, instructionId);
                AssertEx.Equal(activeSpans1, activeStatementSpanProvider(document1.Id, CancellationToken.None).Result);
                return(new LinePositionSpan(new LinePosition(1, 2), new LinePosition(1, 5)));
            };

            Assert.Equal(span1, await proxy.GetCurrentActiveStatementPositionAsync(
                             localWorkspace.CurrentSolution,
                             solutionActiveStatementSpanProvider,
                             instructionId1,
                             CancellationToken.None).ConfigureAwait(false));

            // IsActiveStatementInExceptionRegion

            mockEncService.IsActiveStatementInExceptionRegionImpl = (solution, instructionId) =>
            {
                Assert.Equal(instructionId1, instructionId);
                return(true);
            };

            Assert.True(await proxy.IsActiveStatementInExceptionRegionAsync(localWorkspace.CurrentSolution, instructionId1, CancellationToken.None).ConfigureAwait(false));

            // GetBaseActiveStatementSpans

            mockEncService.GetBaseActiveStatementSpansImpl = (solution, documentIds) =>
            {
                AssertEx.Equal(new[] { document1.Id }, documentIds);
                return(ImmutableArray.Create(ImmutableArray.Create((span1, ActiveStatementFlags.IsNonLeafFrame | ActiveStatementFlags.PartiallyExecuted))));
            };

            var baseActiveSpans = await proxy.GetBaseActiveStatementSpansAsync(localWorkspace.CurrentSolution, ImmutableArray.Create(document1.Id), CancellationToken.None).ConfigureAwait(false);

            Assert.Equal((span1, ActiveStatementFlags.IsNonLeafFrame | ActiveStatementFlags.PartiallyExecuted), baseActiveSpans.Single().Single());

            // GetDocumentActiveStatementSpans

            mockEncService.GetAdjustedActiveStatementSpansImpl = (document, activeStatementSpanProvider) =>
            {
                Assert.Equal("test.cs", document.Name);
                AssertEx.Equal(activeSpans1, activeStatementSpanProvider(CancellationToken.None).Result);
                return(ImmutableArray.Create((span1, ActiveStatementFlags.IsNonLeafFrame | ActiveStatementFlags.PartiallyExecuted)));
            };

            var documentActiveSpans = await proxy.GetAdjustedActiveStatementSpansAsync(document1, documentActiveStatementSpanProvider, CancellationToken.None).ConfigureAwait(false);

            Assert.Equal((span1, ActiveStatementFlags.IsNonLeafFrame | ActiveStatementFlags.PartiallyExecuted), documentActiveSpans.Single());

            // GetDocumentActiveStatementSpans (default array)

            mockEncService.GetAdjustedActiveStatementSpansImpl = (document, _) => default;

            documentActiveSpans = await proxy.GetAdjustedActiveStatementSpansAsync(document1, documentActiveStatementSpanProvider, CancellationToken.None).ConfigureAwait(false);

            Assert.True(documentActiveSpans.IsDefault);

            // OnSourceFileUpdatedAsync

            called = false;
            mockEncService.OnSourceFileUpdatedImpl = updatedDocument =>
            {
                Assert.Equal(document.Id, updatedDocument.Id);
                called = true;
            };

            await proxy.OnSourceFileUpdatedAsync(document, CancellationToken.None).ConfigureAwait(false);

            Assert.True(called);
        }
        public async ValueTask <ImmutableArray <Diagnostic> > GetDocumentDiagnosticsAsync(Document document, Document designTimeDocument, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken)
        {
            var client = await RemoteHostClient.TryGetClientAsync(Workspace, cancellationToken).ConfigureAwait(false);

            if (client == null)
            {
                var diagnostics = await GetLocalService().GetDocumentDiagnosticsAsync(document, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false);

                if (designTimeDocument != document)
                {
                    diagnostics = diagnostics.SelectAsArray(diagnostic => RemapLocation(designTimeDocument, DiagnosticData.Create(diagnostic, document.Project)));
                }

                return(diagnostics);
            }

            var diagnosticData = await client.TryInvokeAsync <IRemoteEditAndContinueService, ImmutableArray <DiagnosticData> >(
                document.Project.Solution,
                (service, solutionInfo, callbackId, cancellationToken) => service.GetDocumentDiagnosticsAsync(solutionInfo, callbackId, document.Id, cancellationToken),
                callbackTarget : new ActiveStatementSpanProviderCallback(activeStatementSpanProvider),
                cancellationToken).ConfigureAwait(false);

            if (!diagnosticData.HasValue)
            {
                return(ImmutableArray <Diagnostic> .Empty);
            }

            var project = document.Project;

            using var _ = ArrayBuilder <Diagnostic> .GetInstance(out var result);

            foreach (var data in diagnosticData.Value)
            {
                Debug.Assert(data.DataLocation != null);

                Diagnostic diagnostic;

                // Workaround for solution crawler not supporting mapped locations to make Razor work.
                // We pretend the diagnostic is in the original document, but use the mapped line span.
                // Razor will ignore the column (which will be off because #line directives can't currently map columns) and only use the line number.
                if (designTimeDocument != document && data.DataLocation.IsMapped)
                {
                    diagnostic = RemapLocation(designTimeDocument, data);
                }
                else
                {
                    diagnostic = await data.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);
                }

                result.Add(diagnostic);
            }

            return(result.ToImmutable());
        }
Example #12
0
        public async Task DiagnosticData_ExternalAdditionalLocationIsPreserved()
        {
            using var workspace = new TestWorkspace(
                      composition: EditorTestCompositions.EditorFeatures
                      );

            var additionalDocument = workspace.CurrentSolution
                                     .AddProject("TestProject", "TestProject", LanguageNames.CSharp)
                                     .AddDocument("test.cs", "")
                                     .Project.AddAdditionalDocument(
                "AdditionalDocument.txt",
                "First line in file",
                filePath: "AdditionalDocument.txt"
                );
            var document = additionalDocument.Project.Documents.Single();

            var externalAdditionalLocation = new DiagnosticDataLocation(
                additionalDocument.Id,
                sourceSpan: new TextSpan(0, 1),
                originalFilePath: additionalDocument.Name,
                originalStartLine: 0,
                originalStartColumn: 0,
                originalEndLine: 0,
                originalEndColumn: 1
                );

            var diagnosticData = new DiagnosticData(
                id: "test1",
                category: "Test",
                message: "test1 message",
                enuMessageForBingSearch: "test1 message format",
                severity: DiagnosticSeverity.Info,
                defaultSeverity: DiagnosticSeverity.Info,
                isEnabledByDefault: true,
                warningLevel: 1,
                projectId: document.Project.Id,
                customTags: ImmutableArray <string> .Empty,
                properties: ImmutableDictionary <string, string> .Empty,
                location: new DiagnosticDataLocation(document.Id),
                additionalLocations: ImmutableArray.Create(externalAdditionalLocation),
                language: document.Project.Language
                );

            var diagnostic = await diagnosticData.ToDiagnosticAsync(
                document.Project,
                CancellationToken.None
                );

            var roundTripDiagnosticData = DiagnosticData.Create(diagnostic, document);

            var roundTripAdditionalLocation = Assert.Single(
                roundTripDiagnosticData.AdditionalLocations
                );

            Assert.Equal(
                externalAdditionalLocation.DocumentId,
                roundTripAdditionalLocation.DocumentId
                );
            Assert.Equal(
                externalAdditionalLocation.SourceSpan,
                roundTripAdditionalLocation.SourceSpan
                );
            Assert.Equal(
                externalAdditionalLocation.OriginalFilePath,
                roundTripAdditionalLocation.OriginalFilePath
                );
            Assert.Equal(
                externalAdditionalLocation.OriginalStartLine,
                roundTripAdditionalLocation.OriginalStartLine
                );
            Assert.Equal(
                externalAdditionalLocation.OriginalStartColumn,
                roundTripAdditionalLocation.OriginalStartColumn
                );
            Assert.Equal(
                externalAdditionalLocation.OriginalEndLine,
                roundTripAdditionalLocation.OriginalEndLine
                );
            Assert.Equal(
                externalAdditionalLocation.OriginalEndLine,
                roundTripAdditionalLocation.OriginalEndLine
                );
        }
        /// <summary>
        /// Reports diagnostics.
        /// </summary>
        /// <returns>Returns ids of documents that belong to <paramref name="projectId"/> and containing one or more diagnostics.</returns>
        public ImmutableArray <DocumentId> ReportDiagnostics(object errorId, Solution solution, ProjectId projectId, IEnumerable <Diagnostic> diagnostics)
        {
            Debug.Assert(errorId != null);
            Debug.Assert(solution != null);
            Debug.Assert(projectId != null);

            var updateEvent = DiagnosticsUpdated;
            var documentIds = PooledHashSet <DocumentId> .GetInstance();

            var documentDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var projectDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var project = solution.GetProject(projectId);

            foreach (var diagnostic in diagnostics)
            {
                var documentOpt = solution.GetDocument(diagnostic.Location.SourceTree);

                if (documentOpt != null)
                {
                    if (updateEvent != null)
                    {
                        documentDiagnosticData.Add(DiagnosticData.Create(documentOpt, diagnostic));
                    }

                    // only add documents from the current project:
                    if (documentOpt.Project.Id == projectId)
                    {
                        documentIds.Add(documentOpt.Id);
                    }
                }
                else if (updateEvent != null)
                {
                    projectDiagnosticData.Add(DiagnosticData.Create(project, diagnostic));
                }
            }

            foreach (var documentDiagnostics in documentDiagnosticData.ToDictionary(data => data.DocumentId))
            {
                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                errorId,
                                solution.Workspace,
                                solution,
                                projectId,
                                documentId: documentDiagnostics.Key,
                                diagnostics: documentDiagnostics.Value));
            }

            if (projectDiagnosticData.Count > 0)
            {
                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                errorId,
                                solution.Workspace,
                                solution,
                                projectId,
                                documentId: null,
                                diagnostics: projectDiagnosticData.ToImmutable()));
            }

            var result = documentIds.AsImmutableOrEmpty();

            documentDiagnosticData.Free();
            projectDiagnosticData.Free();
            documentIds.Free();
            return(result);
        }
Example #14
0
        public void ReportDiagnostics(Solution solution, ProjectId?projectId, IEnumerable <Diagnostic> diagnostics)
        {
            RoslynDebug.Assert(solution != null);

            var updateEvent = DiagnosticsUpdated;

            if (updateEvent == null)
            {
                return;
            }

            var documentDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var nonDocumentDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var workspace = solution.Workspace;
            var options   = solution.Options;
            var project   = (projectId != null) ? solution.GetProject(projectId) : null;

            foreach (var diagnostic in diagnostics)
            {
                var document = solution.GetDocument(diagnostic.Location.SourceTree);

                if (document != null)
                {
                    documentDiagnosticData.Add(DiagnosticData.Create(diagnostic, document));
                }
                else if (project != null)
                {
                    nonDocumentDiagnosticData.Add(DiagnosticData.Create(diagnostic, project));
                }
                else
                {
                    nonDocumentDiagnosticData.Add(DiagnosticData.Create(diagnostic, options));
                }
            }

            if (documentDiagnosticData.Count > 0)
            {
                foreach (var(documentId, diagnosticData) in documentDiagnosticData.ToDictionary(data => data.DocumentId))
                {
                    var diagnosticGroupId = (this, documentId, projectId);

                    updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                    diagnosticGroupId,
                                    workspace,
                                    solution,
                                    projectId,
                                    documentId: documentId,
                                    diagnostics: diagnosticData));
                }
            }

            if (nonDocumentDiagnosticData.Count > 0)
            {
                var diagnosticGroupId = (this, projectId);

                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                diagnosticGroupId,
                                workspace,
                                solution,
                                projectId,
                                documentId: null,
                                diagnostics: nonDocumentDiagnosticData.ToImmutable()));
            }

            documentDiagnosticData.Free();
            nonDocumentDiagnosticData.Free();
        }
            public async Task AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
            {
                // right now, there is no way to observe diagnostics for closed file.
                if (!_workspace.IsDocumentOpen(document.Id) ||
                    !_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Syntax))
                {
                    return;
                }

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                var diagnostics = tree.GetDiagnostics(cancellationToken);

                Contract.Requires(document.Project.Solution.Workspace == _workspace);

                var diagnosticData = diagnostics == null ? ImmutableArray <DiagnosticData> .Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty();

                _service.RaiseDiagnosticsUpdated(
                    DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, Syntax, document.Id),
                                                              _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData));
            }
            public async Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, CancellationToken cancellationToken)
            {
                // right now, there is no way to observe diagnostics for closed file.
                if (!_workspace.IsDocumentOpen(document.Id) ||
                    !_workspace.Options.GetOption(InternalRuntimeDiagnosticOptions.Semantic))
                {
                    return;
                }

                var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var diagnostics = model.GetMethodBodyDiagnostics(span: null, cancellationToken: cancellationToken).Concat(
                    model.GetDeclarationDiagnostics(span: null, cancellationToken: cancellationToken));

                Contract.Requires(document.Project.Solution.Workspace == _workspace);

                var diagnosticData = diagnostics == null ? ImmutableArray <DiagnosticData> .Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty();

                _service.RaiseDiagnosticsUpdated(
                    DiagnosticsUpdatedArgs.DiagnosticsCreated(new DefaultUpdateArgsId(_workspace.Kind, Semantic, document.Id),
                                                              _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData));
            }