PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs

https://gitlab.com/sharadag/Roslyn
C# | 218 lines | 179 code | 30 blank | 9 comment | 21 complexity | c6e10126b26573ab67d64c4007963d12 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.Editing;
  7. using Microsoft.CodeAnalysis.LanguageServices;
  8. using Microsoft.CodeAnalysis.Shared.Extensions;
  9. using Microsoft.CodeAnalysis.Text;
  10. using Roslyn.Utilities;
  11. namespace Microsoft.CodeAnalysis.Completion.Providers
  12. {
  13. internal abstract partial class AbstractOverrideCompletionProvider
  14. {
  15. private partial class ItemGetter
  16. {
  17. private readonly CancellationToken _cancellationToken;
  18. private readonly int _position;
  19. private readonly TextSpan _span;
  20. private readonly AbstractOverrideCompletionProvider _provider;
  21. private readonly SymbolDisplayFormat _overrideNameFormat = SymbolDisplayFormats.NameFormat.WithParameterOptions(
  22. SymbolDisplayParameterOptions.IncludeDefaultValue |
  23. SymbolDisplayParameterOptions.IncludeExtensionThis |
  24. SymbolDisplayParameterOptions.IncludeType |
  25. SymbolDisplayParameterOptions.IncludeName |
  26. SymbolDisplayParameterOptions.IncludeParamsRefOut);
  27. private readonly Document _document;
  28. private readonly SourceText _text;
  29. private readonly SyntaxTree _syntaxTree;
  30. private readonly int _startLineNumber;
  31. private readonly TextLine _startLine;
  32. private ItemGetter(
  33. AbstractOverrideCompletionProvider overrideCompletionProvider,
  34. Document document,
  35. int position,
  36. TextSpan span,
  37. SourceText text,
  38. SyntaxTree syntaxTree,
  39. int startLineNumber,
  40. TextLine startLine,
  41. CancellationToken cancellationToken)
  42. {
  43. _provider = overrideCompletionProvider;
  44. _document = document;
  45. _position = position;
  46. _span = span;
  47. _text = text;
  48. _syntaxTree = syntaxTree;
  49. _startLineNumber = startLineNumber;
  50. _startLine = startLine;
  51. _cancellationToken = cancellationToken;
  52. }
  53. internal static async Task<ItemGetter> CreateAsync(
  54. AbstractOverrideCompletionProvider overrideCompletionProvider,
  55. Document document,
  56. int position,
  57. TextSpan span,
  58. CancellationToken cancellationToken)
  59. {
  60. var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
  61. var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
  62. var startLineNumber = text.Lines.IndexOf(position);
  63. var startLine = text.Lines[startLineNumber];
  64. return new ItemGetter(overrideCompletionProvider, document, position, span, text, syntaxTree, startLineNumber, startLine, cancellationToken);
  65. }
  66. internal async Task<IEnumerable<CompletionItem>> GetItemsAsync()
  67. {
  68. // modifiers* override modifiers* type? |
  69. if (!TryCheckForTrailingTokens(_position))
  70. {
  71. return null;
  72. }
  73. var startToken = _provider.FindStartingToken(_syntaxTree, _position, _cancellationToken);
  74. if (startToken.Parent == null)
  75. {
  76. return null;
  77. }
  78. var semanticModel = await _document.GetSemanticModelForNodeAsync(startToken.Parent, _cancellationToken).ConfigureAwait(false);
  79. ITypeSymbol returnType;
  80. DeclarationModifiers modifiers;
  81. Accessibility seenAccessibility;
  82. SyntaxToken tokenAfterReturnType;
  83. ISet<ISymbol> overridableMembers;
  84. if (!_provider.TryDetermineReturnType(startToken, semanticModel, _cancellationToken, out returnType, out tokenAfterReturnType) ||
  85. !_provider.TryDetermineModifiers(tokenAfterReturnType, _text, _startLineNumber, out seenAccessibility, out modifiers) ||
  86. !TryDetermineOverridableMembers(semanticModel, startToken, seenAccessibility, out overridableMembers))
  87. {
  88. return null;
  89. }
  90. overridableMembers = _provider.FilterOverrides(overridableMembers, returnType);
  91. var symbolDisplayService = _document.GetLanguageService<ISymbolDisplayService>();
  92. return overridableMembers.Select(m => CreateItem(
  93. m, _span, symbolDisplayService, semanticModel, startToken, modifiers)).ToList();
  94. }
  95. private CompletionItem CreateItem(
  96. ISymbol symbol, TextSpan textChangeSpan, ISymbolDisplayService symbolDisplayService,
  97. SemanticModel semanticModel, SyntaxToken startToken, DeclarationModifiers modifiers)
  98. {
  99. var position = startToken.SpanStart;
  100. var displayString = symbolDisplayService.ToMinimalDisplayString(semanticModel, position, symbol, _overrideNameFormat);
  101. return MemberInsertionCompletionItem.Create(
  102. displayString,
  103. textChangeSpan,
  104. symbol.GetGlyph(),
  105. modifiers,
  106. _startLineNumber,
  107. symbol,
  108. startToken,
  109. position,
  110. rules: _provider.GetRules());
  111. }
  112. private bool TryDetermineOverridableMembers(
  113. SemanticModel semanticModel, SyntaxToken startToken, Accessibility seenAccessibility, out ISet<ISymbol> overridableMembers)
  114. {
  115. var result = new HashSet<ISymbol>();
  116. var containingType = semanticModel.GetEnclosingSymbol<INamedTypeSymbol>(startToken.SpanStart, _cancellationToken);
  117. if (containingType != null && !containingType.IsScriptClass && !containingType.IsImplicitClass)
  118. {
  119. if (containingType.TypeKind == TypeKind.Class || containingType.TypeKind == TypeKind.Struct)
  120. {
  121. var baseTypes = containingType.GetBaseTypes().Reverse();
  122. foreach (var type in baseTypes)
  123. {
  124. _cancellationToken.ThrowIfCancellationRequested();
  125. // Prefer overrides in derived classes
  126. RemoveOverriddenMembers(result, type);
  127. // Retain overridable methods
  128. AddOverridableMembers(result, containingType, type);
  129. }
  130. // Don't suggest already overridden members
  131. RemoveOverriddenMembers(result, containingType);
  132. }
  133. }
  134. // Filter based on accessibility
  135. if (seenAccessibility != Accessibility.NotApplicable)
  136. {
  137. result.RemoveWhere(m => m.DeclaredAccessibility != seenAccessibility);
  138. }
  139. overridableMembers = result;
  140. return overridableMembers.Count > 0;
  141. }
  142. private void AddOverridableMembers(HashSet<ISymbol> result, INamedTypeSymbol containingType, INamedTypeSymbol type)
  143. {
  144. foreach (var member in type.GetMembers())
  145. {
  146. _cancellationToken.ThrowIfCancellationRequested();
  147. if (_provider.IsOverridable(member, containingType))
  148. {
  149. result.Add(member);
  150. }
  151. }
  152. }
  153. private void RemoveOverriddenMembers(HashSet<ISymbol> result, INamedTypeSymbol containingType)
  154. {
  155. foreach (var member in containingType.GetMembers())
  156. {
  157. _cancellationToken.ThrowIfCancellationRequested();
  158. var overriddenMember = member.OverriddenMember();
  159. if (overriddenMember != null)
  160. {
  161. result.Remove(overriddenMember);
  162. }
  163. }
  164. }
  165. private bool TryCheckForTrailingTokens(int position)
  166. {
  167. var root = _syntaxTree.GetRoot(_cancellationToken);
  168. var token = root.FindToken(position);
  169. // Don't want to offer Override completion if there's a token after the current
  170. // position.
  171. if (token.SpanStart > position)
  172. {
  173. return false;
  174. }
  175. // If the next token is also on our line then we don't want to offer completion.
  176. if (IsOnStartLine(token.GetNextToken().SpanStart))
  177. {
  178. return false;
  179. }
  180. return true;
  181. }
  182. private bool IsOnStartLine(int position)
  183. {
  184. return _text.Lines.IndexOf(position) == _startLineNumber;
  185. }
  186. }
  187. }
  188. }