Skip to content

Commit

Permalink
[Debug] Add new ExternalTypeResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
JaneySprings committed Oct 27, 2024
1 parent ecdeb31 commit e3f8e43
Show file tree
Hide file tree
Showing 16 changed files with 218 additions and 165 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@
"dotnetMeteor.debuggerOptions.useExternalTypeResolver": {
"type": "boolean",
"default": true,
"description": "%configuration.description.debuggerOptions.useExternalTypeResolver%"
"markdownDescription": "%configuration.description.debuggerOptions.useExternalTypeResolver%"
},
"dotnetMeteor.debuggerOptions.currentExceptionTag": {
"type": "string",
Expand Down
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"configuration.description.debuggerOptions.flattenHierarchy": "Controls whether the debugger should flatten the hierarchy of inherited members.",
"configuration.description.debuggerOptions.groupPrivateMembers": "Controls whether the debugger should group private members in the debugging window.",
"configuration.description.debuggerOptions.groupStaticMembers": "Controls whether the debugger should group static members in the debugging window.",
"configuration.description.debuggerOptions.useExternalTypeResolver": "Search for unknown types in the project's assemblies for the evaluation expressions.",
"configuration.description.debuggerOptions.useExternalTypeResolver": "Resolve types using the external type resolver. Requires the [DotRush](https://github.com/JaneySprings/DotRush) extension.",
"configuration.description.debuggerOptions.currentExceptionTag": "Specifies the display name of the current exception in the debugging window.",
"configuration.description.debuggerOptions.ellipsizeStrings": "Truncates strings in the debugging window.",
"configuration.description.debuggerOptions.ellipsizedLength": "The maximum length of a truncated string.",
Expand Down
6 changes: 6 additions & 0 deletions src/DotNet.Meteor.Debug/Agents/DebugLaunchAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace DotNet.Meteor.Debug;
public class DebugLaunchAgent : BaseLaunchAgent {
private readonly SoftDebuggerStartArgs startArguments;
private readonly SoftDebuggerStartInfo startInformation;
private readonly ExternalTypeResolver typeResolver;

public DebugLaunchAgent(LaunchConfiguration configuration) : base(configuration) {
if (configuration.Device.IsAndroid || (configuration.Device.IsIPhone && !configuration.Device.IsEmulator))
Expand All @@ -21,6 +22,7 @@ public DebugLaunchAgent(LaunchConfiguration configuration) : base(configuration)

ArgumentNullException.ThrowIfNull(startArguments, "Debugger connection arguments not implemented.");

typeResolver = new ExternalTypeResolver(configuration.TransportId);
startInformation = new SoftDebuggerStartInfo(startArguments);
startInformation.SetAssemblies(configuration.GetAssembliesPath(), configuration.DebuggerSessionOptions);
}
Expand All @@ -36,6 +38,10 @@ public override void Launch(IProcessLogger logger) {
}
public override void Connect(SoftDebuggerSession session) {
session.Run(startInformation, Configuration.DebuggerSessionOptions);
if (typeResolver.TryConnect()) {
Disposables.Add(() => typeResolver.Dispose());
session.TypeResolverHandler = typeResolver.Resolve;
}
}

private void LaunchAppleMobile(IProcessLogger logger) {
Expand Down
10 changes: 6 additions & 4 deletions src/DotNet.Meteor.Debug/DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public DebugSession(Stream input, Stream output) : base(input, output) {
session.DebugWriter = OnDebugLog;
session.OutputWriter = OnLog;
session.ExceptionHandler = OnExceptionHandled;
session.TypeResolverHandler = TypeResolverExtensions.ResolveIdentifier;

session.TargetStopped += TargetStopped;
session.TargetHitBreakpoint += TargetHitBreakpoint;
Expand Down Expand Up @@ -363,9 +362,12 @@ protected override EvaluateResponse HandleEvaluateRequest(EvaluateArguments argu
if (frame == null)
throw new ProtocolException("no active stackframe");

TypeResolverExtensions.SetContext(frame, session.Options.EvaluationOptions);
var value = frame.GetExpressionValue(expression, session.Options.EvaluationOptions);
value.WaitHandle.WaitOne(session.Options.EvaluationOptions.EvaluationTimeout);
var options = session.Options.EvaluationOptions.Clone();
if (arguments.Context == EvaluateArguments.ContextValue.Hover)
options.UseExternalTypeResolver = false;

var value = frame.GetExpressionValue(expression, options);
value.WaitHandle.WaitOne(options.EvaluationTimeout);

if (value.IsEvaluating)
throw new ProtocolException("evaluation timeout expected");
Expand Down
1 change: 1 addition & 0 deletions src/DotNet.Meteor.Debug/DotNet.Meteor.Debug.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
<PackageReference Include="StreamJsonRpc" Version="2.19.27" />
</ItemGroup>
</Project>
20 changes: 8 additions & 12 deletions src/DotNet.Meteor.Debug/Extensions/MonoExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reflection;
using System.Text;
using DotNet.Meteor.Common.Extensions;
using Mono.Debugging.Client;
using Mono.Debugging.Soft;

Expand Down Expand Up @@ -71,7 +72,7 @@ public static bool HasNullValue(this ObjectValue objectValue) {

foreach (var remap in session.Options.SourceCodeMappings) {
if (location.FileName.Contains(remap.Key))
return location.FileName.Replace(remap.Key, remap.Value);
return location.FileName.Replace(remap.Key, remap.Value).ToPlatformPath();
}

return location.FileName;
Expand All @@ -86,30 +87,25 @@ public static void SetAssemblies(this SoftDebuggerStartInfo startInfo, string as

foreach (var assemblyPath in assemblyPaths) {
try {
using var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyPath);
if (string.IsNullOrEmpty(assemblyDefinition.Name.FullName)) {
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
if (string.IsNullOrEmpty(assemblyName.FullName) || string.IsNullOrEmpty(assemblyName.Name)) {
DebuggerLoggingService.CustomLogger.LogMessage($"Assembly '{assemblyPath}' has no name");
continue;
}

string? assemblySymbolsFilePath = SymbolServerExtensions.SearchSymbols(options.SymbolSearchPaths, assemblyPath);
if (string.IsNullOrEmpty(assemblySymbolsFilePath) && options.SearchMicrosoftSymbolServer)
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, assemblyDefinition.Name.Name, SymbolServerExtensions.MicrosoftSymbolServerAddress);
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, assemblyName.Name, SymbolServerExtensions.MicrosoftSymbolServerAddress);
if (string.IsNullOrEmpty(assemblySymbolsFilePath) && options.SearchNuGetSymbolServer)
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, assemblyDefinition.Name.Name, SymbolServerExtensions.NuGetSymbolServerAddress);
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, assemblyName.Name, SymbolServerExtensions.NuGetSymbolServerAddress);
if (string.IsNullOrEmpty(assemblySymbolsFilePath))
DebuggerLoggingService.CustomLogger.LogMessage($"No symbols found for '{assemblyPath}'");


if (options.EvaluationOptions.UseExternalTypeResolver)
TypeResolverExtensions.RegisterTypes(assemblyDefinition.MainModule.Types);

if (!string.IsNullOrEmpty(assemblySymbolsFilePath))
assemblySymbolPathMap.Add(assemblyDefinition.Name.FullName, assemblySymbolsFilePath);
assemblySymbolPathMap.Add(assemblyName.FullName, assemblySymbolsFilePath);

if (options.ProjectAssembliesOnly && SymbolServerExtensions.HasDebugSymbols(assemblyPath, useSymbolServers)) {
var assemblyName = new AssemblyName(assemblyDefinition.Name.FullName);
assemblyPathMap.TryAdd(assemblyDefinition.Name.FullName, assemblyPath);
assemblyPathMap.TryAdd(assemblyName.FullName, assemblyPath);
assemblyNames.Add(assemblyName);
DebuggerLoggingService.CustomLogger.LogMessage($"User assembly '{assemblyName.Name}' added");
}
Expand Down
39 changes: 39 additions & 0 deletions src/DotNet.Meteor.Debug/ExternalTypeResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.IO.Pipes;
using Mono.Debugging.Client;
using StreamJsonRpc;

namespace DotNet.Meteor.Debug;

public class ExternalTypeResolver : IDisposable {
private readonly NamedPipeClientStream? transportStream;
private JsonRpc? rpcServer;

public ExternalTypeResolver(string? transportId) {
if (!string.IsNullOrEmpty(transportId))
transportStream = new NamedPipeClientStream(".", transportId, PipeDirection.InOut, PipeOptions.Asynchronous);
}

public bool TryConnect(int timeoutMs = 5000) {
if (transportStream == null)
return false;

try {
transportStream.Connect(timeoutMs);
rpcServer = JsonRpc.Attach(transportStream);
DebuggerLoggingService.CustomLogger.LogMessage("Debugger connected to external type resolver");
} catch (Exception e) {
DebuggerLoggingService.CustomLogger.LogMessage($"Failed to connect to external type resolver: {e}");
return false;
}

return true;
}
public string? Resolve(string identifierName, SourceLocation location) {
return rpcServer?.InvokeAsync<string>("HandleResolveType", identifierName, location)?.Result;
}

public void Dispose() {
rpcServer?.Dispose();
transportStream?.Dispose();
}
}
2 changes: 2 additions & 0 deletions src/DotNet.Meteor.Debug/LaunchConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class LaunchConfiguration {
public int DebugPort { get; init; }
public int ReloadHostPort { get; init; }
public int ProfilerPort { get; init; }
public string? TransportId { get; init; }
public DebuggerSessionOptions DebuggerSessionOptions { get; init; }

private ProfilerMode Profiler { get; init; }
Expand All @@ -30,6 +31,7 @@ public LaunchConfiguration(Dictionary<string, JToken> configurationProperties) {
ReloadHostPort = configurationProperties.TryGetValue("reloadHost").ToValue<int>();
ProfilerPort = configurationProperties.TryGetValue("profilerPort").ToValue<int>();
Profiler = configurationProperties.TryGetValue("profilerMode").ToValue<ProfilerMode>();
TransportId = configurationProperties.TryGetValue("transportId").ToClass<string>();
DebuggerSessionOptions = configurationProperties.TryGetValue("debuggerOptions")?.ToClass<DebuggerSessionOptions>()
?? ServerExtensions.DefaultDebuggerOptions;

Expand Down
8 changes: 4 additions & 4 deletions src/VSCode.Extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { InteropController } from './controllers/interopController';
import { StateController } from './controllers/stateController';
import { PublicExports } from './publicExports';
import { ModulesView } from './features/modulesView';
import { HotReload } from './features/hotReload';
import { XamlServer } from './features/xamlServer';
import { MauiEssentials } from './features/mauiEssentials';
import { ExternalTypeResolver } from './features/externalTypeResolver';
import * as res from './resources/constants';
import * as vscode from 'vscode';

Expand All @@ -25,8 +25,8 @@ export function activate(context: vscode.ExtensionContext): PublicExports | unde
StatusBarController.update();

ModulesView.feature.activate(context);
HotReload.feature.activate(context);
XamlServer.feature.activate(context);
MauiEssentials.feature.activate(context);
ExternalTypeResolver.feature.activate(context);

context.subscriptions.push(vscode.commands.registerCommand(res.commandIdSelectActiveProject, StatusBarController.showQuickPickProject));
context.subscriptions.push(vscode.commands.registerCommand(res.commandIdSelectActiveConfiguration, StatusBarController.showQuickPickConfiguration));
Expand Down
15 changes: 15 additions & 0 deletions src/VSCode.Extension/features/externalTypeResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as res from '../resources/constants';
import * as vscode from 'vscode';

export class ExternalTypeResolver {
public static feature : ExternalTypeResolver = new ExternalTypeResolver();
public transportId: string | undefined;

public async activate(context: vscode.ExtensionContext): Promise<void> {
const dotrushExtension = vscode.extensions.getExtension(res.dotrushExtensionId);
if (!dotrushExtension)
return;

this.transportId = `dotrush-${process.pid}`;
}
}
64 changes: 0 additions & 64 deletions src/VSCode.Extension/features/hotReload.ts

This file was deleted.

Loading

0 comments on commit e3f8e43

Please sign in to comment.