From 1dd5d8c1863d4f5f1c086b11a569b38f5d3a10a0 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Tue, 2 Jun 2015 12:33:56 -0700 Subject: [PATCH] Avoid re-calculating base types Conflicts: src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb --- .../SymbolCompletionProviderTests.vb | 126 ++++++++++++++++ .../AbstractRecommendationService.cs | 142 +++++++++++------- 2 files changed, 215 insertions(+), 53 deletions(-) diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb index 325ac1e416b..c4690e8dfec 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb @@ -5871,5 +5871,131 @@ End Module VerifyNoItemsExist(text) End Sub + + Public Sub InstanceMembersFromBaseOuterType() + Dim text = +.Value + VerifyItemExists(text, "_field") + End Sub + + + Public Sub InstanceMembersFromBaseOuterType2() + Dim text = +.Value + VerifyItemExists(text, "M") + End Sub + + + Public Sub InstanceMembersFromBaseOuterType3() + Dim text = +.Value + VerifyItemIsAbsent(text, "M") + End Sub + + + Public Sub InstanceMembersFromBaseOuterType4() + Dim text = +.Value + VerifyItemExists(text, "M") + End Sub + + + Public Sub InstanceMembersFromBaseOuterType5() + Dim text = +.Value + VerifyItemIsAbsent(text, "Q") + End Sub + + + Public Sub InstanceMembersFromBaseOuterType6() + Dim text = +.Value + VerifyItemIsAbsent(text, "X") + End Sub + End Class End Namespace \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationService.cs b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationService.cs index 508bb1d7604..9caa4cecdb1 100644 --- a/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationService.cs +++ b/src/Workspaces/Core/Portable/Recommendations/AbstractRecommendationService.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Recommendations { @@ -21,82 +22,117 @@ internal abstract class AbstractRecommendationService : IRecommendationService var result = GetRecommendedSymbolsAtPositionWorker(workspace, semanticModel, position, options, cancellationToken); var symbols = result.Item1; - var context = result.Item2; + var context = new ShouldIncludeSymbolContext(result.Item2, cancellationToken); - symbols = symbols.Where(s => ShouldIncludeSymbol(s, context, cancellationToken)); + symbols = symbols.Where(context.ShouldIncludeSymbol); return symbols; } - private bool ShouldIncludeSymbol(ISymbol symbol, AbstractSyntaxContext context, CancellationToken cancellationToken) + private sealed class ShouldIncludeSymbolContext { - var isMember = false; - switch (symbol.Kind) + private readonly AbstractSyntaxContext _context; + private readonly CancellationToken _cancellationToken; + private IEnumerable _lazyOuterTypesAndBases; + private IEnumerable _lazyEnclosingTypeBases; + + internal ShouldIncludeSymbolContext(AbstractSyntaxContext context, CancellationToken cancellationToken) { - case SymbolKind.NamedType: - var namedType = (INamedTypeSymbol)symbol; - if (namedType.SpecialType == SpecialType.System_Void) - { - return false; - } + _context = context; + _cancellationToken = cancellationToken; + } - break; + internal bool ShouldIncludeSymbol(ISymbol symbol) + { + var isMember = false; + switch (symbol.Kind) + { + case SymbolKind.NamedType: + var namedType = (INamedTypeSymbol)symbol; + if (namedType.SpecialType == SpecialType.System_Void) + { + return false; + } + + break; + + case SymbolKind.Method: + switch (((IMethodSymbol)symbol).MethodKind) + { + case MethodKind.EventAdd: + case MethodKind.EventRemove: + case MethodKind.EventRaise: + case MethodKind.PropertyGet: + case MethodKind.PropertySet: + return false; + } + + isMember = true; + break; + + case SymbolKind.Event: + case SymbolKind.Field: + case SymbolKind.Property: + isMember = true; + break; + + case SymbolKind.TypeParameter: + return ((ITypeParameterSymbol)symbol).TypeParameterKind != TypeParameterKind.Cref; + } + + if (_context.IsAttributeNameContext) + { + var enclosingSymbol = _context.SemanticModel.GetEnclosingNamedType(_context.LeftToken.SpanStart, _cancellationToken); + return symbol.IsOrContainsAccessibleAttribute(enclosingSymbol, _context.SemanticModel.Compilation.Assembly); + } + + if (_context.IsEnumTypeMemberAccessContext) + { + return symbol.Kind == SymbolKind.Field; + } - case SymbolKind.Method: - var methodSymbol = (IMethodSymbol)symbol; - if (methodSymbol.MethodKind == MethodKind.EventAdd || - methodSymbol.MethodKind == MethodKind.EventRemove || - methodSymbol.MethodKind == MethodKind.EventRaise || - methodSymbol.MethodKind == MethodKind.PropertyGet || - methodSymbol.MethodKind == MethodKind.PropertySet) + // In an expression or statement context, we don't want to display instance members declared in outer containing types. + if ((_context.IsStatementContext || _context.IsAnyExpressionContext) && + !symbol.IsStatic && + isMember) + { + var containingTypeOriginalDefinition = symbol.ContainingType.OriginalDefinition; + if (this.GetOuterTypesAndBases().Contains(containingTypeOriginalDefinition)) { - return false; + return this.GetEnclosingTypeBases().Contains(containingTypeOriginalDefinition); } + } - isMember = true; - break; - - case SymbolKind.Event: - case SymbolKind.Field: - case SymbolKind.Property: - isMember = true; - break; + var namespaceSymbol = symbol as INamespaceSymbol; + if (namespaceSymbol != null) + { + return namespaceSymbol.ContainsAccessibleTypesOrNamespaces(_context.SemanticModel.Compilation.Assembly); + } - case SymbolKind.TypeParameter: - return ((ITypeParameterSymbol)symbol).TypeParameterKind != TypeParameterKind.Cref; + return true; } - if (context.IsAttributeNameContext) + private IEnumerable GetOuterTypesAndBases() { - var enclosingSymbol = context.SemanticModel.GetEnclosingNamedType(context.LeftToken.SpanStart, cancellationToken); - return symbol.IsOrContainsAccessibleAttribute(enclosingSymbol, context.SemanticModel.Compilation.Assembly); - } + if (_lazyOuterTypesAndBases == null) + { + _lazyOuterTypesAndBases = _context.GetOuterTypes(_cancellationToken).SelectMany(o => o.GetBaseTypesAndThis()).Select(t => t.OriginalDefinition); + } - if (context.IsEnumTypeMemberAccessContext) - { - return symbol.Kind == SymbolKind.Field; + return _lazyOuterTypesAndBases; } - // In an expression or statement context, we don't want to display instance members declared in outer containing types. - if ((context.IsStatementContext || context.IsAnyExpressionContext) && - !symbol.IsStatic && - isMember) + private IEnumerable GetEnclosingTypeBases() { - var outerTypesAndBases = context.GetOuterTypes(cancellationToken).SelectMany(o => o.GetBaseTypesAndThis()).Select(t => t.OriginalDefinition); - var containingTypeOriginalDefinition = symbol.ContainingType.OriginalDefinition; - if (outerTypesAndBases.Contains(containingTypeOriginalDefinition)) + if (_lazyEnclosingTypeBases == null) { - var enclosingType = context.SemanticModel.GetEnclosingNamedType(context.LeftToken.SpanStart, cancellationToken); - return enclosingType != null && enclosingType.GetBaseTypes().Select(b => b.OriginalDefinition).Contains(containingTypeOriginalDefinition); + var enclosingType = _context.SemanticModel.GetEnclosingNamedType(_context.LeftToken.SpanStart, _cancellationToken); + _lazyEnclosingTypeBases = (enclosingType == null) ? + SpecializedCollections.EmptyEnumerable() : + enclosingType.GetBaseTypes().Select(b => b.OriginalDefinition); } - } - var namespaceSymbol = symbol as INamespaceSymbol; - if (namespaceSymbol != null) - { - return namespaceSymbol.ContainsAccessibleTypesOrNamespaces(context.SemanticModel.Compilation.Assembly); + return _lazyEnclosingTypeBases; } - - return true; } } } -- GitLab