Skip to content

Commit c7716ce

Browse files
Use StringBuilder where possible with DocumentUri (#339)
* Use StringBuilder where possible with DocumentUri
1 parent 383d6c2 commit c7716ce

22 files changed

+270
-148
lines changed

src/Protocol/DocumentUri.Internal.cs

+56-42
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
4+
using System.Text;
45
using System.Text.RegularExpressions;
56

67
namespace OmniSharp.Extensions.LanguageServer.Protocol
@@ -98,11 +99,12 @@ private static string ReferenceResolution(string scheme, string path)
9899
{
99100
if (string.IsNullOrWhiteSpace(path))
100101
{
101-
path = StrSlash;
102+
return StrSlash;
102103
}
103-
else if (path[0] != Slash)
104+
105+
if (path[0] != Slash)
104106
{
105-
path = Slash + path;
107+
return Slash + path;
106108
}
107109
}
108110

@@ -135,7 +137,7 @@ private static string ReferenceResolution(string scheme, string path)
135137

136138
private static string EncodeUriComponentFast(string uriComponent, bool allowSlash)
137139
{
138-
string res = null;
140+
StringBuilder res = null;
139141
var nativeEncodePos = -1;
140142

141143
for (var pos = 0; pos < uriComponent.Length; pos++)
@@ -162,23 +164,25 @@ private static string EncodeUriComponentFast(string uriComponent, bool allowSlas
162164
// check if we are delaying native encode
163165
if (nativeEncodePos != -1)
164166
{
165-
res += Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos, pos - nativeEncodePos));
167+
res ??= new StringBuilder();
168+
res.Append(Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos, pos - nativeEncodePos)));
166169
nativeEncodePos = -1;
167170
}
168171

169172
// check if we write into a new string (by default we try to return the param)
170173
if (res != null)
171174
{
172-
res += uriComponent[pos];
175+
res ??= new StringBuilder();
176+
res.Append(uriComponent[pos]);
173177
}
174178
}
175179
else
176180
{
177181
// encoding needed, we need to allocate a new string
178182
if (res == null)
179-
180183
{
181-
res = uriComponent.Substring(0, pos);
184+
res ??= new StringBuilder();
185+
res.Append(uriComponent.Substring(0, pos));
182186
}
183187

184188
// check with default table first
@@ -187,12 +191,12 @@ private static string EncodeUriComponentFast(string uriComponent, bool allowSlas
187191
// check if we are delaying native encode
188192
if (nativeEncodePos != -1)
189193
{
190-
res += Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos, pos - nativeEncodePos));
194+
res.Append(Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos, pos - nativeEncodePos)));
191195
nativeEncodePos = -1;
192196
}
193197

194198
// append escaped variant to result
195-
res += escaped;
199+
res.Append(escaped);
196200
}
197201
else if (nativeEncodePos == -1)
198202
{
@@ -204,37 +208,35 @@ private static string EncodeUriComponentFast(string uriComponent, bool allowSlas
204208

205209
if (nativeEncodePos != -1)
206210
{
207-
res += Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos));
211+
res ??= new StringBuilder();
212+
res.Append(Uri.EscapeDataString(uriComponent.Substring(nativeEncodePos)));
208213
}
209214

210-
return !string.IsNullOrWhiteSpace(res) ? res : uriComponent;
215+
return res != null ? res.ToString() : uriComponent;
211216
}
212217

213218
private static string EncodeUriComponentMinimal(string path)
214219
{
215-
string res = null;
220+
StringBuilder res = null;
216221
for (var pos = 0; pos < path.Length; pos++)
217222
{
218223
var code = path[pos];
219224
if (code == CharCode.Hash || code == CharCode.QuestionMark)
220225
{
221226
if (res == null)
222227
{
223-
res = path.Substring(0, pos);
228+
res = new StringBuilder(path.Substring(0, pos));
224229
}
225230

226-
res += EncodeTable[code];
231+
res.Append(EncodeTable[code]);
227232
}
228233
else
229234
{
230-
if (res != null)
231-
{
232-
res += path[pos];
233-
}
235+
res?.Append(path[pos]);
234236
}
235237
}
236238

237-
return res ?? path;
239+
return res != null ? res.ToString() : path;
238240
}
239241

