void AddImportExtensionMethodCompletionData(CompletionDataList result, CSharpSyntaxContext ctx, INamedTypeSymbol fromType, ITypeSymbol receiverType, Dictionary <INamespaceSymbol, List <ImportSymbolCompletionData> > extMethodDict)
        {
            try {
                foreach (var extMethod in fromType.GetMembers().OfType <IMethodSymbol> ().Where(method => method.IsExtensionMethod))
                {
                    var reducedMethod = extMethod.ReduceExtensionMethod(receiverType);
                    if (reducedMethod != null)
                    {
                        if (!extMethodDict.TryGetValue(fromType.ContainingNamespace, out var importSymbolList))
                        {
                            extMethodDict.Add(fromType.ContainingNamespace, importSymbolList = new List <ImportSymbolCompletionData> ());
                        }

                        var newData = new ImportSymbolCompletionData(this, ctx, reducedMethod, false);
                        ImportSymbolCompletionData existingItem = null;
                        foreach (var data in importSymbolList)
                        {
                            if (data.Symbol.Name == extMethod.Name)
                            {
                                existingItem = data;
                                break;
                            }
                        }

                        if (existingItem != null)
                        {
                            existingItem.AddOverload(newData);
                        }
                        else
                        {
                            result.Add(newData);
                            importSymbolList.Add(newData);
                        }
                    }
                }
            } catch (Exception e) {
                LoggingService.LogError("Exception while AddImportExtensionMethodCompletionData", e);
            }
        }
Beispiel #2
0
        internal void AddImportCompletionData(CSharpSyntaxContext ctx, CompletionDataList result, SemanticModel semanticModel, int position, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (result.Count == 0)
            {
                return;
            }
            var root       = semanticModel.SyntaxTree.GetRoot();
            var node       = root.FindNode(TextSpan.FromBounds(position, position));
            var syntaxTree = root.SyntaxTree;

            if (syntaxTree.IsInNonUserCode(position, cancellationToken) ||
                syntaxTree.GetContainingTypeOrEnumDeclaration(position, cancellationToken) is EnumDeclarationSyntax ||
                syntaxTree.IsPreProcessorDirectiveContext(position, cancellationToken))
            {
                return;
            }

            var         extensionMethodImport = syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken);
            ITypeSymbol extensionType         = null;

            if (extensionMethodImport)
            {
                var memberAccess = ctx.TargetToken.Parent as MemberAccessExpressionSyntax;
                if (memberAccess != null)
                {
                    var symbolInfo = ctx.SemanticModel.GetSymbolInfo(memberAccess.Expression);
                    if (symbolInfo.Symbol.Kind == SymbolKind.NamedType)
                    {
                        return;
                    }
                    extensionType = ctx.SemanticModel.GetTypeInfo(memberAccess.Expression).Type;
                    if (extensionType == null)
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }
            }

            var tokenLeftOfPosition = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken);

            if (extensionMethodImport ||
                syntaxTree.IsGlobalStatementContext(position, cancellationToken) ||
                syntaxTree.IsExpressionContext(position, tokenLeftOfPosition, true, cancellationToken) ||
                syntaxTree.IsStatementContext(position, tokenLeftOfPosition, cancellationToken) ||
                syntaxTree.IsTypeContext(position, cancellationToken) ||
                syntaxTree.IsTypeDeclarationContext(position, tokenLeftOfPosition, cancellationToken) ||
                syntaxTree.IsMemberDeclarationContext(position, tokenLeftOfPosition, cancellationToken) ||
                syntaxTree.IsLabelContext(position, cancellationToken))
            {
                var usedNamespaces = new HashSet <string> ();
                foreach (var un in semanticModel.GetUsingNamespacesInScope(node))
                {
                    usedNamespaces.Add(un.GetFullName());
                }
                var enclosingNamespaceName = semanticModel.GetEnclosingNamespace(position, cancellationToken).GetFullName();

                var stack = new Stack <INamespaceOrTypeSymbol> ();
                foreach (var member in semanticModel.Compilation.GlobalNamespace.GetNamespaceMembers())
                {
                    stack.Push(member);
                }
                var extMethodDict = extensionMethodImport ? new Dictionary <INamespaceSymbol, List <ImportSymbolCompletionData> > () : null;
                var typeDict      = new Dictionary <INamespaceSymbol, HashSet <string> > ();
                while (stack.Count > 0)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                    var current   = stack.Pop();
                    var currentNs = current as INamespaceSymbol;
                    if (currentNs != null)
                    {
                        var currentNsName = currentNs.GetFullName();
                        if (usedNamespaces.Contains(currentNsName) ||
                            enclosingNamespaceName == currentNsName ||
                            (enclosingNamespaceName.StartsWith(currentNsName, StringComparison.Ordinal) &&
                             enclosingNamespaceName [currentNsName.Length] == '.'))
                        {
                            foreach (var member in currentNs.GetNamespaceMembers())
                            {
                                stack.Push(member);
                            }
                        }
                        else
                        {
                            foreach (var member in currentNs.GetMembers())
                            {
                                stack.Push(member);
                            }
                        }
                    }
                    else
                    {
                        var type = (INamedTypeSymbol)current;
                        if (type.IsImplicitClass || type.IsScriptClass)
                        {
                            continue;
                        }
                        if (type.DeclaredAccessibility != Accessibility.Public)
                        {
                            if (type.DeclaredAccessibility != Accessibility.Internal)
                            {
                                continue;
                            }
                            if (!type.IsAccessibleWithin(semanticModel.Compilation.Assembly))
                            {
                                continue;
                            }
                        }
                        if (extensionMethodImport)
                        {
                            if (!type.MightContainExtensionMethods)
                            {
                                continue;
                            }
                            foreach (var extMethod in type.GetMembers().OfType <IMethodSymbol> ().Where(method => method.IsExtensionMethod))
                            {
                                var reducedMethod = extMethod.ReduceExtensionMethod(extensionType);
                                if (reducedMethod != null)
                                {
                                    List <ImportSymbolCompletionData> importSymbolList;
                                    if (!extMethodDict.TryGetValue(type.ContainingNamespace, out importSymbolList))
                                    {
                                        extMethodDict.Add(type.ContainingNamespace, importSymbolList = new List <ImportSymbolCompletionData> ());
                                    }
                                    var newData      = new ImportSymbolCompletionData(this, reducedMethod, false);
                                    var existingItem = importSymbolList.FirstOrDefault(data => data.Symbol.Name == extMethod.Name);
                                    if (existingItem != null)
                                    {
                                        existingItem.AddOverload(newData);
                                    }
                                    else
                                    {
                                        result.Add(newData);
                                        importSymbolList.Add(newData);
                                    }
                                }
                            }
                        }
                        else
                        {
                            HashSet <string> existingTypeHashSet;
                            if (!typeDict.TryGetValue(type.ContainingNamespace, out existingTypeHashSet))
                            {
                                typeDict.Add(type.ContainingNamespace, existingTypeHashSet = new HashSet <string> ());
                            }
                            if (!existingTypeHashSet.Contains(type.Name))
                            {
                                result.Add(new ImportSymbolCompletionData(this, type, false));
                                existingTypeHashSet.Add(type.Name);
                            }
                        }
                    }
                }
            }
        }