未验证 提交 81ab2013 编写于 作者: D dotnet-automerge-bot 提交者: GitHub

Merge pull request #30392 from dotnet/merges/dev16.0.x-to-master

Merge dev16.0.x to master
......@@ -3079,5 +3079,15 @@ public async Task TestDirectiveStringLiteral()
{
await TestInMethodAsync(@"#line 1 ""a\b""");
}
[WorkItem(30378, "https://github.com/dotnet/roslyn/issues/30378")]
[Fact, Trait(Traits.Feature, Traits.Features.Classification)]
public async Task TestFormatSpecifierInInterpolation()
{
await TestInMethodAsync(@"var goo = $""goo{{1:0000}}bar"";",
Keyword("var"),
Escape(@"{{"),
Escape(@"}}"));
}
}
}
......@@ -29,10 +29,10 @@ public static async Task<RemoteHostClient> CreateAsync(Workspace workspace, bool
var remoteHostStream = await inprocServices.RequestServiceAsync(WellKnownRemoteHostServices.RemoteHostService, cancellationToken).ConfigureAwait(false);
var remotableDataRpc = new RemotableDataJsonRpc(workspace, inprocServices.Logger, await inprocServices.RequestServiceAsync(WellKnownServiceHubServices.SnapshotService, cancellationToken).ConfigureAwait(false));
var instance = new InProcRemoteHostClient(workspace, inprocServices, new ReferenceCountedDisposable<RemotableDataJsonRpc>(remotableDataRpc), remoteHostStream);
var current = CreateClientId(Process.GetCurrentProcess().Id.ToString());
var instance = new InProcRemoteHostClient(current, workspace, inprocServices, new ReferenceCountedDisposable<RemotableDataJsonRpc>(remotableDataRpc), remoteHostStream);
// make sure connection is done right
var current = $"VS ({Process.GetCurrentProcess().Id})";
var telemetrySession = default(string);
var uiCultureLCIDE = 0;
var cultureLCID = 0;
......@@ -49,6 +49,7 @@ public static async Task<RemoteHostClient> CreateAsync(Workspace workspace, bool
}
private InProcRemoteHostClient(
string clientId,
Workspace workspace,
InProcRemoteServices inprocServices,
ReferenceCountedDisposable<RemotableDataJsonRpc> remotableDataRpc,
......@@ -57,6 +58,8 @@ public static async Task<RemoteHostClient> CreateAsync(Workspace workspace, bool
{
Contract.ThrowIfNull(remotableDataRpc);
ClientId = clientId;
_inprocServices = inprocServices;
_remotableDataRpc = remotableDataRpc;
......@@ -76,6 +79,8 @@ public void RegisterService(string name, Func<Stream, IServiceProvider, ServiceH
_inprocServices.RegisterService(name, serviceCreator);
}
public override string ClientId { get; }
public override async Task<Connection> TryCreateConnectionAsync(
string serviceName, object callbackTarget, CancellationToken cancellationToken)
{
......
......@@ -721,5 +721,13 @@ End Operator"
Await TestAsync("#region ""goo""""bar""",
Escape(""""""))
End Function
<WorkItem(30378, "https://github.com/dotnet/roslyn/issues/30378")>
<Fact, Trait(Traits.Feature, Traits.Features.Classification)>
Public Async Function TestFormatSpecifierInInterpolation() As Task
Await TestInMethodAsync("dim goo = $""goo{{1:0000}}bar""",
Escape("{{"),
Escape("}}"))
End Function
End Class
End Namespace
......@@ -57,6 +57,8 @@ private partial class ConnectionManager
_shutdownLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
}
public HostGroup HostGroup => _hostGroup;
public Task<Connection> TryCreateConnectionAsync(string serviceName, object callbackTarget, CancellationToken cancellationToken)
{
// pool is not enabled by option
......
......@@ -7,7 +7,6 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Notification;
......@@ -30,8 +29,6 @@ private enum GlobalNotificationState
Finished
}
private static int s_instanceId = 0;
private readonly JsonRpc _rpc;
private readonly ConnectionManager _connectionManager;
......@@ -75,9 +72,7 @@ public static async Task<ServiceHubRemoteHostClient> CreateWorkerAsync(Workspace
try
{
// let each client to have unique id so that we can distinguish different clients when service is restarted
var currentInstanceId = Interlocked.Add(ref s_instanceId, 1);
var current = $"VS ({Process.GetCurrentProcess().Id}) ({currentInstanceId})";
var current = CreateClientId(Process.GetCurrentProcess().Id.ToString());
var hostGroup = new HostGroup(current);
var remoteHostStream = await Connections.RequestServiceAsync(workspace, primary, WellKnownRemoteHostServices.RemoteHostService, hostGroup, timeout, cancellationToken).ConfigureAwait(false);
......@@ -133,6 +128,8 @@ public static async Task<ServiceHubRemoteHostClient> CreateWorkerAsync(Workspace
_rpc.StartListening();
}
public override string ClientId => _connectionManager.HostGroup.Id;
public override Task<Connection> TryCreateConnectionAsync(string serviceName, object callbackTarget, CancellationToken cancellationToken)
{
return _connectionManager.TryCreateConnectionAsync(serviceName, callbackTarget, cancellationToken);
......@@ -158,6 +155,15 @@ protected override void OnStopped()
_connectionManager.Shutdown();
}
public HostGroup HostGroup
{
get
{
Debug.Assert(_connectionManager.HostGroup.Id == ClientId);
return _connectionManager.HostGroup;
}
}
private void RegisterGlobalOperationNotifications()
{
var globalOperationService = this.Workspace.Services.GetService<IGlobalOperationNotificationService>();
......@@ -295,4 +301,4 @@ private void OnRpcDisconnected(object sender, JsonRpcDisconnectedEventArgs e)
Stopped();
}
}
}
\ No newline at end of file
}
......@@ -52,6 +52,26 @@ public async Task Enable_Disable()
Assert.Null(disabledClient);
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task ClientId()
{
var service = CreateRemoteHostClientService();
service.Enable();
var client1 = await service.TryGetRemoteHostClientAsync(CancellationToken.None);
var id1 = client1.ClientId;
await service.RequestNewRemoteHostAsync(CancellationToken.None);
var client2 = await service.TryGetRemoteHostClientAsync(CancellationToken.None);
var id2 = client2.ClientId;
Assert.NotEqual(id1, id2);
service.Disable();
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task GlobalAssets()
{
......
......@@ -48,17 +48,21 @@ protected override ImmutableArray<VirtualChar> TryConvertToVirtualCharsWorker(Sy
? TryConvertVerbatimStringToVirtualChars(token, "@\"", "\"", escapeBraces: false)
: TryConvertStringToVirtualChars(token, "\"", "\"", escapeBraces: false);
}
else if (token.Kind() == SyntaxKind.InterpolatedStringTextToken)
{
var interpolatedString = (InterpolatedStringExpressionSyntax)token.Parent.Parent;
return interpolatedString.StringStartToken.Kind() == SyntaxKind.InterpolatedVerbatimStringStartToken
? TryConvertVerbatimStringToVirtualChars(token, "", "", escapeBraces: true)
: TryConvertStringToVirtualChars(token, "", "", escapeBraces: true);
}
else
if (token.Kind() == SyntaxKind.InterpolatedStringTextToken)
{
return default;
// The sections between `}` and `{` are InterpolatedStringTextToken *as are* the
// format specifiers in an interpolated string. We only want to get the virtual
// chars for this first type.
if (token.Parent.Parent is InterpolatedStringExpressionSyntax interpolatedString)
{
return interpolatedString.StringStartToken.Kind() == SyntaxKind.InterpolatedVerbatimStringStartToken
? TryConvertVerbatimStringToVirtualChars(token, "", "", escapeBraces: true)
: TryConvertStringToVirtualChars(token, "", "", escapeBraces: true);
}
}
return default;
}
private bool IsInDirective(SyntaxNode node)
......
......@@ -26,6 +26,14 @@ protected RemoteHostClient(Workspace workspace)
public event EventHandler<bool> StatusChanged;
/// <summary>
/// Return an unique string per client.
///
/// one can use this to distinguish different clients that are connected to different RemoteHosts including
/// cases where 2 external process finding each others
/// </summary>
public abstract string ClientId { get; }
/// <summary>
/// Create <see cref="RemoteHostClient.Connection"/> for the <paramref name="serviceName"/> if possible.
/// otherwise, return null.
......@@ -64,6 +72,11 @@ private void OnStatusChanged(bool started)
StatusChanged?.Invoke(this, started);
}
public static string CreateClientId(string prefix)
{
return $"VS ({prefix}) ({Guid.NewGuid().ToString()})";
}
/// <summary>
/// NoOpClient is used if a user killed our remote host process. Basically this client never
/// create a session
......@@ -75,6 +88,8 @@ public class NoOpClient : RemoteHostClient
{
}
public override string ClientId => nameof(NoOpClient);
public override Task<Connection> TryCreateConnectionAsync(string serviceName, object callbackTarget, CancellationToken cancellationToken)
{
return SpecializedTasks.Default<Connection>();
......@@ -140,7 +155,7 @@ public void Dispose()
// when that happen, we don't want to crash VS, so this is debug only check
if (!Environment.HasShutdownStarted)
{
Debug.Assert(false,
Debug.Assert(false,
$"Unless OOP process (RoslynCodeAnalysisService) is explicitly killed, this should have been disposed!\r\n {_creationCallStack}");
}
}
......
......@@ -4,6 +4,7 @@ Imports System.Collections.Immutable
Imports System.Composition
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.VirtualChars
<ExportLanguageService(GetType(IVirtualCharService), LanguageNames.VisualBasic), [Shared]>
......@@ -21,7 +22,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.VirtualChars
If token.Kind() = SyntaxKind.StringLiteralToken Then
Return TryConvertSimpleDoubleQuoteString(token, """", """", escapeBraces:=False)
ElseIf token.Kind() = SyntaxKind.InterpolatedStringTextToken Then
End If
If token.Kind() = SyntaxKind.InterpolatedStringTextToken AndAlso
TypeOf token.Parent.Parent Is InterpolatedStringExpressionSyntax Then
Return TryConvertSimpleDoubleQuoteString(token, "", "", escapeBraces:=True)
End If
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册