240242
/// <summary>
@@ -290,18 +292,18 @@ string Encoder(string p, bool allowSlash)
290292
return !skipEncoding ? EncodeUriComponentFast(p, allowSlash) : EncodeUriComponentMinimal(p);
291293
}
292294

293-
var res = "";
295+
var res = new StringBuilder();
294296
var (scheme, authority, path, query, fragment) = uri;
295297
if (!string.IsNullOrWhiteSpace(scheme))
296298
{
297-
res += scheme;
298-
res += ":";
299+
res.Append(scheme);
300+
res.Append(":");
299301
}
300302

301303
if (!string.IsNullOrWhiteSpace(authority) || scheme == "file")
302304
{
303-
res += Slash;
304-
res += Slash;
305+
res.Append(Slash);
306+
res.Append(Slash);
305307
}
306308

307309
if (!string.IsNullOrWhiteSpace(authority))
@@ -315,70 +317,82 @@ string Encoder(string p, bool allowSlash)
315317
idx = userinfo.IndexOf(":");
316318
if (idx == -1)
317319
{
318-
res += Encoder(userinfo, false);
320+
res.Append(Encoder(userinfo, false));
319321
}
320322
else
321323
{
322324
// <user>:<pass>@<auth>
323-
res += Encoder(userinfo.Substring(0, idx), false);
324-
res += ":";
325-
res += Encoder(userinfo.Substring(idx + 1), false);
325+
res.Append(Encoder(userinfo.Substring(0, idx), false));
326+
res.Append(":");
327+
res.Append(Encoder(userinfo.Substring(idx + 1), false));
326328
}
327329

328-
res += "@";
330+
res.Append("@");
329331
}
330332

331333
authority = authority.ToLowerInvariant();
332334
idx = authority.IndexOf(":", StringComparison.Ordinal);
333335
if (idx == -1)
334336
{
335-
res += Encoder(authority, false);
337+
res.Append(Encoder(authority, false));
336338
}
337339
else
338340
{
339341
// <auth>:<port>
340-
res += Encoder(authority.Substring(0, idx), false);
341-
res += authority.Substring(idx);
342+
res.Append(Encoder(authority.Substring(0, idx), false));
343+
res.Append(authority.Substring(idx));
342344
}
343345
}
344346

345347
if (!string.IsNullOrWhiteSpace(path))
346348
{
349+
var appended = false;
347350
// lower-case windows drive letters in /C:/fff or C:/fff
348351
if (path.Length >= 3 && path[0] == CharCode.Slash && path[2] == CharCode.Colon)
349352
{
350353
var code = path[1];
351354
if (code >= CharCode.A && code <= CharCode.Z)
352355
{
353-
path = $"/{Convert.ToChar(code + 32)}:{path.Substring(3)}"; // "/c:".length == 3
356+
appended = true;
357+
res.Append("/");
358+
res.Append(Convert.ToChar(code + 32));
359+
res.Append(":");
360+
res.Append(Encoder(path.Substring(3), true));
361+
// path = $"/{Convert.ToChar(code + 32)}:{path.Substring(3)}"; // "/c:".length == 3
354362
}
355363
}
356364
else if (path.Length >= 2 && path[1] == CharCode.Colon)
357365
{
358366
var code = path[0];
359367
if (code >= CharCode.A && code <= CharCode.Z)
360368
{
361-
path = $"{Convert.ToChar(code + 32)}:{path.Substring(2)}"; // "/c:".length == 3
369+
appended = true;
370+
res.Append(Convert.ToChar(code + 32));
371+
res.Append(":");
372+
res.Append(Encoder(path.Substring(2), true));
373+
// path = $"{Convert.ToChar(code + 32)}:{path.Substring(2)}"; // "/c:".length == 3
362374
}
363375
}
364376

365-
// encode the rest of the path
366-
res += Encoder(path, true);
377+
if (!appended)
378+
{
379+
res.Append(Encoder(path, true));
380+
}
367381
}
368382

369383
if (!string.IsNullOrWhiteSpace(query))
370384
{
371-
res += "?";
372-
res += Encoder(query, false);
385+
res.Append("?");
386+
res.Append(Encoder(query, false));
373387
}
374388

