Skip to content

Commit

Permalink
Fix NullReferenceException during debugging
Browse files Browse the repository at this point in the history
When opening a file during a debugging session, VS sets its buffer read-only when it is not editable. To do so, VS asks its document to the workspace but in some cases, the workspace returns nothing, causing NRE and VS Crash. Issue dotnet#1202 is tracking to fix this issue directly (by enforcing the workspace to load projects before EnC). In this PR, we defensively add a null check and log it to make a further investigation easier.
  • Loading branch information
wschae committed Apr 3, 2015
1 parent 0ab8e70 commit fc44da4
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
Expand All @@ -20,7 +21,9 @@ internal sealed class VsReadOnlyDocumentTracker : ForegroundThreadAffinitizedObj
private readonly Workspace _workspace;
private readonly AbstractProject _vsProject;

private bool _isDisposed;
private bool _isDisposed;

internal static readonly TraceLog log = new TraceLog(2048, "VsReadOnlyDocumentTracker");

public VsReadOnlyDocumentTracker(IEditAndContinueWorkspaceService encService, IVsEditorAdaptersFactoryService adapters, AbstractProject vsProject)
: base(assertIsForeground: true)
Expand Down Expand Up @@ -142,6 +145,12 @@ private void SetReadOnlyFlag(ITextBuffer buffer, bool value)
private static ITextBuffer GetTextBuffer(Workspace workspace, DocumentId documentId)
{
var doc = workspace.CurrentSolution.GetDocument(documentId);
if (doc == null)
{
log.Write($"GetTextBuffer: document not found for '{documentId?.GetDebuggerDisplay()}'");

This comment has been minimized.

Copy link
@tmat

tmat Apr 3, 2015

If this is a temporary change please add // TODO with an issue number.

return null;
}

SourceText text;
if (!doc.TryGetText(out text))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

Imports System.Collections.Immutable
Imports System.IO
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.EditAndContinue
Expand Down Expand Up @@ -115,6 +116,61 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.EditAndContinue
Assert.Equal(Of UInteger)(0, mockVsBuffer._oldFlags) ' Editable
End Sub

<WorkItem(1147868, "DevDiv")>
<Fact>
Public Sub InvalidDocumentTest1()
Dim diagnosticService As IDiagnosticAnalyzerService = New EditAndContinueTestHelper.TestDiagnosticAnalyzerService()
Dim encService As IEditAndContinueWorkspaceService = New EditAndContinueWorkspaceService(diagnosticService)
Dim workspace = EditAndContinueTestHelper.CreateTestWorkspace()
Dim currentSolution = workspace.CurrentSolution
Dim project = currentSolution.Projects(0)

Dim mockVsBuffer = New VsTextBufferMock()
Assert.Equal(Of UInteger)(0, mockVsBuffer._oldFlags)

Dim mockEditorAdaptersFactoryService = New VsEditorAdaptersFactoryServiceMock(mockVsBuffer)
Dim readOnlyDocumentTracker As VsReadOnlyDocumentTracker

' start debugging & readOnlyDocumentTracker
encService.StartDebuggingSession(workspace.CurrentSolution)
readOnlyDocumentTracker = New VsReadOnlyDocumentTracker(encService, mockEditorAdaptersFactoryService, Nothing)

' valid document
readOnlyDocumentTracker.SetReadOnly(project.DocumentIds.First(), False)
Assert.Equal(Of UInteger)(0, mockVsBuffer._oldFlags) ' Editable

' invlid documentId
readOnlyDocumentTracker.SetReadOnly(Nothing, False) ' Check no NRE
End Sub

<WorkItem(1147868, "DevDiv")>
<Fact>
Public Sub InvalidDocumentTest2()
Dim diagnosticService As IDiagnosticAnalyzerService = New EditAndContinueTestHelper.TestDiagnosticAnalyzerService()
Dim encService As IEditAndContinueWorkspaceService = New EditAndContinueWorkspaceService(diagnosticService)
Dim workspace = EditAndContinueTestHelper.CreateTestWorkspace()
Dim currentSolution = workspace.CurrentSolution
Dim project = currentSolution.Projects(0)

Dim mockVsBuffer = New VsTextBufferMock()
Assert.Equal(Of UInteger)(0, mockVsBuffer._oldFlags)

Dim mockEditorAdaptersFactoryService = New VsEditorAdaptersFactoryServiceMock(mockVsBuffer)
Dim readOnlyDocumentTracker As VsReadOnlyDocumentTracker

' start debugging & readOnlyDocumentTracker
encService.StartDebuggingSession(workspace.CurrentSolution)
readOnlyDocumentTracker = New VsReadOnlyDocumentTracker(encService, mockEditorAdaptersFactoryService, Nothing)

' valid document
readOnlyDocumentTracker.SetReadOnly(project.DocumentIds.First(), False)
Assert.Equal(Of UInteger)(0, mockVsBuffer._oldFlags) ' Editable

' the given project does not contain this document
Dim newDocumentId = New DocumentId(New ProjectId(New Guid(), "TestProject"), New Guid(), "TestDoc")
readOnlyDocumentTracker.SetReadOnly(newDocumentId, False) ' Check no NRE
End Sub

#Region "Helper Methods"

Public Class VsTextBufferMock
Expand Down

1 comment on commit fc44da4

@tmat
Copy link

@tmat tmat commented on fc44da4 Apr 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.