Skip to content

Commit 9dbbf9d

Browse files
Remove usage of WaitAndGetResult from debugger paths
1 parent 2dc3043 commit 9dbbf9d

File tree

1 file changed

+78
-90
lines changed

1 file changed

+78
-90
lines changed

src/VisualStudio/Core/Def/LanguageService/AbstractLanguageService`2.VsLanguageDebugInfo.cs

Lines changed: 78 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.CodeAnalysis.Internal.Log;
1414
using Microsoft.CodeAnalysis.Text;
1515
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
16+
using Microsoft.Internal.VisualStudio.Shell.Interop;
1617
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
1718
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
1819
using Microsoft.VisualStudio.Utilities;
@@ -70,63 +71,52 @@ public int GetLocationOfName(string pszName, out string? pbstrMkDoc, out VsTextS
7071

7172
public int GetNameOfLocation(IVsTextBuffer pBuffer, int iLine, int iCol, out string? pbstrName, out int piLineOffset)
7273
{
73-
using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetNameOfLocation, CancellationToken.None))
74-
{
75-
string? name = null;
76-
var lineOffset = 0;
74+
(pbstrName, piLineOffset) = GetNameOfLocationWorker();
7775

78-
if (_languageDebugInfo != null)
79-
{
80-
_uiThreadOperationExecutor.Execute(
81-
title: ServicesVSResources.Debugger,
82-
defaultDescription: ServicesVSResources.Determining_breakpoint_location,
83-
allowCancellation: true,
84-
showProgress: false,
85-
action: waitContext =>
86-
{
87-
var cancellationToken = waitContext.UserCancellationToken;
88-
var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer);
89-
if (textBuffer != null)
90-
{
91-
var nullablePoint = textBuffer.CurrentSnapshot.TryGetPoint(iLine, iCol);
92-
if (nullablePoint.HasValue)
93-
{
94-
var point = nullablePoint.Value;
95-
var document = point.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
96-
97-
if (document != null)
98-
{
99-
// NOTE(cyrusn): We have to wait here because the debuggers'
100-
// GetNameOfLocation is a blocking call. In the future, it
101-
// would be nice if they could make it async.
102-
this.ThreadingContext.JoinableTaskFactory.Run(async () =>
103-
{
104-
var debugLocationInfo = await _languageDebugInfo.GetLocationInfoAsync(document, point, cancellationToken).ConfigureAwait(false);
105-
106-
if (!debugLocationInfo.IsDefault)
107-
{
108-
name = debugLocationInfo.Name;
109-
lineOffset = debugLocationInfo.LineOffset;
110-
}
111-
});
112-
}
113-
}
114-
}
115-
});
76+
// Note(DustinCa): Docs say that GetNameOfLocation should return S_FALSE if a name could not be found.
77+
// Also, that's what the old native code does, so we should do it here.
78+
return pbstrName != null ? VSConstants.S_OK : VSConstants.S_FALSE;
11679

117-
if (name != null)
80+
(string name, int lineOffset) GetNameOfLocationWorker()
81+
{
82+
return this.ThreadingContext.JoinableTaskFactory.Run(async () =>
83+
{
84+
using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_GetNameOfLocation, CancellationToken.None))
11885
{
119-
pbstrName = name;
120-
piLineOffset = lineOffset;
121-
return VSConstants.S_OK;
122-
}
123-
}
86+
if (_languageDebugInfo == null)
87+
return default;
12488

125-
// Note(DustinCa): Docs say that GetNameOfLocation should return S_FALSE if a name could not be found.
126-
// Also, that's what the old native code does, so we should do it here.
127-
pbstrName = null;
128-
piLineOffset = 0;
129-
return VSConstants.S_FALSE;
89+
using var waitContext = _uiThreadOperationExecutor.BeginExecute(
90+
title: ServicesVSResources.Debugger,
91+
defaultDescription: ServicesVSResources.Determining_breakpoint_location,
92+
allowCancellation: true,
93+
showProgress: false);
94+
95+
var cancellationToken = waitContext.UserCancellationToken;
96+
var textBuffer = _languageService.EditorAdaptersFactoryService.GetDataBuffer(pBuffer);
97+
if (textBuffer == null)
98+
return default;
99+
100+
var nullablePoint = textBuffer.CurrentSnapshot.TryGetPoint(iLine, iCol);
101+
if (!nullablePoint.HasValue)
102+
return default;
103+
104+
var point = nullablePoint.Value;
105+
var document = point.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
106+
if (document == null)
107+
return default;
108+
109+
// NOTE(cyrusn): We have to wait here because the debuggers'
110+
// GetNameOfLocation is a blocking call. In the future, it
111+
// would be nice if they could make it async.
112+
var debugLocationInfo = await _languageDebugInfo.GetLocationInfoAsync(document, point, cancellationToken).ConfigureAwait(false);
113+
114+
if (debugLocationInfo.IsDefault)
115+
return default;
116+
117+
return (debugLocationInfo.Name, debugLocationInfo.LineOffset);
118+
}
119+
});
130120
}
131121
}
132122

@@ -178,51 +168,49 @@ public int IsMappedLocation(IVsTextBuffer pBuffer, int iLine, int iCol)
178168

179169
public int ResolveName(string pszName, uint dwFlags, out IVsEnumDebugName? ppNames)
180170
{
181-
using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ResolveName, CancellationToken.None))
171+
// In VS, this method frequently get's called with an empty string to test if the language service
172+
// supports this method (some language services, like F#, implement IVsLanguageDebugInfo but don't
173+
// implement this method). In that scenario, there's no sense doing work, so we'll just return
174+
// S_FALSE (as the old VB language service did).
175+
if (string.IsNullOrEmpty(pszName))
182176
{
183-
// In VS, this method frequently get's called with an empty string to test if the language service
184-
// supports this method (some language services, like F#, implement IVsLanguageDebugInfo but don't
185-
// implement this method). In that scenario, there's no sense doing work, so we'll just return
186-
// S_FALSE (as the old VB language service did).
187-
if (string.IsNullOrEmpty(pszName))
188-
{
189-
ppNames = null;
190-
return VSConstants.S_FALSE;
191-
}
177+
ppNames = null;
178+
return VSConstants.S_FALSE;
179+
}
192180

193-
VsEnumDebugName? enumName = null;
194-
_uiThreadOperationExecutor.Execute(
195-
title: ServicesVSResources.Debugger,
196-
defaultDescription: ServicesVSResources.Resolving_breakpoint_location,
197-
allowCancellation: true,
198-
showProgress: false,
199-
action: waitContext =>
181+
ppNames = this.ThreadingContext.JoinableTaskFactory.Run(async () =>
182+
{
183+
using (Logger.LogBlock(FunctionId.Debugging_VsLanguageDebugInfo_ResolveName, CancellationToken.None))
200184
{
201-
this.ThreadingContext.JoinableTaskFactory.Run(async () =>
185+
using var waitContext = _uiThreadOperationExecutor.BeginExecute(
186+
title: ServicesVSResources.Debugger,
187+
defaultDescription: ServicesVSResources.Resolving_breakpoint_location,
188+
allowCancellation: true,
189+
showProgress: false);
190+
191+
var cancellationToken = waitContext.UserCancellationToken;
192+
if (dwFlags == (uint)RESOLVENAMEFLAGS.RNF_BREAKPOINT)
202193
{
203-
var cancellationToken = waitContext.UserCancellationToken;
204-
if (dwFlags == (uint)RESOLVENAMEFLAGS.RNF_BREAKPOINT)
205-
{
206-
var solution = _languageService.Workspace.CurrentSolution;
194+
var solution = _languageService.Workspace.CurrentSolution;
207195

208-
// NOTE(cyrusn): We have to wait here because the debuggers' ResolveName
209-
// call is synchronous. In the future it would be nice to make it async.
210-
if (_breakpointService != null)
211-
{
212-
var breakpoints = await _breakpointService.ResolveBreakpointsAsync(
213-
solution, pszName, cancellationToken).ConfigureAwait(false);
214-
var debugNames = await breakpoints.SelectAsArrayAsync(
215-
bp => CreateDebugNameAsync(bp, cancellationToken)).ConfigureAwait(false);
196+
// NOTE(cyrusn): We have to wait here because the debuggers' ResolveName
197+
// call is synchronous. In the future it would be nice to make it async.
198+
if (_breakpointService != null)
199+
{
200+
var breakpoints = await _breakpointService.ResolveBreakpointsAsync(
201+
solution, pszName, cancellationToken).ConfigureAwait(false);
202+
var debugNames = await breakpoints.SelectAsArrayAsync(
203+
bp => CreateDebugNameAsync(bp, cancellationToken)).ConfigureAwait(false);
216204

217-
enumName = new VsEnumDebugName(debugNames);
218-
}
205+
return new VsEnumDebugName(debugNames);
219206
}
220-
});
221-
});
207+
}
208+
}
222209

223-
ppNames = enumName;
224-
return ppNames != null ? VSConstants.S_OK : VSConstants.E_NOTIMPL;
225-
}
210+
return null;
211+
});
212+
213+
return ppNames != null ? VSConstants.S_OK : VSConstants.E_NOTIMPL;
226214
}
227215

228216
private async ValueTask<IVsDebugName> CreateDebugNameAsync(

0 commit comments

Comments
 (0)