PageRenderTime 52ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Features/CSharp/Completion/CompletionProviders/CrefCompletionProvider.cs

https://gitlab.com/sharadag/TestProject2
C# | 238 lines | 192 code | 39 blank | 7 comment | 34 complexity | 6df83e00ae121e8af35471039207b154 MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Microsoft.CodeAnalysis.Completion;
  7. using Microsoft.CodeAnalysis.Completion.Providers;
  8. using Microsoft.CodeAnalysis.CSharp.Extensions;
  9. using Microsoft.CodeAnalysis.CSharp.Symbols;
  10. using Microsoft.CodeAnalysis.CSharp.Syntax;
  11. using Microsoft.CodeAnalysis.Options;
  12. using Microsoft.CodeAnalysis.Shared.Extensions;
  13. using Microsoft.CodeAnalysis.Text;
  14. using Roslyn.Utilities;
  15. namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
  16. {
  17. internal partial class CrefCompletionProvider : AbstractCompletionProvider
  18. {
  19. public static readonly SymbolDisplayFormat CrefFormat =
  20. new SymbolDisplayFormat(
  21. globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
  22. typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
  23. propertyStyle: SymbolDisplayPropertyStyle.NameOnly,
  24. genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
  25. parameterOptions:
  26. SymbolDisplayParameterOptions.IncludeType,
  27. miscellaneousOptions:
  28. SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
  29. SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
  30. public override bool IsCommitCharacter(CompletionItem completionItem, char ch, string textTypedSoFar)
  31. {
  32. if (ch == '{' && completionItem.DisplayText.Contains('{'))
  33. {
  34. return false;
  35. }
  36. if (ch == '(' && completionItem.DisplayText.Contains('('))
  37. {
  38. return false;
  39. }
  40. return CompletionUtilities.IsCommitCharacter(completionItem, ch, textTypedSoFar);
  41. }
  42. public override bool SendEnterThroughToEditor(CompletionItem completionItem, string textTypedSoFar)
  43. {
  44. return CompletionUtilities.SendEnterThroughToEditor(completionItem, textTypedSoFar);
  45. }
  46. public override bool IsTriggerCharacter(SourceText text, int characterPosition, OptionSet options)
  47. {
  48. return CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
  49. }
  50. protected override Task<bool> IsExclusiveAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
  51. {
  52. return SpecializedTasks.True;
  53. }
  54. protected override async Task<IEnumerable<CompletionItem>> GetItemsWorkerAsync(Document document, int position, CompletionTriggerInfo triggerInfo, System.Threading.CancellationToken cancellationToken)
  55. {
  56. var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
  57. if (!tree.IsEntirelyWithinCrefSyntax(position, cancellationToken))
  58. {
  59. return null;
  60. }
  61. var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);
  62. token = token.GetPreviousTokenIfTouchingWord(position);
  63. if (token.Kind() == SyntaxKind.None)
  64. {
  65. return null;
  66. }
  67. var result = SpecializedCollections.EmptyEnumerable<ISymbol>();
  68. // To get a Speculative SemanticModel (which is much faster), we need to
  69. // walk up to the node the DocumentationTrivia is attached to.
  70. var parentNode = token.GetAncestor<DocumentationCommentTriviaSyntax>().ParentTrivia.Token.Parent;
  71. var semanticModel = await document.GetSemanticModelForNodeAsync(parentNode, cancellationToken).ConfigureAwait(false);
  72. // cref ""|, ""|"", ""a|""
  73. if (token.IsKind(SyntaxKind.DoubleQuoteToken, SyntaxKind.SingleQuoteToken) && token.Parent.IsKind(SyntaxKind.XmlCrefAttribute))
  74. {
  75. result = semanticModel.LookupSymbols(token.SpanStart)
  76. .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);
  77. result = result.Concat(GetOperatorsAndIndexers(token, semanticModel, cancellationToken));
  78. }
  79. else if (IsSignatureContext(token))
  80. {
  81. result = semanticModel.LookupNamespacesAndTypes(token.SpanStart)
  82. .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);
  83. }
  84. else if (token.IsKind(SyntaxKind.DotToken) && token.Parent.IsKind(SyntaxKind.QualifiedCref))
  85. {
  86. // cref "a.|"
  87. var parent = token.Parent as QualifiedCrefSyntax;
  88. var leftType = semanticModel.GetTypeInfo(parent.Container, cancellationToken).Type;
  89. var leftSymbol = semanticModel.GetSymbolInfo(parent.Container, cancellationToken).Symbol;
  90. var container = leftSymbol ?? leftType;
  91. result = semanticModel.LookupSymbols(token.SpanStart, container: (INamespaceOrTypeSymbol)container)
  92. .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation);
  93. if (container is INamedTypeSymbol)
  94. {
  95. result = result.Concat(((INamedTypeSymbol)container).InstanceConstructors);
  96. }
  97. }
  98. return await CreateItemsAsync(document.Project.Solution.Workspace, semanticModel,
  99. position, result, token, cancellationToken).ConfigureAwait(false);
  100. }
  101. private bool IsSignatureContext(SyntaxToken token)
  102. {
  103. return token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken, SyntaxKind.RefKeyword, SyntaxKind.OutKeyword)
  104. && token.Parent.IsKind(SyntaxKind.CrefParameterList, SyntaxKind.CrefBracketedParameterList);
  105. }
  106. // LookupSymbols doesn't return indexers or operators because they can't be referred to by name, so we'll have to try to
  107. // find the innermost type declaration and return its operators and indexers
  108. private IEnumerable<ISymbol> GetOperatorsAndIndexers(SyntaxToken token, SemanticModel semanticModel, CancellationToken cancellationToken)
  109. {
  110. var typeDeclaration = token.GetAncestor<TypeDeclarationSyntax>();
  111. var result = new List<ISymbol>();
  112. if (typeDeclaration != null)
  113. {
  114. var type = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken);
  115. result.AddRange(type.GetMembers().OfType<IPropertySymbol>().Where(p => p.IsIndexer));
  116. result.AddRange(type.GetAccessibleMembersInThisAndBaseTypes<IMethodSymbol>(type)
  117. .Where(m => m.MethodKind == MethodKind.UserDefinedOperator));
  118. }
  119. return result;
  120. }
  121. private async Task<IEnumerable<CompletionItem>> CreateItemsAsync(
  122. Workspace workspace, SemanticModel semanticModel, int textChangeSpanPosition, IEnumerable<ISymbol> symbols, SyntaxToken token, CancellationToken cancellationToken)
  123. {
  124. var items = new List<CompletionItem>();
  125. foreach (var symbol in symbols)
  126. {
  127. var item = await CreateItemAsync(workspace, semanticModel, textChangeSpanPosition, symbol, token, cancellationToken).ConfigureAwait(false);
  128. items.Add(item);
  129. }
  130. return items;
  131. }
  132. private async Task<CompletionItem> CreateItemAsync(
  133. Workspace workspace, SemanticModel semanticModel, int textChangeSpanPosition, ISymbol symbol, SyntaxToken token, CancellationToken cancellationToken)
  134. {
  135. int tokenPosition = token.SpanStart;
  136. string symbolText = string.Empty;
  137. if (symbol is INamespaceOrTypeSymbol && token.IsKind(SyntaxKind.DotToken))
  138. {
  139. symbolText = symbol.Name.EscapeIdentifier();
  140. if (symbol.GetArity() > 0)
  141. {
  142. symbolText += "{";
  143. symbolText += string.Join(", ", ((INamedTypeSymbol)symbol).TypeParameters);
  144. symbolText += "}";
  145. }
  146. }
  147. else
  148. {
  149. symbolText = symbol.ToMinimalDisplayString(semanticModel, tokenPosition, CrefFormat);
  150. var parameters = symbol.GetParameters().Select(p =>
  151. {
  152. var displayName = p.Type.ToMinimalDisplayString(semanticModel, tokenPosition);
  153. if (p.RefKind == RefKind.Out)
  154. {
  155. return "out " + displayName;
  156. }
  157. if (p.RefKind == RefKind.Ref)
  158. {
  159. return "ref " + displayName;
  160. }
  161. return displayName;
  162. });
  163. var parameterList = !symbol.IsIndexer() ? string.Format("({0})", string.Join(", ", parameters))
  164. : string.Format("[{0}]", string.Join(", ", parameters));
  165. symbolText += parameterList;
  166. }
  167. var insertionText = symbolText
  168. .Replace('<', '{')
  169. .Replace('>', '}')
  170. .Replace("()", "");
  171. var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
  172. return new CrefCompletionItem(
  173. workspace,
  174. completionProvider: this,
  175. displayText: insertionText,
  176. insertionText: insertionText,
  177. textSpan: GetTextChangeSpan(text, textChangeSpanPosition),
  178. descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, tokenPosition, symbol),
  179. glyph: symbol.GetGlyph(),
  180. sortText: symbolText);
  181. }
  182. private TextSpan GetTextChangeSpan(SourceText text, int position)
  183. {
  184. return CommonCompletionUtilities.GetTextChangeSpan(
  185. text,
  186. position,
  187. (ch) => CompletionUtilities.IsTextChangeSpanStartCharacter(ch) || ch == '{',
  188. (ch) => CompletionUtilities.IsWordCharacter(ch) || ch == '{' || ch == '}');
  189. }
  190. private string CreateParameters(IEnumerable<ITypeSymbol> arguments, SemanticModel semanticModel, int position)
  191. {
  192. return string.Join(", ", arguments.Select(t => t.ToMinimalDisplayString(semanticModel, position)));
  193. }
  194. public override TextChange GetTextChange(CompletionItem selectedItem, char? ch = null, string textTypedSoFar = null)
  195. {
  196. return new TextChange(selectedItem.FilterSpan, ((CrefCompletionItem)selectedItem).InsertionText);
  197. }
  198. }
  199. }