private static void GetItemsFromConflictingTypes( INamespaceSymbol containingNamespaceSymbol, ConflictNameNode conflictTypeNodes, ArrayBuilder <SerializableImportCompletionItem> builder, ITypeSymbol receiverTypeSymbol, SemanticModel semanticModel, int position, StatisticCounter counter) { Debug.Assert(!conflictTypeNodes.NamespaceAndMethodNames.HasValue); foreach (var child in conflictTypeNodes.Children.Values) { if (child.NamespaceAndMethodNames == null) { var childNamespace = containingNamespaceSymbol.GetMembers(child.Name).OfType <INamespaceSymbol>().FirstOrDefault(); if (childNamespace != null) { GetItemsFromConflictingTypes(childNamespace, child, builder, receiverTypeSymbol, semanticModel, position, counter); } } else { var types = containingNamespaceSymbol.GetMembers(child.Name).OfType <INamedTypeSymbol>(); foreach (var type in types) { var(namespaceName, methodNames) = child.NamespaceAndMethodNames.Value; GetItemsFromTypeContainsPotentialMatches(type, namespaceName, methodNames, receiverTypeSymbol, semanticModel, position, counter, builder); } } } }
private static ImmutableArray <SerializableImportCompletionItem> GetExtensionMethodItems( INamespaceSymbol rootNamespaceSymbol, ITypeSymbol receiverTypeSymbol, SemanticModel semanticModel, int position, ISet <string> namespaceFilter, MultiDictionary <string, string> methodNameFilter, StatisticCounter counter, CancellationToken cancellationToken) { var compilation = semanticModel.Compilation; using var _ = ArrayBuilder <SerializableImportCompletionItem> .GetInstance(out var builder); using var conflictTypeRootNode = new ConflictNameNode(name: string.Empty); foreach (var(fullyQualifiedContainerName, methodNames) in methodNameFilter) { cancellationToken.ThrowIfCancellationRequested(); var indexOfLastDot = fullyQualifiedContainerName.LastIndexOf('.'); var qualifiedNamespaceName = indexOfLastDot > 0 ? fullyQualifiedContainerName.Substring(0, indexOfLastDot) : string.Empty; if (namespaceFilter.Contains(qualifiedNamespaceName)) { continue; } // Container of extension method (static class in C# and Module in VB) can't be generic or nested. // Note that we might incorrectly ignore valid types, because, for example, calling `GetTypeByMetadataName` // would return null if we have multiple definitions of a type even though only one is accessible from here // (e.g. an internal type declared inside a shared document). In this case, we have to handle the conflicted // types explicitly here. // // TODO: // Alternatively, we can try to get symbols out of each assembly, instead of the compilation (which includes all references), // to avoid such conflict. We should give this approach a try and see if any perf improvement can be archieved. var containerSymbol = compilation.GetTypeByMetadataName(fullyQualifiedContainerName); if (containerSymbol != null) { GetItemsFromTypeContainsPotentialMatches(containerSymbol, qualifiedNamespaceName, methodNames, receiverTypeSymbol, semanticModel, position, counter, builder); } else { conflictTypeRootNode.Add(fullyQualifiedContainerName, (qualifiedNamespaceName, methodNames)); } } var ticks = Environment.TickCount; GetItemsFromConflictingTypes(rootNamespaceSymbol, conflictTypeRootNode, builder, receiverTypeSymbol, semanticModel, position, counter); counter.GetSymbolExtraTicks = Environment.TickCount - ticks; return(builder.ToImmutable()); }