diff --git a/src/EditorFeatures/CSharp/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs b/src/EditorFeatures/CSharp/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs index e27c9658742c9..1fbf06fe7d0b6 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/AbstractCSharpSignatureHelpProvider.cs @@ -61,7 +61,7 @@ protected static SignatureHelpParameter Convert( return new SignatureHelpParameter( parameter.Name, parameter.IsOptional, - parameter.GetDocumentationParts(semanticModel, position, formatter, cancellationToken), + parameter.GetDocumentationPartsFactory(semanticModel, position, formatter), parameter.ToMinimalDisplayParts(semanticModel, position)); } diff --git a/src/EditorFeatures/CSharp/SignatureHelp/AttributeSignatureHelpProvider.cs b/src/EditorFeatures/CSharp/SignatureHelp/AttributeSignatureHelpProvider.cs index 5a4d8e0412ec0..ce9a16e68c513 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/AttributeSignatureHelpProvider.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/AttributeSignatureHelpProvider.cs @@ -135,7 +135,7 @@ private SignatureHelpItem Convert( constructor, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic, - constructor.GetDocumentationParts(semanticModel, position, documentationCommentFormatter, cancellationToken), + constructor.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormatter), GetPreambleParts(constructor, semanticModel, position), GetSeparatorParts(), GetPostambleParts(constructor), @@ -158,6 +158,8 @@ private IEnumerable GetParameters( for (int i = 0; i < namedParameters.Count; i++) { + cancellationToken.ThrowIfCancellationRequested(); + var namedParameter = namedParameters[i]; var type = namedParameter is IFieldSymbol ? ((IFieldSymbol)namedParameter).Type : ((IPropertySymbol)namedParameter).Type; @@ -175,7 +177,7 @@ private IEnumerable GetParameters( yield return new SignatureHelpParameter( namedParameter.Name, isOptional: true, - documentation: namedParameter.GetDocumentationParts(semanticModel, position, documentationCommentFormatter, cancellationToken), + documentationFactory: namedParameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormatter), displayParts: displayParts, prefixDisplayParts: GetParameterPrefixDisplayParts(i)); } diff --git a/src/EditorFeatures/CSharp/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs b/src/EditorFeatures/CSharp/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs index 8f3990bf56cb8..5ae886cee5e8d 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs @@ -135,7 +135,7 @@ private SignatureHelpItem Convert( constructor, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, constructor.IsParams(), - constructor.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + constructor.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(constructor, semanticModel, position), GetSeparatorParts(), GetPostambleParts(constructor), diff --git a/src/EditorFeatures/CSharp/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs b/src/EditorFeatures/CSharp/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs index a9f21faee110a..13051f4d885c7 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs @@ -200,7 +200,7 @@ private SignatureHelpItem Convert( var item = CreateItem(indexer, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, indexer.IsParams(), - indexer.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + indexer.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(indexer, position, semanticModel), GetSeparatorParts(), GetPostambleParts(indexer), diff --git a/src/EditorFeatures/CSharp/SignatureHelp/GenericNameSignatureHelpProvider.cs b/src/EditorFeatures/CSharp/SignatureHelp/GenericNameSignatureHelpProvider.cs index 73601f6177f7e..0bd3b17dc2877 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/GenericNameSignatureHelpProvider.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/GenericNameSignatureHelpProvider.cs @@ -183,7 +183,7 @@ private SignatureHelpItem Convert( symbol, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, false, - symbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + symbol.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(namedType, semanticModel, position), GetSeparatorParts(), GetPostambleParts(namedType), @@ -196,7 +196,7 @@ private SignatureHelpItem Convert( symbol, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, false, - symbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken).Concat(GetAwaitableUsage(method, semanticModel, position)), + c => symbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, c).Concat(GetAwaitableUsage(method, semanticModel, position)), GetPreambleParts(method, semanticModel, position), GetSeparatorParts(), GetPostambleParts(method, semanticModel, position), @@ -220,7 +220,7 @@ private SignatureHelpParameter Convert( return new SignatureHelpParameter( parameter.Name, isOptional: false, - documentation: parameter.GetDocumentationParts(semanticModel, position, formatter, cancellationToken), + documentationFactory: parameter.GetDocumentationPartsFactory(semanticModel, position, formatter), displayParts: parameter.ToMinimalDisplayParts(semanticModel, position, s_minimallyQualifiedFormat), selectedDisplayParts: GetSelectedDisplayParts(parameter, semanticModel, position, cancellationToken)); } diff --git a/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_DelegateInvoke.cs b/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_DelegateInvoke.cs index d27292b911040..055c6526b08fa 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_DelegateInvoke.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_DelegateInvoke.cs @@ -37,7 +37,7 @@ private IEnumerable GetDelegateInvokeItems( invokeMethod, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic: invokeMethod.IsParams(), - documentation: SpecializedCollections.EmptyEnumerable(), + documentationFactory: null, prefixParts: GetDelegateInvokePreambleParts(invokeMethod, semanticModel, position), separatorParts: GetSeparatorParts(), suffixParts: GetDelegateInvokePostambleParts(), @@ -62,10 +62,11 @@ private IEnumerable GetDelegateInvokeParameters( { foreach (var parameter in invokeMethod.Parameters) { + cancellationToken.ThrowIfCancellationRequested(); yield return new SignatureHelpParameter( parameter.Name, parameter.IsOptional, - parameter.GetDocumentationParts(semanticModel, position, formattingService, cancellationToken), + parameter.GetDocumentationPartsFactory(semanticModel, position, formattingService), parameter.ToMinimalDisplayParts(semanticModel, position)); } } diff --git a/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs b/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs index e279e20ee871d..ace33c3afa21e 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs @@ -108,7 +108,7 @@ private SignatureHelpItem ConvertMethodGroupMethod( method, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, method.IsParams(), - method.OriginalDefinition.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken).Concat(GetAwaitableUsage(method, semanticModel, position)), + c => method.OriginalDefinition.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, c).Concat(GetAwaitableUsage(method, semanticModel, position)), GetMethodGroupPreambleParts(method, semanticModel, position), GetSeparatorParts(), GetMethodGroupPostambleParts(method), diff --git a/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs b/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs index 86d624cba9c77..acbb99aade86d 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_DelegateType.cs @@ -32,7 +32,7 @@ private IEnumerable GetDelegateTypeConstructors( invokeMethod, semanticModel, position, symbolDisplayService, anonymousTypeDispalyService, isVariadic: false, - documentation: SpecializedCollections.EmptyEnumerable(), + documentationFactory: null, prefixParts: GetDelegateTypePreambleParts(invokeMethod, semanticModel, position), separatorParts: GetSeparatorParts(), suffixParts: GetDelegateTypePostambleParts(invokeMethod), @@ -80,7 +80,7 @@ private IEnumerable GetDelegateTypeParameters(IMethodSym yield return new SignatureHelpParameter( TargetName, isOptional: false, - documentation: SpecializedCollections.EmptyEnumerable(), + documentationFactory: null, displayParts: parts); } diff --git a/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs b/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs index c473c82cb2ae1..69d50ed346472 100644 --- a/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs +++ b/src/EditorFeatures/CSharp/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider_NormalType.cs @@ -56,7 +56,7 @@ private SignatureHelpItem ConvertNormalTypeConstructor( constructor, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, constructor.IsParams(), - constructor.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + constructor.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetNormalTypePreambleParts(constructor, semanticModel, position), GetSeparatorParts(), GetNormalTypePostambleParts(constructor), diff --git a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItem.cs b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItem.cs index 1f2119ef19b7e..965c8a5af5cba 100644 --- a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItem.cs +++ b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpItem.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis; using Roslyn.Utilities; @@ -16,25 +18,26 @@ internal class SignatureHelpItem /// selected parameter index strictly goes past the number of defined parameters for this /// item. /// - public bool IsVariadic { get; private set; } + public bool IsVariadic { get; } - public IList PrefixDisplayParts { get; private set; } - public IList SuffixDisplayParts { get; private set; } + public ImmutableArray PrefixDisplayParts { get; } + public ImmutableArray SuffixDisplayParts { get; } - // TODO(cyrusn): This probably won't be sufficient for VB query signature help. It has + // TODO: This probably won't be sufficient for VB query signature help. It has // arbitrary separators between parameters. - public IList SeparatorDisplayParts { get; private set; } + public ImmutableArray SeparatorDisplayParts { get; } - public IList Parameters { get; private set; } + public ImmutableArray Parameters { get; } - public IList DescriptionParts { get; internal set; } + public ImmutableArray DescriptionParts { get; internal set; } - // TODO(cyrusn): This may be unnecessary. How would a user ever see this. - public IList Documentation { get; set; } + public Func> DocumenationFactory { get; } + + private static readonly Func> s_emptyDocumentationFactory = _ => SpecializedCollections.EmptyEnumerable(); public SignatureHelpItem( bool isVariadic, - IEnumerable documentation, + Func> documentationFactory, IEnumerable prefixParts, IEnumerable separatorParts, IEnumerable suffixParts, @@ -47,7 +50,7 @@ public SignatureHelpItem( } this.IsVariadic = isVariadic; - this.Documentation = documentation.ToImmutableArrayOrEmpty(); + this.DocumenationFactory = documentationFactory ?? s_emptyDocumentationFactory; this.PrefixDisplayParts = prefixParts.ToImmutableArrayOrEmpty(); this.SeparatorDisplayParts = separatorParts.ToImmutableArrayOrEmpty(); this.SuffixDisplayParts = suffixParts.ToImmutableArrayOrEmpty(); diff --git a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpParameter.cs b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpParameter.cs index 97f779f4f79ea..8777dbfc0e4ab 100644 --- a/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpParameter.cs +++ b/src/EditorFeatures/Core/Extensibility/SignatureHelp/SignatureHelpParameter.cs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor @@ -13,46 +14,48 @@ internal class SignatureHelpParameter /// /// The name of this parameter. /// - public string Name { get; private set; } + public string Name { get; } /// /// Documentation for this parameter. This should normally be presented to the user when /// this parameter is selected. /// - public IList Documentation { get; private set; } + public Func> DocumentationFactory { get; } /// /// Display parts to show before the normal display parts for the parameter. /// - public IList PrefixDisplayParts { get; private set; } + public IList PrefixDisplayParts { get; } /// /// Display parts to show after the normal display parts for the parameter. /// - public IList SuffixDisplayParts { get; private set; } + public IList SuffixDisplayParts { get; } /// /// Display parts for this parameter. This should normally be presented to the user as part /// of the entire signature display. /// - public IList DisplayParts { get; private set; } + public IList DisplayParts { get; } /// /// True if this parameter is optional or not. Optional parameters may be presented in a /// different manner to users. /// - public bool IsOptional { get; private set; } + public bool IsOptional { get; } /// /// Display parts for this parameter that should be presented to the user when this /// parameter is selected. /// - public IList SelectedDisplayParts { get; private set; } + public IList SelectedDisplayParts { get; } + + private static readonly Func> s_emptyDocumentationFactory = _ => SpecializedCollections.EmptyEnumerable(); public SignatureHelpParameter( string name, bool isOptional, - IEnumerable documentation, + Func> documentationFactory, IEnumerable displayParts, IEnumerable prefixDisplayParts = null, IEnumerable suffixDisplayParts = null, @@ -60,7 +63,7 @@ public SignatureHelpParameter( { this.Name = name ?? string.Empty; this.IsOptional = isOptional; - this.Documentation = documentation.ToImmutableArrayOrEmpty(); + this.DocumentationFactory = documentationFactory ?? s_emptyDocumentationFactory; this.DisplayParts = displayParts.ToImmutableArrayOrEmpty(); this.PrefixDisplayParts = prefixDisplayParts.ToImmutableArrayOrEmpty(); this.SuffixDisplayParts = suffixDisplayParts.ToImmutableArrayOrEmpty(); diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs index 886a9360bd546..db90b3cfe31df 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs @@ -2,9 +2,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Threading; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { @@ -12,17 +10,17 @@ internal abstract partial class AbstractSignatureHelpProvider { internal class SymbolKeySignatureHelpItem : SignatureHelpItem, IEquatable { - public SymbolKey SymbolKey { get; private set; } + public SymbolKey SymbolKey { get; } public SymbolKeySignatureHelpItem( ISymbol symbol, bool isVariadic, - IEnumerable documentation, + Func> documentationFactory, IEnumerable prefixParts, IEnumerable separatorParts, IEnumerable suffixParts, IEnumerable parameters, - IEnumerable descriptionParts) : base(isVariadic, documentation, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) + IEnumerable descriptionParts) : base(isVariadic, documentationFactory, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) { this.SymbolKey = symbol == null ? null : symbol.GetSymbolKey(); } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.cs index 0c933caea15bd..835eac1ba0655 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/AbstractSignatureHelpProvider.cs @@ -75,7 +75,7 @@ protected SignatureHelpItem CreateItem( ISymbolDisplayService symbolDisplayService, IAnonymousTypeDisplayService anonymousTypeDisplayService, bool isVariadic, - IEnumerable documentation, + Func> documentationFactory, IEnumerable prefixParts, IEnumerable separatorParts, IEnumerable suffixParts, @@ -83,7 +83,7 @@ protected SignatureHelpItem CreateItem( IEnumerable descriptionParts = null) { var item = new SymbolKeySignatureHelpItem( - orderSymbol, isVariadic, documentation, prefixParts, separatorParts, + orderSymbol, isVariadic, documentationFactory, prefixParts, separatorParts, suffixParts, parameters, descriptionParts); return FixAnonymousTypeParts(orderSymbol, item, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService); @@ -93,7 +93,7 @@ private SignatureHelpItem FixAnonymousTypeParts( ISymbol orderSymbol, SignatureHelpItem item, SemanticModel semanticModel, int position, ISymbolDisplayService symbolDisplayService, IAnonymousTypeDisplayService anonymousTypeDisplayService) { var currentItem = new SymbolKeySignatureHelpItem( - orderSymbol, item.IsVariadic, item.Documentation, + orderSymbol, item.IsVariadic, item.DocumenationFactory, anonymousTypeDisplayService.InlineDelegateAnonymousTypes(item.PrefixDisplayParts, semanticModel, position, symbolDisplayService), anonymousTypeDisplayService.InlineDelegateAnonymousTypes(item.SeparatorDisplayParts, semanticModel, position, symbolDisplayService), anonymousTypeDisplayService.InlineDelegateAnonymousTypes(item.SuffixDisplayParts, semanticModel, position, symbolDisplayService), @@ -120,7 +120,7 @@ where part.Symbol.IsNormalAnonymousType() currentItem = new SymbolKeySignatureHelpItem( orderSymbol, currentItem.IsVariadic, - currentItem.Documentation, + currentItem.DocumenationFactory, info.ReplaceAnonymousTypes(currentItem.PrefixDisplayParts), info.ReplaceAnonymousTypes(currentItem.SeparatorDisplayParts), info.ReplaceAnonymousTypes(currentItem.SuffixDisplayParts), @@ -138,7 +138,7 @@ private SignatureHelpParameter ReplaceAnonymousTypes( return new SignatureHelpParameter( parameter.Name, parameter.IsOptional, - parameter.Documentation, + parameter.DocumentationFactory, info.ReplaceAnonymousTypes(parameter.DisplayParts), info.ReplaceAnonymousTypes(parameter.SelectedDisplayParts)); } @@ -153,7 +153,7 @@ private SignatureHelpParameter InlineDelegateAnonymousTypes( return new SignatureHelpParameter( parameter.Name, parameter.IsOptional, - parameter.Documentation, + parameter.DocumentationFactory, anonymousTypeDisplayService.InlineDelegateAnonymousTypes(parameter.DisplayParts, semanticModel, position, symbolDisplayService), anonymousTypeDisplayService.InlineDelegateAnonymousTypes(parameter.PrefixDisplayParts, semanticModel, position, symbolDisplayService), anonymousTypeDisplayService.InlineDelegateAnonymousTypes(parameter.SuffixDisplayParts, semanticModel, position, symbolDisplayService), @@ -256,7 +256,7 @@ private SignatureHelpItem UpdateItem(SignatureHelpItem item, SupportedPlatformDa ? item.DescriptionParts.Concat(startingNewLine.Concat(platformParts)) : startingNewLine.Concat(platformParts); - item.DescriptionParts = updatedDescription.ToList(); + item.DescriptionParts = updatedDescription.ToImmutableArrayOrEmpty(); return item; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Controller.Session_UpdateModel.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Controller.Session_UpdateModel.cs index 094b7adc7b39d..796549ea67f82 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Controller.Session_UpdateModel.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Controller.Session_UpdateModel.cs @@ -95,7 +95,7 @@ private static SignatureHelpItem GetBestItem( // If we don't have an item that can take that number of parameters, then just pick // the last item. Or stick with the current item if the last item isn't any better. var lastItem = filteredItems.Last(); - if (currentItem.IsVariadic || currentItem.Parameters.Count == lastItem.Parameters.Count) + if (currentItem.IsVariadic || currentItem.Parameters.Length == lastItem.Parameters.Length) { return currentItem; } @@ -117,7 +117,7 @@ private static bool IsApplicable(SignatureHelpItem item, int argumentCount, stri // parameter index. i.e. if it has 2 parameters and we're at index 0 or 1 then it's // applicable. However, if it has 2 parameters and we're at index 2, then it's not // applicable. - if (item.Parameters.Count >= argumentCount) + if (item.Parameters.Length >= argumentCount) { return true; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Parameter.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Parameter.cs index 9eff8b3c08a0f..cfea61d116876 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Parameter.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Parameter.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Threading; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; @@ -8,11 +9,17 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHel { internal class Parameter : IParameter { - public string Documentation { get; internal set; } - public string Name { get; internal set; } - public Span Locus { get; internal set; } - public Span PrettyPrintedLocus { get; internal set; } - public ISignature Signature { get; internal set; } + private readonly SignatureHelpParameter _parameter; + private string _documentation; + private readonly int _contentLength; + private readonly int _index; + private readonly int _prettyPrintedIndex; + + public string Documentation => _documentation ?? (_documentation = _parameter.DocumentationFactory(CancellationToken.None).GetFullText()); + public string Name => _parameter.Name; + public Span Locus => new Span(_index, _contentLength); + public Span PrettyPrintedLocus => new Span(_prettyPrintedIndex, _contentLength); + public ISignature Signature { get; } public Parameter( Signature signature, @@ -21,12 +28,11 @@ public Parameter( int index, int prettyPrintedIndex) { + _parameter = parameter; this.Signature = signature; - this.Name = parameter.Name; - this.Documentation = parameter.Documentation.GetFullText(); - - this.Locus = new Span(index, content.Length); - this.PrettyPrintedLocus = new Span(prettyPrintedIndex, content.Length); + _contentLength = content.Length; + _index = index; + _prettyPrintedIndex = prettyPrintedIndex; } } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Signature.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Signature.cs index 1b972480d6891..cf9449dbd44ec 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Signature.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/Signature.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; @@ -8,6 +9,7 @@ using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Roslyn.Utilities; +using System.Threading; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp.Presentation { @@ -16,26 +18,91 @@ internal class Signature : ISignature private const int MaxParamColumnCount = 100; private readonly SignatureHelpItem _signatureHelpItem; - private IParameter _currentParameter; - internal IList DisplayParts { get; private set; } - private IList _prettyPrintedDisplayParts; - - public ITrackingSpan ApplicableToSpan { get; internal set; } - public string Content { get; private set; } - public string PrettyPrintedContent { get; private set; } - public ReadOnlyCollection Parameters { get; private set; } - public string Documentation { get; private set; } - - public event EventHandler CurrentParameterChanged; - public Signature(ITrackingSpan applicableToSpan, SignatureHelpItem signatureHelpItem) + public Signature(ITrackingSpan applicableToSpan, SignatureHelpItem signatureHelpItem, int selectedParameterIndex) { + if (selectedParameterIndex < -1 || selectedParameterIndex >= signatureHelpItem.Parameters.Length) + { + throw new ArgumentOutOfRangeException(nameof(selectedParameterIndex)); + } + this.ApplicableToSpan = applicableToSpan; _signatureHelpItem = signatureHelpItem; - this.Initialize(setParameters: true); + _parameterIndex = selectedParameterIndex; + } + + private bool _isInitialized; + private void EnsureInitialized() + { + if (!_isInitialized) + { + _isInitialized = true; + Initialize(); + } + } + + private Signature InitializedThis + { + get + { + EnsureInitialized(); + return this; + } + } + + private IList _displayParts; + internal IList DisplayParts => InitializedThis._displayParts; + + public ITrackingSpan ApplicableToSpan { get; } + + private string _content; + public string Content => InitializedThis._content; + + private int _parameterIndex = -1; + public IParameter CurrentParameter + { + get + { + EnsureInitialized(); + return _parameterIndex >= 0 && _parameters != null ? _parameters[_parameterIndex] : null; + } } - private void Initialize(bool setParameters) + public string Documentation => null; + + private ReadOnlyCollection _parameters; + public ReadOnlyCollection Parameters => InitializedThis._parameters; + + private string _prettyPrintedContent; + public string PrettyPrintedContent => InitializedThis._prettyPrintedContent; + + // This event is required by the ISignature interface but it's not actually used + // (once created the CurrentParameter property cannot change) + public event EventHandler CurrentParameterChanged + { + add + { + } + remove + { + } + } + + private IList _prettyPrintedDisplayParts; + internal IList PrettyPrintedDisplayParts + { + get + { + return InitializedThis._prettyPrintedDisplayParts; + } + + set + { + _prettyPrintedDisplayParts = value; + } + } + + private void Initialize() { var content = new StringBuilder(); var prettyPrintedContent = new StringBuilder(); @@ -61,7 +128,7 @@ private void Initialize(bool setParameters) var paramColumnCount = 0; - for (int i = 0; i < _signatureHelpItem.Parameters.Count; i++) + for (int i = 0; i < _signatureHelpItem.Parameters.Length; i++) { var sigHelpParameter = _signatureHelpItem.Parameters[i]; @@ -107,9 +174,9 @@ private void Initialize(bool setParameters) AddRange(_signatureHelpItem.SuffixDisplayParts, parts, prettyPrintedParts); Append(_signatureHelpItem.SuffixDisplayParts.GetFullText(), content, prettyPrintedContent); - if (_currentParameter != null) + if (_parameterIndex >= 0) { - var sigHelpParameter = _signatureHelpItem.Parameters[this.Parameters.IndexOf(_currentParameter)]; + var sigHelpParameter = _signatureHelpItem.Parameters[_parameterIndex]; AddRange(sigHelpParameter.SelectedDisplayParts, parts, prettyPrintedParts); Append(sigHelpParameter.SelectedDisplayParts.GetFullText(), content, prettyPrintedContent); @@ -118,24 +185,21 @@ private void Initialize(bool setParameters) AddRange(_signatureHelpItem.DescriptionParts, parts, prettyPrintedParts); Append(_signatureHelpItem.DescriptionParts.GetFullText(), content, prettyPrintedContent); - if (_signatureHelpItem.Documentation.Count > 0) + var documentation = _signatureHelpItem.DocumenationFactory(CancellationToken.None).ToList(); + if (documentation.Count > 0) { AddRange(new[] { newLinePart }, parts, prettyPrintedParts); Append(newLineContent, content, prettyPrintedContent); - AddRange(_signatureHelpItem.Documentation, parts, prettyPrintedParts); - Append(_signatureHelpItem.Documentation.GetFullText(), content, prettyPrintedContent); + AddRange(documentation, parts, prettyPrintedParts); + Append(documentation.GetFullText(), content, prettyPrintedContent); } - this.Content = content.ToString(); - this.PrettyPrintedContent = prettyPrintedContent.ToString(); - this.DisplayParts = parts.ToImmutableArrayOrEmpty(); - this.PrettyPrintedDisplayParts = prettyPrintedParts.ToImmutableArrayOrEmpty(); - - if (setParameters) - { - this.Parameters = parameters.ToReadOnlyCollection(); - } + _content = content.ToString(); + _prettyPrintedContent = prettyPrintedContent.ToString(); + _displayParts = parts.ToImmutableArrayOrEmpty(); + _prettyPrintedDisplayParts = prettyPrintedParts.ToImmutableArrayOrEmpty(); + _parameters = parameters.ToReadOnlyCollection(); } private void AddRange(IList values, List parts, List prettyPrintedParts) @@ -163,45 +227,5 @@ private IList AddOptionalBrackets(bool isOptional, IList PrettyPrintedDisplayParts - { - get - { - return _prettyPrintedDisplayParts; - } - - set - { - _prettyPrintedDisplayParts = value; - } - } } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs index 61ae79f84b042..9075ebf25ad1f 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs @@ -116,45 +116,30 @@ private void CreateSignatures( foreach (var item in _signatureHelpItems) { - _signatureMap = _signatureMap.Add(item, new Signature(triggerSpan, item)); - } - - this.SetCurrentParameterForAllItems(selectedParameter); - } - - private void SetCurrentParameterForAllItems(int? selectedParameter) - { - foreach (var item in _signatureHelpItems) - { - this.SetCurrentParameter(item, selectedParameter); + _signatureMap = _signatureMap.Add(item, new Signature(triggerSpan, item, GetParameterIndexForItem(item, selectedParameter))); } } - private void SetCurrentParameter(SignatureHelpItem item, int? selectedParameter) + private static int GetParameterIndexForItem(SignatureHelpItem item, int? selectedParameter) { - Contract.ThrowIfFalse(_signatureMap.ContainsKey(item)); - var signature = _signatureMap.GetValueOrDefault(item); - if (selectedParameter.HasValue) { - if (selectedParameter.Value < item.Parameters.Count) + if (selectedParameter.Value < item.Parameters.Length) { // If the selected parameter is within the range of parameters of this item then set // that as the current parameter. - signature.CurrentParameter = signature.Parameters[selectedParameter.Value]; - return; + return selectedParameter.Value; } else if (item.IsVariadic) { - // It wasn't in range, but the item takes an unlmiited number of parameters. So + // It wasn't in range, but the item takes an unlimited number of parameters. So // just set current parameter to the last parameter (the variadic one). - signature.CurrentParameter = signature.Parameters.Last(); - return; + return item.Parameters.Length - 1; } } // It was out of bounds, there is no current parameter now. - signature.CurrentParameter = null; + return -1; } private void OnEditorSessionDismissed() diff --git a/src/EditorFeatures/Test/SignatureHelp/AbstractSignatureHelpProviderTests.cs b/src/EditorFeatures/Test/SignatureHelp/AbstractSignatureHelpProviderTests.cs index d9d45a4bbbaac..3a12a1e16edbd 100644 --- a/src/EditorFeatures/Test/SignatureHelp/AbstractSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/Test/SignatureHelp/AbstractSignatureHelpProviderTests.cs @@ -200,15 +200,17 @@ private void CompareSigHelpItemsAndCurrentPosition( int cursorPosition, TextSpan applicableSpan) { - var signature = new Signature(applicableToSpan: null, signatureHelpItem: actualSignatureHelpItem); + int currentParameterIndex = -1; if (expectedTestItem.CurrentParameterIndex != null) { - if (expectedTestItem.CurrentParameterIndex.Value >= 0 && expectedTestItem.CurrentParameterIndex.Value < signature.Parameters.Count) + if (expectedTestItem.CurrentParameterIndex.Value >= 0 && expectedTestItem.CurrentParameterIndex.Value < actualSignatureHelpItem.Parameters.Length) { - signature.CurrentParameter = signature.Parameters[expectedTestItem.CurrentParameterIndex.Value]; + currentParameterIndex = expectedTestItem.CurrentParameterIndex.Value; } } + var signature = new Signature(applicableToSpan: null, signatureHelpItem: actualSignatureHelpItem, selectedParameterIndex: currentParameterIndex); + // We're a match if the signature matches... // We're now combining the signature and documentation to make classification work. if (!string.IsNullOrEmpty(expectedTestItem.MethodDocumentation)) @@ -227,7 +229,7 @@ private void CompareSigHelpItemsAndCurrentPosition( if (expectedTestItem.MethodDocumentation != null) { - Assert.Equal(expectedTestItem.MethodDocumentation, actualSignatureHelpItem.Documentation.GetFullText()); + Assert.Equal(expectedTestItem.MethodDocumentation, actualSignatureHelpItem.DocumenationFactory(CancellationToken.None).GetFullText()); } if (expectedTestItem.ParameterDocumentation != null) diff --git a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb index 280092bea9d0f..ce11b37867062 100644 --- a/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb @@ -205,7 +205,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense End Function Private Shared Function CreateItems(count As Integer) As IList(Of SignatureHelpItem) - Return Enumerable.Range(0, count).Select(Function(i) New SignatureHelpItem(isVariadic:=False, documentation:={}, prefixParts:={}, separatorParts:={}, suffixParts:={}, parameters:={}, descriptionParts:={})).ToList() + Return Enumerable.Range(0, count).Select(Function(i) New SignatureHelpItem(isVariadic:=False, documentationFactory:=Nothing, prefixParts:={}, separatorParts:={}, suffixParts:={}, parameters:={}, descriptionParts:={})).ToList() End Function Friend Class MockSignatureHelpProvider diff --git a/src/EditorFeatures/Test2/IntelliSense/TestState.vb b/src/EditorFeatures/Test2/IntelliSense/TestState.vb index ae8e432aed388..d01e740ad65e2 100644 --- a/src/EditorFeatures/Test2/IntelliSense/TestState.vb +++ b/src/EditorFeatures/Test2/IntelliSense/TestState.vb @@ -2,6 +2,7 @@ Imports System.ComponentModel.Composition.Hosting Imports System.ComponentModel.Composition.Primitives +Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers @@ -388,7 +389,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense End If If documentation IsNot Nothing Then - Assert.Equal(documentation, Me.CurrentSignatureHelpPresenterSession.SelectedItem.Documentation.GetFullText()) + Assert.Equal(documentation, Me.CurrentSignatureHelpPresenterSession.SelectedItem.DocumenationFactory(CancellationToken.None).GetFullText()) End If If selectedParameter IsNot Nothing Then diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb index ebdb39e8bbebf..2bdb51c2400aa 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb @@ -55,11 +55,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Dim parameters As New List(Of SignatureHelpParameter) For i = 0 To documentation.ParameterCount - 1 + Dim capturedIndex = i parameters.Add( New SignatureHelpParameter( name:=documentation.GetParameterName(i), isOptional:=False, - documentation:=documentation.GetParameterDocumentation(i).ToSymbolDisplayParts(), + documentationFactory:=Function(c As CancellationToken) documentation.GetParameterDocumentation(capturedIndex).ToSymbolDisplayParts(), displayParts:=documentation.GetParameterDisplayParts(i))) Next @@ -72,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Nothing, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic:=False, - documentation:=SpecializedCollections.SingletonEnumerable(New SymbolDisplayPart(SymbolDisplayPartKind.Text, Nothing, documentation.DocumentationText)), + documentationFactory:=Function(c As CancellationToken) SpecializedCollections.SingletonEnumerable(New SymbolDisplayPart(SymbolDisplayPartKind.Text, Nothing, documentation.DocumentationText)), prefixParts:=documentation.PrefixParts, separatorParts:=GetSeparatorParts(), suffixParts:=suffixParts, diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractSignatureHelpProvider.vb index 77f827b568c05..716f295389282 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/AbstractSignatureHelpProvider.vb @@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Return New SignatureHelpParameter( parameter.Name, parameter.IsOptional, - parameter.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + parameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), parameter.ToMinimalDisplayParts(semanticModel, position)) End Function diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/AttributeSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/AttributeSignatureHelpProvider.vb index 5507b8e536da6..3527d1df27835 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/AttributeSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/AttributeSignatureHelpProvider.vb @@ -113,7 +113,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp constructor, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic, - constructor.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + constructor.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(constructor, semanticModel, position), GetSeparatorParts(), GetPostambleParts(constructor), @@ -151,7 +151,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp result.Add(New SignatureHelpParameter( namedParameter.Name, isOptional:=True, - documentation:=namedParameter.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + documentationFactory:=namedParameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), displayParts:=displayParts, prefixDisplayParts:=GetParameterPrefixDisplayParts(i))) Next diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb index 88b0bf548d565..4c49db67d08c0 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb @@ -96,7 +96,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp method, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, False, - method.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + method.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(method, semanticModel, position), GetSeparatorParts(), GetPostambleParts(method, semanticModel, position), @@ -154,7 +154,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Dim sigHelpParameter = New SignatureHelpParameter( "", parameter.IsOptional, - parameter.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + parameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), parts) Return SpecializedCollections.SingletonEnumerable(sigHelpParameter) diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/GenericNameSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/GenericNameSignatureHelpProvider.vb index 226d5bb7c9900..3559e72ca345f 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/GenericNameSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/GenericNameSignatureHelpProvider.vb @@ -117,7 +117,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp symbol, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, False, - symbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + symbol.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(namedType, semanticModel, position), GetSeparatorParts(), GetPostambleParts(namedType), namedType.TypeParameters.[Select](Function(p) Convert(p, semanticModel, position, documentationCommentFormattingService, cancellationToken))) Else Dim method = DirectCast(symbol, IMethodSymbol) @@ -125,7 +125,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp symbol, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, False, - symbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + symbol.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(method, semanticModel, position), GetSeparatorParts(), GetPostambleParts(method, semanticModel, position), method.TypeParameters.[Select](Function(p) Convert(p, semanticModel, position, documentationCommentFormattingService, cancellationToken))) End If @@ -142,7 +142,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Return New SignatureHelpParameter( parameter.Name, isOptional:=False, - documentation:=parameter.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + documentationFactory:=parameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), displayParts:=parts) End Function diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb index 3ec7e17b0b4f2..1ee1b1c20891e 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.DelegateInvoke.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp invokeMethod, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic:=invokeMethod.IsParams(), - documentation:=SpecializedCollections.EmptyEnumerable(Of SymbolDisplayPart)(), + documentationFactory:=Nothing, prefixParts:=GetDelegateInvokePreambleParts(invokeMethod, semanticModel, position), separatorParts:=GetSeparatorParts(), suffixParts:=GetDelegateInvokePostambleParts(invokeMethod, semanticModel, position), @@ -52,10 +52,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Private Function GetDelegateInvokeParameters(invokeMethod As IMethodSymbol, semanticModel As SemanticModel, position As Integer, documentationCommentoFormattingService As IDocumentationCommentFormattingService, cancellationToken As CancellationToken) As IEnumerable(Of SignatureHelpParameter) Dim parameters = New List(Of SignatureHelpParameter) For Each parameter In invokeMethod.Parameters + cancellationToken.ThrowIfCancellationRequested() parameters.Add(New SignatureHelpParameter( parameter.Name, isOptional:=False, - documentation:=parameter.GetDocumentationParts(semanticModel, position, documentationCommentoFormattingService, cancellationToken), + documentationFactory:=parameter.GetDocumentationPartsFactory(semanticModel, position, documentationCommentoFormattingService), displayParts:=parameter.ToMinimalDisplayParts(semanticModel, position))) Next diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb index 27e7c09ed1c0d..f2faa828aab82 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.ElementAccess.vb @@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp indexer, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, indexer.IsParams(), - indexer.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + indexer.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetIndexerPreambleParts(indexer, semanticModel, position), GetSeparatorParts(), GetIndexerPostambleParts(indexer, semanticModel, position), diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.MemberGroup.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.MemberGroup.vb index e060f045e599f..c944a98d8fd81 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.MemberGroup.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/InvocationExpressionSignatureHelpProvider.MemberGroup.vb @@ -55,7 +55,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp member, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, member.IsParams(), - member.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken).Concat(GetAwaitableDescription(member, semanticModel, position)), + Function(c) member.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, c).Concat(GetAwaitableDescription(member, semanticModel, position)), GetMemberGroupPreambleParts(member, semanticModel, position), GetSeparatorParts(), GetMemberGroupPostambleParts(member, semanticModel, position), diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb index 062fc1a5e1605..795cc9fe6f227 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.DelegateType.vb @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp invokeMethod, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, isVariadic:=False, - documentation:=invokeMethod.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + documentationFactory:=invokeMethod.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), prefixParts:=GetDelegateTypePreambleParts(invokeMethod, semanticModel, position), separatorParts:=GetSeparatorParts(), suffixParts:=GetDelegateTypePostambleParts(invokeMethod), parameters:=GetDelegateTypeParameters(invokeMethod, semanticModel, position, cancellationToken)) Return SpecializedCollections.SingletonEnumerable(item) End Function @@ -77,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp Return {New SignatureHelpParameter( TargetName, isOptional:=False, - documentation:=String.Empty.ToSymbolDisplayParts(), + documentationFactory:=Nothing, displayParts:=parts)} End Function diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb index 9888ac3950a63..181d5714fb061 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.NormalType.vb @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp constructor, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, constructor.IsParams(), - constructor.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + constructor.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetNormalTypePreambleParts(constructor, semanticModel, position), GetSeparatorParts(), GetNormalTypePostambleParts(constructor), constructor.Parameters.[Select](Function(p) Convert(p, semanticModel, position, documentationCommentFormattingService, cancellationToken))) Return item End Function diff --git a/src/EditorFeatures/VisualBasic/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb b/src/EditorFeatures/VisualBasic/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb index 9b570a6cc52ee..6b388c61ed86c 100644 --- a/src/EditorFeatures/VisualBasic/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb +++ b/src/EditorFeatures/VisualBasic/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb @@ -109,7 +109,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.SignatureHelp eventSymbol, semanticModel, position, symbolDisplayService, anonymousTypeDisplayService, False, - eventSymbol.GetDocumentationParts(semanticModel, position, documentationCommentFormattingService, cancellationToken), + eventSymbol.GetDocumentationPartsFactory(semanticModel, position, documentationCommentFormattingService), GetPreambleParts(eventSymbol, semanticModel, position), GetSeparatorParts(), GetPostambleParts(eventSymbol, semanticModel, position), diff --git a/src/Features/CSharp/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs b/src/Features/CSharp/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs index 8dcef4a52702f..e178913746268 100644 --- a/src/Features/CSharp/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs +++ b/src/Features/CSharp/Completion/CompletionProviders/EnumAndCompletionListTagCompletionProvider.cs @@ -121,7 +121,14 @@ protected override async Task> GetItemsWorkerAsync( private INamedTypeSymbol GetCompletionListType(ITypeSymbol type, INamedTypeSymbol within, Compilation compilation) { - var documentation = type.GetDocumentationComment(); + // PERF: Avoid parsing XML unless the text contains the word "completionlist". + string xmlText = type.GetDocumentationCommentXml(); + if (xmlText == null || !xmlText.Contains(DocumentationCommentXmlNames.CompletionListElementName)) + { + return null; + } + + var documentation = Shared.Utilities.DocumentationComment.FromXmlFragment(xmlText); var completionListType = documentation.CompletionListCref != null ? DocumentationCommentId.GetSymbolsForDeclarationId(documentation.CompletionListCref, compilation).OfType().FirstOrDefault() diff --git a/src/Features/Core/Shared/Extensions/ISymbolExtensions_2.cs b/src/Features/Core/Shared/Extensions/ISymbolExtensions_2.cs index d2cc1580d7714..678148acfdfc8 100644 --- a/src/Features/Core/Shared/Extensions/ISymbolExtensions_2.cs +++ b/src/Features/Core/Shared/Extensions/ISymbolExtensions_2.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.DocumentationCommentFormatting; -using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions @@ -170,8 +169,6 @@ public static Glyph GetGlyph(this ISymbol symbol) public static IEnumerable GetDocumentationParts(this ISymbol symbol, SemanticModel semanticModel, int position, IDocumentationCommentFormattingService formatter, CancellationToken cancellationToken) { - var globalNamespace = semanticModel.Compilation.GlobalNamespace; - var documentation = symbol.TypeSwitch( (IParameterSymbol parameter) => parameter.ContainingSymbol.OriginalDefinition.GetDocumentationComment(cancellationToken: cancellationToken).GetParameterText(symbol.Name), (ITypeParameterSymbol typeParam) => typeParam.ContainingSymbol.GetDocumentationComment(cancellationToken: cancellationToken).GetTypeParameterText(symbol.Name), @@ -179,12 +176,14 @@ public static IEnumerable GetDocumentationParts(this ISymbol (IAliasSymbol alias) => alias.Target.GetDocumentationComment(cancellationToken: cancellationToken).SummaryText, _ => symbol.GetDocumentationComment(cancellationToken: cancellationToken).SummaryText); - if (documentation != null) - { - return formatter.Format(documentation, semanticModel, position, CrefFormat); - } + return documentation != null + ? formatter.Format(documentation, semanticModel, position, CrefFormat) + : SpecializedCollections.EmptyEnumerable(); + } - return SpecializedCollections.EmptyList(); + public static Func> GetDocumentationPartsFactory(this ISymbol symbol, SemanticModel semanticModel, int position, IDocumentationCommentFormattingService formatter) + { + return c => symbol.GetDocumentationParts(semanticModel, position, formatter, cancellationToken: c); } public static readonly SymbolDisplayFormat CrefFormat = diff --git a/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb b/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb index 68fb4fe68dbec..fe48db7183b50 100644 --- a/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb +++ b/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb @@ -1,6 +1,7 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. Imports System.ComponentModel.Composition.Hosting +Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers @@ -8,7 +9,7 @@ Imports Microsoft.CodeAnalysis.Completion.Rules Imports Microsoft.CodeAnalysis.Editor Imports Microsoft.CodeAnalysis.Editor.CommandHandlers Imports Microsoft.CodeAnalysis.Editor.Commands -Imports Microsoft.CodeAnalysis.Editor.Implementation.Intellisense.Completion +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests Imports Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Imports Microsoft.CodeAnalysis.Host.Mef @@ -365,7 +366,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.DebuggerIntelliSense End If If documentation IsNot Nothing Then - Assert.Equal(documentation, Me.CurrentSignatureHelpPresenterSession.SelectedItem.Documentation.GetFullText()) + Assert.Equal(documentation, Me.CurrentSignatureHelpPresenterSession.SelectedItem.DocumenationFactory(CancellationToken.None).GetFullText()) End If If selectedParameter IsNot Nothing Then diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs b/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs index 1258a506c4370..1c33bf3eb3c60 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/DocumentationComment.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Threading; using System.Xml; using XmlNames = Roslyn.Utilities.DocumentationCommentXmlNames; @@ -71,6 +72,11 @@ private DocumentationComment() ExceptionTypes = ImmutableArray.Empty; } + /// + /// Cache of the most recently parsed fragment and the resulting DocumentationComment + /// + private static volatile DocumentationComment s_cacheLastXmlFragmentParse; + /// /// Parses and constructs a from the given fragment of XML. /// @@ -78,7 +84,15 @@ private DocumentationComment() /// A DocumentationComment instance. public static DocumentationComment FromXmlFragment(string xml) { - return CommentBuilder.Parse(xml); + var result = s_cacheLastXmlFragmentParse; + if (result == null || result.FullXmlFragment != xml) + { + // Cache miss + result = CommentBuilder.Parse(xml); + s_cacheLastXmlFragmentParse = result; + } + + return result; } ///