diff --git a/Razor.sln b/Razor.sln index ed7243ac96..1d3fd090db 100644 --- a/Razor.sln +++ b/Razor.sln @@ -180,6 +180,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorSyntaxGenerator", "src EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compiler Tests", "Compiler Tests", "{A5E2E4FA-6087-4C16-BB7A-89E23AA0F4E3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Common.Test", "src\Razor\test\Microsoft.AspNetCore.Razor.Common.Test\Microsoft.AspNetCore.Razor.Common.Test.csproj", "{23E48E5E-91FC-421E-B122-C7D084FCE39A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -756,6 +758,14 @@ Global {A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9}.Release|Any CPU.Build.0 = Release|Any CPU {A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU {A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.Release|Any CPU.Build.0 = Release|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {23E48E5E-91FC-421E-B122-C7D084FCE39A}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -839,6 +849,7 @@ Global {1360ABF4-752C-4069-84A9-8D1831281AF1} = {FB7C870E-A173-4F75-BE63-4EF39C79A759} {97DE8703-467C-49A7-BCE4-42FF1FEC8AC2} = {FB7C870E-A173-4F75-BE63-4EF39C79A759} {A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9} = {FB7C870E-A173-4F75-BE63-4EF39C79A759} + {23E48E5E-91FC-421E-B122-C7D084FCE39A} = {92463391-81BE-462B-AC3C-78C6C760741F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Microsoft.AspNetCore.Razor.Common.csproj b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Microsoft.AspNetCore.Razor.Common.csproj index 7738d4b2b7..4061f333de 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Microsoft.AspNetCore.Razor.Common.csproj +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Microsoft.AspNetCore.Razor.Common.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.Policy.cs new file mode 100644 index 0000000000..274a948325 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.Policy.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class ArrayBuilderPool +{ + private class Policy : IPooledObjectPolicy.Builder> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public ImmutableArray.Builder Create() => ImmutableArray.CreateBuilder(); + + public bool Return(ImmutableArray.Builder builder) + { + var count = builder.Count; + + builder.Clear(); + + if (count > DefaultPool.MaximumObjectSize) + { + builder.Capacity = DefaultPool.MaximumObjectSize; + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.cs new file mode 100644 index 0000000000..83713f0c3c --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ArrayBuilderPool`1.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class ArrayBuilderPool +{ + public static readonly ObjectPool.Builder> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject.Builder> GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject.Builder> GetPooledObject(out ImmutableArray.Builder builder) + => Default.GetPooledObject(out builder); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DefaultPool.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DefaultPool.cs new file mode 100644 index 0000000000..66ef76360b --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DefaultPool.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static class DefaultPool +{ + public const int MaximumObjectSize = 512; + + public static ObjectPool Create(IPooledObjectPolicy policy) + where T : class + => new DefaultObjectPool(policy, 20); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.Policy.cs new file mode 100644 index 0000000000..75ab2c4114 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.Policy.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class DictionaryPool + where TKey : notnull +{ + private class Policy : IPooledObjectPolicy> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public Dictionary Create() => new(); + + public bool Return(Dictionary map) + { + var count = map.Count; + + map.Clear(); + + return count <= DefaultPool.MaximumObjectSize; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.cs new file mode 100644 index 0000000000..e8a41d289d --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/DictionaryPool`2.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class DictionaryPool + where TKey : notnull +{ + public static readonly ObjectPool> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject> GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject> GetPooledObject(out Dictionary map) + => Default.GetPooledObject(out map); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.Policy.cs new file mode 100644 index 0000000000..374490d08d --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.Policy.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class HashSetPool +{ + private class Policy : IPooledObjectPolicy> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public HashSet Create() => new(); + + public bool Return(HashSet set) + { + var count = set.Count; + + set.Clear(); + + if (count > DefaultPool.MaximumObjectSize) + { + set.TrimExcess(); + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.cs new file mode 100644 index 0000000000..ba4e0ff1a7 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/HashSetPool`1.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances that compares items using default equality. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class HashSetPool +{ + public static readonly ObjectPool> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject> GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject> GetPooledObject(out HashSet set) + => Default.GetPooledObject(out set); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.Policy.cs new file mode 100644 index 0000000000..40a7ffed79 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.Policy.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class ListPool +{ + private class Policy : IPooledObjectPolicy> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public List Create() => new(); + + public bool Return(List list) + { + var count = list.Count; + + list.Clear(); + + if (count > DefaultPool.MaximumObjectSize) + { + list.TrimExcess(); + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.cs new file mode 100644 index 0000000000..7f9cc9d061 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ListPool`1.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class ListPool +{ + public static readonly ObjectPool> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject> GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject> GetPooledObject(out List list) + => Default.GetPooledObject(out list); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObjectExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObjectExtensions.cs new file mode 100644 index 0000000000..663986b97f --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObjectExtensions.cs @@ -0,0 +1,99 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Text; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class PooledObjectExtensions +{ + public static PooledObject.Builder> GetPooledObject(this ObjectPool.Builder> pool) + => new(pool); + + public static PooledObject.Builder> GetPooledObject( + this ObjectPool.Builder> pool, + out ImmutableArray.Builder builder) + { + var pooledObject = pool.GetPooledObject(); + builder = pooledObject.Object; + return pooledObject; + } + + public static PooledObject> GetPooledObject(this ObjectPool> pool) + where TKey : notnull + => new(pool); + + public static PooledObject> GetPooledObject( + this ObjectPool> pool, + out Dictionary map) + where TKey : notnull + { + var pooledObject = pool.GetPooledObject(); + map = pooledObject.Object; + return pooledObject; + } + + public static PooledObject> GetPooledObject(this ObjectPool> pool) + => new(pool); + + public static PooledObject> GetPooledObject( + this ObjectPool> pool, + out HashSet set) + { + var pooledObject = pool.GetPooledObject(); + set = pooledObject.Object; + return pooledObject; + } + + public static PooledObject> GetPooledObject(this ObjectPool> pool) + => new(pool); + + public static PooledObject> GetPooledObject( + this ObjectPool> pool, + out List list) + { + var pooledObject = pool.GetPooledObject(); + list = pooledObject.Object; + return pooledObject; + } + + public static PooledObject> GetPooledObject(this ObjectPool> pool) + => new(pool); + + public static PooledObject> GetPooledObject( + this ObjectPool> pool, + out Stack stack) + { + var pooledObject = pool.GetPooledObject(); + stack = pooledObject.Object; + return pooledObject; + } + + public static PooledObject GetPooledObject(this ObjectPool pool) + => new(pool); + + public static PooledObject GetPooledObject( + this ObjectPool pool, + out Stopwatch watch) + { + var pooledObject = pool.GetPooledObject(); + watch = pooledObject.Object; + return pooledObject; + } + + public static PooledObject GetPooledObject(this ObjectPool pool) + => new(pool); + + public static PooledObject GetPooledObject( + this ObjectPool pool, + out StringBuilder builder) + { + var pooledObject = pool.GetPooledObject(); + builder = pooledObject.Object; + return pooledObject; + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObject`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObject`1.cs new file mode 100644 index 0000000000..be24601088 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/PooledObject`1.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +// Copied from https://github/dotnet/roslyn + +using System; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal struct PooledObject : IDisposable + where T : class +{ + private readonly ObjectPool _pool; + private T? _object; + + // Because of how this API is intended to be used, we don't want the consumption code to have + // to deal with Object being a nullable reference type. Intead, the guarantee is that this is + // non-null until this is disposed. + public T Object => _object!; + + public PooledObject(ObjectPool pool) + : this() + { + _pool = pool; + _object = pool.Get(); + } + + public void Dispose() + { + if (_object is { } obj) + { + _pool.Return(obj); + _object = null; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.Policy.cs new file mode 100644 index 0000000000..fa844038e5 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.Policy.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.Utilities; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class ReferenceEqualityHashSetPool +{ + private class Policy : IPooledObjectPolicy> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public HashSet Create() => new(ReferenceEqualityComparer.Instance); + + public bool Return(HashSet set) + { + var count = set.Count; + + set.Clear(); + + if (count > DefaultPool.MaximumObjectSize) + { + set.TrimExcess(); + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.cs new file mode 100644 index 0000000000..c5a521cd0f --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/ReferenceEqualityHashSetPool`1.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances that compares items using reference equality. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class ReferenceEqualityHashSetPool + where T : class +{ + public static readonly ObjectPool> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject> GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject> GetPooledObject(out HashSet set) + => Default.GetPooledObject(out set); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.Policy.cs new file mode 100644 index 0000000000..2fed6370f8 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.Policy.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class StackPool +{ + private class Policy : IPooledObjectPolicy> + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public Stack Create() => new(); + + public bool Return(Stack stack) + { + var count = stack.Count; + + stack.Clear(); + + if (count > DefaultPool.MaximumObjectSize) + { + stack.TrimExcess(); + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.cs new file mode 100644 index 0000000000..b70af11217 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StackPool`1.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class StackPool +{ + public static readonly ObjectPool> Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject> GetPooledObject() => Default.GetPooledObject(); + + public static PooledObject> GetPooledObject(out Stack stack) + => Default.GetPooledObject(out stack); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.Policy.cs new file mode 100644 index 0000000000..5844b7b0c2 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.Policy.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class StopwatchPool +{ + private class Policy : IPooledObjectPolicy + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public Stopwatch Create() => new(); + + public bool Return(Stopwatch watch) + { + watch.Reset(); + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.cs new file mode 100644 index 0000000000..8479df1e92 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StopwatchPool.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class StopwatchPool +{ + public static readonly ObjectPool Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject GetPooledObject(out Stopwatch watch) + => Default.GetPooledObject(out watch); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.Policy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.Policy.cs new file mode 100644 index 0000000000..1e7ac018ee --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.Policy.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Text; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class StringBuilderPool +{ + private class Policy : IPooledObjectPolicy + { + public static readonly Policy Instance = new(); + + private Policy() + { + } + + public StringBuilder Create() => new(); + + public bool Return(StringBuilder builder) + { + builder.Clear(); + + if (builder.Capacity > DefaultPool.MaximumObjectSize) + { + builder.Capacity = DefaultPool.MaximumObjectSize; + } + + return true; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.cs new file mode 100644 index 0000000000..75d78316c8 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringBuilderPool.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Text; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// A pool of instances. +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class StringBuilderPool +{ + public static readonly ObjectPool Default = DefaultPool.Create(Policy.Instance); + + public static PooledObject GetPooledObject() + => Default.GetPooledObject(); + + public static PooledObject GetPooledObject(out StringBuilder builder) + => Default.GetPooledObject(out builder); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalIgnoreCasePolicy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalIgnoreCasePolicy.cs new file mode 100644 index 0000000000..736e28a96c --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalIgnoreCasePolicy.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class StringDictionaryPool +{ + private class OrdinalIgnoreCasePolicy : IPooledObjectPolicy> + { + public static readonly OrdinalIgnoreCasePolicy Instance = new(); + + private OrdinalIgnoreCasePolicy() + { + } + + public Dictionary Create() => new(StringComparer.OrdinalIgnoreCase); + + public bool Return(Dictionary map) + { + var count = map.Count; + + map.Clear(); + + // If the map grew too large, don't return it to the pool. + return count <= DefaultPool.MaximumObjectSize; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalPolicy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalPolicy.cs new file mode 100644 index 0000000000..3eca68439a --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.OrdinalPolicy.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +internal static partial class StringDictionaryPool +{ + private class OrdinalPolicy : IPooledObjectPolicy> + { + public static readonly OrdinalPolicy Instance = new(); + + private OrdinalPolicy() + { + } + + public Dictionary Create() => new(StringComparer.Ordinal); + + public bool Return(Dictionary map) + { + var count = map.Count; + + map.Clear(); + + // If the map grew too large, don't return it to the pool. + return count <= DefaultPool.MaximumObjectSize; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.cs new file mode 100644 index 0000000000..33cc544688 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/PooledObjects/StringDictionaryPool`1.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Razor.PooledObjects; + +/// +/// Pooled instances when the key is of type . +/// +/// +/// +/// Instances originating from this pool are intended to be short-lived and are suitable +/// for temporary work. Do not return them as the results of methods or store them in fields. +/// +internal static partial class StringDictionaryPool +{ + public static readonly ObjectPool> Ordinal = ObjectPool.Create(OrdinalPolicy.Instance); + public static readonly ObjectPool> OrdinalIgnoreCase = ObjectPool.Create(OrdinalIgnoreCasePolicy.Instance); + + public static PooledObject> GetPooledObject() + => Ordinal.GetPooledObject(); + + public static PooledObject> GetPooledObject(out Dictionary map) + => Ordinal.GetPooledObject(out map); + + public static PooledObject> GetPooledObject(bool ignoreCase) + => ignoreCase + ? OrdinalIgnoreCase.GetPooledObject() + : Ordinal.GetPooledObject(); + + public static PooledObject> GetPooledObject(bool ignoreCase, out Dictionary map) + => ignoreCase + ? OrdinalIgnoreCase.GetPooledObject(out map) + : Ordinal.GetPooledObject(out map); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Properties/AssemblyInfo.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Properties/AssemblyInfo.cs index 4628f89ea0..6e405aa15c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Properties/AssemblyInfo.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Common.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.LanguageServer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.LanguageServer.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.LanguageServer.Common.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/StringBuilderExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/StringBuilderExtensions.cs new file mode 100644 index 0000000000..529e24c0ba --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/StringBuilderExtensions.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Text; + +namespace Microsoft.AspNetCore.Razor; + +internal static class StringBuilderExtensions +{ + public static void SetCapacityIfLarger(this StringBuilder builder, int newCapacity) + { + if (builder.Capacity < newCapacity) + { + builder.Capacity = newCapacity; + } + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Utilities/ReferenceEqualityComparer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Utilities/ReferenceEqualityComparer.cs new file mode 100644 index 0000000000..d8643e51ff --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.Common/Utilities/ReferenceEqualityComparer.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Microsoft.AspNetCore.Razor.Utilities; + +internal sealed class ReferenceEqualityComparer : IEqualityComparer + where T : class +{ + public static readonly ReferenceEqualityComparer Instance = new(); + + private ReferenceEqualityComparer() + { + } + + bool IEqualityComparer.Equals(T? x, T? y) + => ReferenceEquals(x, y); + + int IEqualityComparer.GetHashCode(T obj) + => RuntimeHelpers.GetHashCode(obj); +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs index 5f9fb4e976..07fde3c2c3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -12,6 +11,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Razor.LanguageServer.Protocol; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.Extensions.Logging; @@ -165,7 +165,8 @@ internal class TextDocumentUriPresentationEndpoint : AbstractTextDocumentPresent // TODO: Add @using statements if required, or fully qualify (GetTypeName()) - var sb = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var sb); + sb.Append('<'); sb.Append(typeName); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs index 4e6b065ec8..fdafd1b808 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -14,6 +13,7 @@ using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Protocol; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; @@ -401,7 +401,10 @@ internal class CSharpOnTypeFormattingPass : CSharpFormattingPassBase private static string PrependLines(string text, string newLine, int count) { - var builder = new StringBuilder((newLine.Length * count) + text.Length); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + + builder.SetCapacityIfLarger((newLine.Length * count) + text.Length); + for (var i = 0; i < count; i++) { builder.Append(newLine); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SourceTextDiffer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SourceTextDiffer.cs index 600836b406..4718ec10ad 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SourceTextDiffer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/SourceTextDiffer.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.LanguageServer; @@ -84,7 +84,9 @@ internal class SourceTextDiffer : TextDiffer var start = 0; var end = 0; - var builder = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var builder); + foreach (var edit in edits) { var startPosition = _lineDiffOnly ? OldText.Lines[edit.Position].Start : edit.Position; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultLSPTagHelperTooltipFactory.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultLSPTagHelperTooltipFactory.cs index 07ccbc53c3..3aeed21dff 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultLSPTagHelperTooltipFactory.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultLSPTagHelperTooltipFactory.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -36,7 +37,8 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory // // Additional description infos result in a triple `---` to separate the markdown entries. - var descriptionBuilder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var descriptionBuilder); + for (var i = 0; i < associatedTagHelperInfos.Count; i++) { var descriptionInfo = associatedTagHelperInfos[i]; @@ -70,6 +72,7 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory Kind = markupKind, Value = descriptionBuilder.ToString(), }; + return true; } @@ -97,7 +100,8 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory // // Additional description infos result in a triple `---` to separate the markdown entries. - var descriptionBuilder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var descriptionBuilder); + for (var i = 0; i < associatedAttributeInfos.Count; i++) { var descriptionInfo = associatedAttributeInfos[i]; @@ -117,11 +121,11 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory var reducedReturnTypeName = ReduceTypeName(returnTypeName); descriptionBuilder.Append(reducedReturnTypeName); StartOrEndBold(descriptionBuilder, markupKind); - descriptionBuilder.Append(" "); + descriptionBuilder.Append(' '); var tagHelperTypeName = descriptionInfo.TypeName; var reducedTagHelperTypeName = ReduceTypeName(tagHelperTypeName); descriptionBuilder.Append(reducedTagHelperTypeName); - descriptionBuilder.Append("."); + descriptionBuilder.Append('.'); StartOrEndBold(descriptionBuilder, markupKind); descriptionBuilder.Append(descriptionInfo.PropertyName); StartOrEndBold(descriptionBuilder, markupKind); @@ -143,6 +147,7 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory Kind = markupKind, Value = descriptionBuilder.ToString(), }; + return true; } @@ -155,7 +160,10 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory // it'll be serialized as html (wont show). summaryContent = summaryContent.Trim(); var crefMatches = ExtractCrefMatches(summaryContent); - var summaryBuilder = new StringBuilder(summaryContent); + + using var _ = StringBuilderPool.GetPooledObject(out var summaryBuilder); + + summaryBuilder.Append(summaryContent); for (var i = crefMatches.Count - 1; i >= 0; i--) { @@ -175,11 +183,11 @@ internal class DefaultLSPTagHelperTooltipFactory : LSPTagHelperTooltipFactory return finalSummaryContent; } - private void StartOrEndBold(StringBuilder stringBuilder, MarkupKind markupKind) + private static void StartOrEndBold(StringBuilder builder, MarkupKind markupKind) { if (markupKind == MarkupKind.Markdown) { - stringBuilder.Append("**"); + builder.Append("**"); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultVSLSPTagHelperTooltipFactory.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultVSLSPTagHelperTooltipFactory.cs index 553bb98a36..7a245ea689 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultVSLSPTagHelperTooltipFactory.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/DefaultVSLSPTagHelperTooltipFactory.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Tooltip; using Microsoft.VisualStudio.Core.Imaging; using Microsoft.VisualStudio.Text.Adornments; @@ -243,7 +244,8 @@ internal class DefaultVSLSPTagHelperTooltipFactory : VSLSPTagHelperTooltipFactor private static void ClassifyReducedTypeName(List runs, string reducedTypeName) { - var currentTextRun = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var currentTextRun); + for (var i = 0; i < reducedTypeName.Length; i++) { var ch = reducedTypeName[i]; @@ -352,7 +354,8 @@ internal class DefaultVSLSPTagHelperTooltipFactory : VSLSPTagHelperTooltipFactor return; } - var currentTextRun = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var currentTextRun); + var currentCrefMatchIndex = 0; var currentCodeMatchIndex = 0; for (var i = 0; i < summaryContent.Length; i++) @@ -360,7 +363,7 @@ internal class DefaultVSLSPTagHelperTooltipFactory : VSLSPTagHelperTooltipFactor // If we made it through all the crefs and code matches, add the rest of the text and break out of the loop. if (currentCrefMatchIndex == crefMatches.Count && currentCodeMatchIndex == codeMatches.Count) { - currentTextRun.Append(summaryContent.Substring(i)); + currentTextRun.Append(summaryContent[i..]); break; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj index f5e8658329..e4293f0517 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj @@ -29,6 +29,7 @@ <_PublishedFiles Include="$(PublishDir)**\Microsoft.CodeAnalysis.Remote.Razor.*" Exclude="@(_ExcludedFiles)"/> <_PublishedFiles Include="$(PublishDir)**\Microsoft.AspNetCore.*" /> <_PublishedFiles Include="$(PublishDir)**\Microsoft.Extensions.Logging.Abstractions.dll" /> + <_PublishedFiles Include="$(PublishDir)**\Microsoft.Extensions.ObjectPool.dll" /> <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Extension)' == '.pdb'" /> <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Extension)' == '.xml'" /> diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Microsoft.VisualStudio.Mac.RazorAddin.csproj b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Microsoft.VisualStudio.Mac.RazorAddin.csproj index 3ee2194d91..e0362bb5c9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Microsoft.VisualStudio.Mac.RazorAddin.csproj +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Microsoft.VisualStudio.Mac.RazorAddin.csproj @@ -81,6 +81,7 @@ + diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Properties/_Manifest.addin.xml b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Properties/_Manifest.addin.xml index 738d6e40e6..690b6172d5 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Properties/_Manifest.addin.xml +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/Properties/_Manifest.addin.xml @@ -17,6 +17,7 @@ + diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/mpack/addin.info b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/mpack/addin.info index b28c0dece6..36e468972b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/mpack/addin.info +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/mpack/addin.info @@ -17,6 +17,7 @@ + diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyBindingRedirects.cs b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyBindingRedirects.cs index 6b0d918877..0947414cf4 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyBindingRedirects.cs +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyBindingRedirects.cs @@ -7,55 +7,62 @@ using Microsoft.VisualStudio.Shell; AssemblyName = "Microsoft.Extensions.Logging.Abstractions", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.Logging", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.DependencyInjection", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.DependencyInjection.Abstractions", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", + NewVersion = "6.0.0.0")] +[assembly: ProvideBindingRedirection( + AssemblyName = "Microsoft.Extensions.ObjectPool", + GenerateCodeBase = true, + PublicKeyToken = "adb9793829ddae60", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.Options", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.Configuration.Abstractions", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.Configuration", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] [assembly: ProvideBindingRedirection( AssemblyName = "Microsoft.Extensions.Primitives", GenerateCodeBase = true, PublicKeyToken = "adb9793829ddae60", - OldVersionLowerBound = "2.0.0.0", - OldVersionUpperBound = "2.0.0.0", + OldVersionLowerBound = "0.0.0.0", + OldVersionUpperBound = "6.0.0.0", NewVersion = "6.0.0.0")] diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs index 5cb42e4405..bd0ab4ad27 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs @@ -9,6 +9,7 @@ using Microsoft.VisualStudio.Shell; [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\OmniSharp.Extensions.LanguageServer.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\OmniSharp.Extensions.LanguageServer.Shared.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.CommonLanguageServerProtocol.Framework.dll")] +[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.Extensions.ObjectPool.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.Extensions.Options.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.Extensions.Primitives.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.Extensions.DependencyInjection.dll")] diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj index 862677393e..6f5bfa5f9c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj @@ -143,6 +143,7 @@ + diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest index 48a1e8004c..5cea67313e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest @@ -42,6 +42,7 @@ + diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/Microsoft.AspNetCore.Razor.Common.Test.csproj b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/Microsoft.AspNetCore.Razor.Common.Test.csproj new file mode 100644 index 0000000000..98701a9306 --- /dev/null +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/Microsoft.AspNetCore.Razor.Common.Test.csproj @@ -0,0 +1,16 @@ + + + + $(DefaultNetCoreTargetFramework);$(DefaultNetFxTargetFramework) + + + + + + + + + + + + diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/XunitAssemblyInfo.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/XunitAssemblyInfo.cs new file mode 100644 index 0000000000..3417e66389 --- /dev/null +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/XunitAssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Xunit; + +[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/xunit.runner.json b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/xunit.runner.json new file mode 100644 index 0000000000..4b6534f94d --- /dev/null +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Common.Test/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "methodDisplay": "method", + "shadowCopy": false, + "parallelizeTestCollections": false +} \ No newline at end of file diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokenTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokenTestBase.cs index a1c804ab35..18ab72416f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokenTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokenTestBase.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Completion; using Microsoft.AspNetCore.Razor.LanguageServer.Extensions; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models; using Microsoft.AspNetCore.Razor.LanguageServer.Test.Common; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -159,7 +160,8 @@ public abstract class SemanticTokenTestBase : TagHelperServiceTestBase private static void GenerateSemanticBaseline(IEnumerable? actual, string baselineFileName) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + if (actual != null) { var actualArray = actual.ToArray(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/CompilationFailedException.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/CompilationFailedException.cs index 70dd202c57..6b6ab9c35e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/CompilationFailedException.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/CompilationFailedException.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis; using Xunit.Sdk; @@ -27,7 +28,8 @@ public class CompilationFailedException : XunitException { get { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine("Compilation failed: "); var syntaxTreesWithErrors = new HashSet(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeVerifier.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeVerifier.cs index 4198239751..84fafd8193 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeVerifier.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeVerifier.cs @@ -7,8 +7,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using Microsoft.AspNetCore.Razor.Language.Intermediate; +using Microsoft.AspNetCore.Razor.PooledObjects; using Xunit; using Xunit.Sdk; @@ -242,7 +242,8 @@ public static class IntermediateNodeVerifier private static string Format(IntermediateNode[] ancestors, string expected, string actual, string userMessage) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine(userMessage); builder.AppendLine(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs index d04abc0241..d40bad5b24 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/RazorIntegrationTestBase.cs @@ -9,9 +9,9 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis; @@ -398,7 +398,8 @@ public class RazorIntegrationTestBase : TestBase { get { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine("Compilation failed: "); var diagnostics = Compilation.GetDiagnostics(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/SourceMappingsSerializer.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/SourceMappingsSerializer.cs index 1ce0644c0b..b5e40e5550 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/SourceMappingsSerializer.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/SourceMappingsSerializer.cs @@ -4,6 +4,7 @@ #nullable disable using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests; @@ -11,7 +12,8 @@ public static class SourceMappingsSerializer { public static string Serialize(RazorCSharpDocument csharpDocument, RazorSourceDocument sourceDocument) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + var charBuffer = new char[sourceDocument.Length]; sourceDocument.CopyTo(0, charBuffer, 0, sourceDocument.Length); var sourceContent = new string(charBuffer); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs index 2dd19ab662..6e308a40c9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Intermediate/IntermediateNodeAssert.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; -using System.Text; using Microsoft.AspNetCore.Razor.Language.Extensions; +using Microsoft.AspNetCore.Razor.PooledObjects; using Xunit; using Xunit.Sdk; @@ -99,7 +99,9 @@ public static class IntermediateNodeAssert try { var html = Assert.IsType(node); - var content = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < html.Children.Count; i++) { var token = Assert.IsType(html.Children[i]); @@ -120,7 +122,9 @@ public static class IntermediateNodeAssert try { var statement = Assert.IsType(node); - var content = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < statement.Children.Count; i++) { var token = Assert.IsType(statement.Children[i]); @@ -207,7 +211,8 @@ public static class IntermediateNodeAssert try { - var content = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < attributeValue.Children.Count; i++) { var token = Assert.IsType(attributeValue.Children[i]); @@ -230,7 +235,8 @@ public static class IntermediateNodeAssert try { - var content = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < attributeValue.Children.Count; i++) { var token = Assert.IsType(attributeValue.Children[i]); @@ -253,7 +259,8 @@ public static class IntermediateNodeAssert { var cSharp = Assert.IsType(node); - var content = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < cSharp.Children.Count; i++) { var token = Assert.IsType(cSharp.Children[i]); @@ -274,7 +281,9 @@ public static class IntermediateNodeAssert try { var beginNode = Assert.IsType(node); - var content = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < beginNode.Children.Count; i++) { var token = Assert.IsType(beginNode.Children[i]); @@ -295,7 +304,9 @@ public static class IntermediateNodeAssert try { var endNode = Assert.IsType(node); - var content = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var content); + for (var i = 0; i < endNode.Children.Count; i++) { var token = Assert.IsType(endNode.Children[i]); @@ -458,7 +469,8 @@ public static class IntermediateNodeAssert private static string Format(IntermediateNode[] ancestors, IEnumerable nodes, string userMessage) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine(userMessage); builder.AppendLine(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/ClassifiedSpan/ClassifiedSpanVerifier.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/ClassifiedSpan/ClassifiedSpanVerifier.cs index 77c1c27d50..66e2adb175 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/ClassifiedSpan/ClassifiedSpanVerifier.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/ClassifiedSpan/ClassifiedSpanVerifier.cs @@ -5,7 +5,7 @@ using System; using System.IO; -using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Xunit; using Xunit.Sdk; @@ -90,7 +90,8 @@ internal class ClassifiedSpanVerifier private static string Format(string expected, string actual, string userMessage) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine(userMessage); builder.AppendLine(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeVerifier.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeVerifier.cs index 31e5ab9a52..6565b37f1b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeVerifier.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeVerifier.cs @@ -7,8 +7,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.PooledObjects; using Xunit; using Xunit.Sdk; @@ -263,7 +263,8 @@ public static class SyntaxNodeVerifier private static string Format(SyntaxNode[] ancestors, string expected, string actual, string userMessage) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine(userMessage); builder.AppendLine(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeWriter.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeWriter.cs index 4ffb15d494..94b639e172 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeWriter.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/SyntaxNodeWriter.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.AspNetCore.Razor.Language.Legacy; +using Microsoft.AspNetCore.Razor.PooledObjects; namespace Microsoft.AspNetCore.Razor.Language.Syntax; @@ -113,7 +114,9 @@ internal class SyntaxNodeWriter : SyntaxRewriter return; } - var builder = new StringBuilder("Directive:{"); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + + builder.Append("Directive:{"); builder.Append(node.DirectiveDescriptor.Directive); builder.Append(';'); builder.Append(node.DirectiveDescriptor.Kind); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/TagHelperSpan/TagHelperSpanVerifier.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/TagHelperSpan/TagHelperSpanVerifier.cs index 37afb419f2..68f4891177 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/TagHelperSpan/TagHelperSpanVerifier.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Language/Legacy/TagHelperSpan/TagHelperSpanVerifier.cs @@ -5,7 +5,7 @@ using System; using System.IO; -using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Xunit; using Xunit.Sdk; @@ -90,7 +90,8 @@ internal class TagHelperSpanVerifier private static string Format(string expected, string actual, string userMessage) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + builder.AppendLine(userMessage); builder.AppendLine(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Mef/TestComposition.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Mef/TestComposition.cs index 4b99171815..96e545c454 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Mef/TestComposition.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common/Mef/TestComposition.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; -using System.Text; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.VisualStudio.Composition; using Roslyn.Utilities; @@ -225,7 +225,8 @@ public HostServices GetHostServices() { var configuration = CompositionConfiguration.Create(GetCatalog()); - var sb = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var sb); + foreach (var errorGroup in configuration.CompositionErrors) { foreach (var error in errorGroup) diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CodeFoldingTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CodeFoldingTests.cs index 3394d2cb2b..f74f57faee 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CodeFoldingTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/CodeFoldingTests.cs @@ -3,8 +3,8 @@ using System.Collections.Immutable; using System.Linq; -using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Outlining; @@ -93,7 +93,8 @@ public class CodeFoldingTests : AbstractRazorEditorTest static string PrintLines(ImmutableArray lines, ITextView textView) { - var sb = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var sb); + foreach (var line in lines) { sb.AppendLine(); diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Hover.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Hover.cs index 07388e35f7..1ba1e6e58e 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Hover.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess_Hover.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; @@ -68,7 +69,8 @@ internal partial class EditorInProcess { var hoverContent = await HoverAsync(position, cancellationToken); - var sb = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var sb); + TraverseContent(hoverContent, sb); return sb.ToString(); diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/Semantic/RazorSemanticTokensTests.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/Semantic/RazorSemanticTokensTests.cs index 7a38a67ee0..5a360a06dc 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/Semantic/RazorSemanticTokensTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/Semantic/RazorSemanticTokensTests.cs @@ -6,10 +6,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; @@ -143,7 +143,8 @@ public class RazorSemanticTokensTests : AbstractRazorEditorTest private static void GenerateSemanticBaseline(IEnumerable actual, string baselineFileName) { - var builder = new StringBuilder(); + using var _ = StringBuilderPool.GetPooledObject(out var builder); + foreach (var baseline in actual) { builder.Append(baseline.Span.Start.Position).Append(Separator); diff --git a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/VisualStudioLogging.cs b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/VisualStudioLogging.cs index d077753303..b22b5f8872 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/VisualStudioLogging.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/VisualStudioLogging.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.Internal.VisualStudio.Shell.Embeddable.Feedback; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; @@ -98,7 +98,8 @@ internal static class VisualStudioLogging private static void RazorExtensionExplorerLogger(string filePath) { var hiveDirectory = GetHiveDirectory(); - var fileBuilder = new StringBuilder(); + + using var _ = StringBuilderPool.GetPooledObject(out var fileBuilder); var extensionsDir = Path.Combine(hiveDirectory, "Extensions"); var compatListFile = Path.Combine(extensionsDir, "CompatibilityList.xml");