375389
if (!string.IsNullOrWhiteSpace(fragment))
376390
{
377-
res += "#";
378-
res += !skipEncoding ? EncodeUriComponentFast(fragment, false) : fragment;
391+
res.Append("#");
392+
res.Append(!skipEncoding ? EncodeUriComponentFast(fragment, false) : fragment);
379393
}
380394

381-
return res;
395+
return res.ToString();
382396
}
383397

384398
private static string DecodeUriComponentGraceful(string str)

src/Server/DefaultLanguageServerFacade.cs

+7-9
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ internal class DefaultLanguageServerFacade : LanguageProtocolProxy, ILanguageSer
2424
private readonly Lazy<IServerWorkDoneManager> _workDoneManager;
2525
private readonly Lazy<ISupportedCapabilities> _supportedCapabilities;
2626
private readonly TextDocumentIdentifiers _textDocumentIdentifiers;
27-
private readonly IInsanceHasStarted _insanceHasStarted;
28-
private ILanguageServer _languageServer;
29-
private TaskCompletionSource<Unit> _hasStarted;
27+
private readonly IInsanceHasStarted _instancesHasStarted;
28+
private readonly TaskCompletionSource<Unit> _hasStarted;
3029

3130
public DefaultLanguageServerFacade(
3231
IResponseRouter requestRouter,
@@ -42,7 +41,7 @@ public DefaultLanguageServerFacade(
4241
Lazy<IServerWorkDoneManager> workDoneManager,
4342
Lazy<ISupportedCapabilities> supportedCapabilities,
4443
TextDocumentIdentifiers textDocumentIdentifiers,
45-
IInsanceHasStarted insanceHasStarted
44+
IInsanceHasStarted instancesHasStarted
4645
) : base(requestRouter, resolverContext, progressManager, languageProtocolSettings)
4746
{
4847
_textDocument = textDocument;
@@ -54,7 +53,7 @@ IInsanceHasStarted insanceHasStarted
5453
_workDoneManager = workDoneManager;
5554
_supportedCapabilities = supportedCapabilities;
5655
_textDocumentIdentifiers = textDocumentIdentifiers;
57-
_insanceHasStarted = insanceHasStarted;
56+
_instancesHasStarted = instancesHasStarted;
5857
_hasStarted = new TaskCompletionSource<Unit>();
5958
}
6059

@@ -70,7 +69,7 @@ public IDisposable Register(Action<ILanguageServerRegistry> registryAction)
7069
registryAction(new LangaugeServerRegistry(ResolverContext, manager, _textDocumentIdentifiers));
7170

7271
var result = manager.GetDisposable();
73-
if (_insanceHasStarted.Started)
72+
if (_instancesHasStarted.Started)
7473
{
7574
LanguageServerHelpers.InitHandlers(ResolverContext.Resolve<ILanguageServer>(), result);
7675
}
@@ -80,9 +79,8 @@ public IDisposable Register(Action<ILanguageServerRegistry> registryAction)
8079

8180
Task IOnLanguageServerStarted.OnStarted(ILanguageServer client, CancellationToken cancellationToken)
8281
{
83-
_languageServer = client;
84-
_hasStarted.SetResult(Unit.Value);
82+
_hasStarted.TrySetResult(Unit.Value);
8583
return Task.CompletedTask;
8684
}
8785
}
88-
}
86+
}

test/Client.Tests/ClientTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ public async Task Diagnostics_Success()
628628
actualDocumentUri = request.Uri;
629629
actualDiagnostics = request.Diagnostics.ToList();
630630

631-
receivedDiagnosticsNotification.SetResult(null);
631+
receivedDiagnosticsNotification.TrySetResult(null);
632632
return Unit.Task;
633633
}
634634
);
@@ -643,7 +643,7 @@ public async Task Diagnostics_Success()
643643
}
644644
);
645645

646-
CancellationToken.Register(() => receivedDiagnosticsNotification.SetCanceled());
646+
CancellationToken.Register(() => receivedDiagnosticsNotification.TrySetCanceled());
647647

648648
// Timeout.
649649
var winner = await Task.WhenAny(

0 commit comments

Comments
 (0)