From 608c25180a7add13766fbbbf8eed2332290b1b84 Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Wed, 11 Dec 2024 07:57:17 -0800 Subject: [PATCH] Remove an enumerator allocation in SymbolCompletionItem.CreateWorker This is a small allocation, only showing up as about 0.1% of allocationsi n the typing scenario in the csharp editing speedometer test. However, the change is fairly simple, and I prefer the change as it passes around ImmutableArrays instead of IReadOnlyLists. --- ...tributeNamedParameterCompletionProvider.cs | 2 +- ...agedCallingConventionCompletionProvider.cs | 2 +- .../NamedParameterCompletionProvider.cs | 2 +- .../TupleNameCompletionProvider.cs | 2 +- .../Completion/CommonCompletionUtilities.cs | 26 ++------------- .../AbstractPartialTypeCompletionProvider.cs | 2 +- .../Providers/SymbolCompletionItem.cs | 32 +++++++++---------- .../Api/PythiaCompletionProviderBase.cs | 3 +- ...ceUsingStatementCodeRefactoringProvider.cs | 2 +- 9 files changed, 25 insertions(+), 48 deletions(-) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs index 6e703ff629340..e219e3e03abcf 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/AttributeNamedParameterCompletionProvider.cs @@ -189,7 +189,7 @@ select SymbolCompletionItem.CreateWithSymbolId( displayText: p.Name.ToIdentifierToken().ToString(), displayTextSuffix: displayTextSuffix, insertionText: null, - symbols: ImmutableArray.Create(p), + symbols: [p], contextPosition: token.SpanStart, sortText: p.Name, rules: CompletionItemRules.Default); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs index 9359ac89b0321..d4c43d1d2b2d4 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs @@ -112,7 +112,7 @@ private static void AddTypes(HashSet completionItems, int contex completionItems.Add( SymbolCompletionItem.CreateWithSymbolId( displayName, - ImmutableArray.Create(type), + [type], rules: CompletionItemRules.Default, contextPosition)); } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs index c45c28db81ff9..ea2d30a4250d0 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/NamedParameterCompletionProvider.cs @@ -117,7 +117,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: escapedName, displayTextSuffix: ColonString, - symbols: ImmutableArray.Create(parameter), + symbols: [parameter], rules: s_rules.WithMatchPriority(SymbolMatchPriority.PreferNamedArgument), contextPosition: token.SpanStart, filterText: escapedName)); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs index 22bc9cde7db4d..4dd89ec82e573 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/TupleNameCompletionProvider.cs @@ -106,7 +106,7 @@ private static void AddItems(ImmutableArray inferredTypes, int context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: field.Name, displayTextSuffix: ColonString, - symbols: ImmutableArray.Create(field), + symbols: [field], rules: CompletionItemRules.Default, contextPosition: spanStart, filterText: field.Name)); diff --git a/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs b/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs index 59171a4607a8c..e5b754d70789c 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionUtilities.cs @@ -82,28 +82,6 @@ public static bool IsStartingNewWord(SourceText text, int characterPosition, Fun return true; } - public static Func> CreateDescriptionFactory( - SolutionServices workspaceServices, - SemanticModel semanticModel, - int position, - ISymbol symbol, - SymbolDescriptionOptions options) - { - return CreateDescriptionFactory(workspaceServices, semanticModel, position, options, [symbol]); - } - - public static Func> CreateDescriptionFactory( - SolutionServices workspaceServices, SemanticModel semanticModel, int position, SymbolDescriptionOptions options, IReadOnlyList symbols) - { - return c => CreateDescriptionAsync(workspaceServices, semanticModel, position, symbols, options, supportedPlatforms: null, cancellationToken: c); - } - - public static Func> CreateDescriptionFactory( - SolutionServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData supportedPlatforms) - { - return c => CreateDescriptionAsync(workspaceServices, semanticModel, position, symbols, options, supportedPlatforms: supportedPlatforms, cancellationToken: c); - } - public static async Task CreateDescriptionAsync( SolutionServices workspaceServices, SemanticModel semanticModel, int position, ISymbol symbol, int overloadCount, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) { @@ -170,13 +148,13 @@ public static async Task CreateDescriptionAsync( } public static Task CreateDescriptionAsync( - SolutionServices workspaceServices, SemanticModel semanticModel, int position, IReadOnlyList symbols, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) + SolutionServices workspaceServices, SemanticModel semanticModel, int position, ImmutableArray symbols, SymbolDescriptionOptions options, SupportedPlatformData? supportedPlatforms, CancellationToken cancellationToken) { // Lets try to find the first non-obsolete symbol (overload) and fall-back // to the first symbol if all are obsolete. var symbol = symbols.FirstOrDefault(s => !s.IsObsolete()) ?? symbols[0]; - return CreateDescriptionAsync(workspaceServices, semanticModel, position, symbol, overloadCount: symbols.Count - 1, options, supportedPlatforms, cancellationToken); + return CreateDescriptionAsync(workspaceServices, semanticModel, position, symbol, overloadCount: symbols.Length - 1, options, supportedPlatforms, cancellationToken); } private static void AddOverloadPart(List textContentBuilder, int overloadCount, bool isGeneric) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs index 37f354e2f5c9b..01fac320c09b8 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialTypeCompletionProvider.cs @@ -66,7 +66,7 @@ private CompletionItem CreateCompletionItem(INamedTypeSymbol symbol, TSyntaxCont displayText: displayText, displayTextSuffix: suffix, insertionText: insertionText, - symbols: ImmutableArray.Create(symbol), + symbols: [symbol], contextPosition: context.Position, properties: GetProperties(symbol, context), rules: CompletionItemRules.Default); diff --git a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs index be34b7df9a37f..ab5be33964e62 100644 --- a/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs @@ -22,17 +22,17 @@ internal static class SymbolCompletionItem { private const string InsertionTextProperty = "InsertionText"; - private static readonly Action, ArrayBuilder>> s_addSymbolEncoding = AddSymbolEncoding; - private static readonly Action, ArrayBuilder>> s_addSymbolInfo = AddSymbolInfo; + private static readonly Action, ArrayBuilder>> s_addSymbolEncoding = AddSymbolEncoding; + private static readonly Action, ArrayBuilder>> s_addSymbolInfo = AddSymbolInfo; private static readonly char[] s_projectSeperators = [';']; private static CompletionItem CreateWorker( string displayText, string? displayTextSuffix, - IReadOnlyList symbols, + ImmutableArray symbols, CompletionItemRules rules, int contextPosition, - Action, ArrayBuilder>> symbolEncoder, + Action, ArrayBuilder>> symbolEncoder, string? sortText = null, string? insertionText = null, string? filterText = null, @@ -50,16 +50,14 @@ private static CompletionItem CreateWorker( builder.AddRange(properties); if (insertionText != null) - { builder.Add(KeyValuePairUtil.Create(InsertionTextProperty, insertionText)); - } builder.Add(KeyValuePairUtil.Create("ContextPosition", contextPosition.ToString())); AddSupportedPlatforms(builder, supportedPlatforms); symbolEncoder(symbols, builder); tags = tags.NullToEmpty(); - if (symbols.All(symbol => symbol.IsObsolete()) && !tags.Contains(WellKnownTags.Deprecated)) + if (!tags.Contains(WellKnownTags.Deprecated) && symbols.All(static symbol => symbol.IsObsolete())) tags = tags.Add(WellKnownTags.Deprecated); var firstSymbol = symbols[0]; @@ -80,10 +78,10 @@ private static CompletionItem CreateWorker( return item; } - private static void AddSymbolEncoding(IReadOnlyList symbols, ArrayBuilder> properties) + private static void AddSymbolEncoding(ImmutableArray symbols, ArrayBuilder> properties) => properties.Add(KeyValuePairUtil.Create("Symbols", EncodeSymbols(symbols))); - private static void AddSymbolInfo(IReadOnlyList symbols, ArrayBuilder> properties) + private static void AddSymbolInfo(ImmutableArray symbols, ArrayBuilder> properties) { var symbol = symbols[0]; var isGeneric = symbol.GetArity() > 0; @@ -107,13 +105,13 @@ public static bool GetShouldProvideParenthesisCompletion(CompletionItem item) return false; } - public static string EncodeSymbols(IReadOnlyList symbols) + public static string EncodeSymbols(ImmutableArray symbols) { - if (symbols.Count > 1) + if (symbols.Length > 1) { return string.Join("|", symbols.Select(EncodeSymbol)); } - else if (symbols.Count == 1) + else if (symbols.Length == 1) { return EncodeSymbol(symbols[0]); } @@ -270,7 +268,7 @@ public static bool TryGetInsertionText(CompletionItem item, [NotNullWhen(true)] // COMPAT OVERLOAD: This is used by IntelliCode. public static CompletionItem CreateWithSymbolId( string displayText, - IReadOnlyList symbols, + ImmutableArray symbols, CompletionItemRules rules, int contextPosition, string? sortText = null, @@ -302,7 +300,7 @@ public static CompletionItem CreateWithSymbolId( public static CompletionItem CreateWithSymbolId( string displayText, string? displayTextSuffix, - IReadOnlyList symbols, + ImmutableArray symbols, CompletionItemRules rules, int contextPosition, string? sortText = null, @@ -326,7 +324,7 @@ public static CompletionItem CreateWithSymbolId( public static CompletionItem CreateWithNameAndKind( string displayText, string displayTextSuffix, - IReadOnlyList symbols, + ImmutableArray symbols, CompletionItemRules rules, int contextPosition, string? sortText = null, @@ -357,12 +355,12 @@ internal static bool GetSymbolIsGeneric(CompletionItem item) => item.TryGetProperty("IsGeneric", out var v) && bool.TryParse(v, out var isGeneric) && isGeneric; public static async Task GetDescriptionAsync( - CompletionItem item, IReadOnlyList symbols, Document document, SemanticModel semanticModel, SymbolDescriptionOptions options, CancellationToken cancellationToken) + CompletionItem item, ImmutableArray symbols, Document document, SemanticModel semanticModel, SymbolDescriptionOptions options, CancellationToken cancellationToken) { var position = GetDescriptionPosition(item); var supportedPlatforms = GetSupportedPlatforms(item, document.Project.Solution); - if (symbols.Count != 0) + if (symbols.Length != 0) { return await CommonCompletionUtilities.CreateDescriptionAsync(document.Project.Solution.Services, semanticModel, position, symbols, options, supportedPlatforms, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs index 66a4aa7cb1292..a19b4f9380989 100644 --- a/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs +++ b/src/Features/Core/Portable/ExternalAccess/Pythia/Api/PythiaCompletionProviderBase.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api; @@ -42,7 +43,7 @@ public static CompletionItem CreateSymbolCompletionItem( SupportedPlatformData? supportedPlatforms = null, ImmutableDictionary? properties = null, ImmutableArray tags = default) - => SymbolCompletionItem.CreateWithSymbolId(displayText, displayTextSuffix: null, symbols, rules, contextPosition, sortText, insertionText, + => SymbolCompletionItem.CreateWithSymbolId(displayText, displayTextSuffix: null, symbols.ToImmutableArray(), rules, contextPosition, sortText, insertionText, filterText, displayTextPrefix: null, inlineDescription: null, glyph: null, supportedPlatforms, properties.AsImmutableOrNull(), tags); public static ImmutableArray CreateRecommendedKeywordDisplayParts(string keyword, string toolTip) diff --git a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs index 789fcb2f94aed..494638685f764 100644 --- a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs @@ -429,7 +429,7 @@ private static TStatementSyntax FindSiblingStatementContainingLastUsage( private static void AddReferencedLocalVariables( HashSet referencedVariables, SyntaxNode node, - IReadOnlyList localVariables, + ArrayBuilder localVariables, SemanticModel semanticModel, ISyntaxFactsService syntaxFactsService, CancellationToken cancellationToken)