예제 #1
0
        public async Task <SignatureHelpViewModel> ComputeSignatureHelpAsync(
            SourceText sourceText,
            LinePosition linePosition,
            CancellationToken cancellationToken)
        {
            var signatureHelp = new SignatureHelpViewModel();
            var position      = sourceText.Lines.GetPosition(linePosition);

            if (position <= 0)
            {
                return(signatureHelp);
            }

            var document = compilationWorkspace.GetSubmissionDocument(sourceText.Container);
            var root     = await document.GetSyntaxRootAsync(cancellationToken);

            var syntaxToken = root.FindToken(position);

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken);

            var currentNode = syntaxToken.Parent;

            do
            {
                var creationExpression = currentNode as ObjectCreationExpressionSyntax;
                if (creationExpression != null && creationExpression.ArgumentList.Span.Contains(position))
                {
                    return(CreateMethodGroupSignatureHelp(
                               creationExpression,
                               creationExpression.ArgumentList,
                               position,
                               semanticModel));
                }

                var invocationExpression = currentNode as InvocationExpressionSyntax;
                if (invocationExpression != null && invocationExpression.ArgumentList.Span.Contains(position))
                {
                    return(CreateMethodGroupSignatureHelp(
                               invocationExpression.Expression,
                               invocationExpression.ArgumentList,
                               position,
                               semanticModel));
                }

                currentNode = currentNode.Parent;
            } while (currentNode != null);

            return(signatureHelp);
        }
예제 #2
0
        static SignatureHelpViewModel CreateMethodGroupSignatureHelp(
            ExpressionSyntax expression,
            ArgumentListSyntax argumentList,
            int position,
            SemanticModel semanticModel)
        {
            var signatureHelp = new SignatureHelpViewModel();

            // Happens for object initializers with no preceding parens, as soon as user types comma
            if (argumentList == null)
            {
                return(signatureHelp);
            }

            int currentArg;

            if (TryGetCurrentArgumentIndex(argumentList, position, out currentArg))
            {
                signatureHelp.ActiveParameter = currentArg;
            }

            var symbolInfo      = semanticModel.GetSymbolInfo(expression);
            var bestGuessMethod = symbolInfo.Symbol as IMethodSymbol;

            // Include everything by default (global eval context)
            var includeInstance = true;
            var includeStatic   = true;

            ITypeSymbol throughType = null;

            // When accessing method via some member, only show static methods in static context and vice versa for instance methods.
            // This block based on https://github.com/dotnet/roslyn/blob/3b6536f4a616e5f3b8ede940c63663a828e68b5d/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs#L44-L50
            if (expression is MemberAccessExpressionSyntax memberAccessExpression)
            {
                var throughExpression = (memberAccessExpression).Expression;
                if (!(throughExpression is BaseExpressionSyntax))
                {
                    throughType = semanticModel.GetTypeInfo(throughExpression).Type;
                }
                var throughSymbolInfo = semanticModel.GetSymbolInfo(throughExpression);
                var throughSymbol     = throughSymbolInfo.Symbol ?? throughSymbolInfo.CandidateSymbols.FirstOrDefault();

                includeInstance = !throughExpression.IsKind(SyntaxKind.IdentifierName) ||
                                  semanticModel.LookupSymbols(throughExpression.SpanStart, name: throughSymbol.Name).Any(s => !(s is INamedTypeSymbol)) ||
                                  (!(throughSymbol is INamespaceOrTypeSymbol) && semanticModel.LookupSymbols(throughExpression.SpanStart, throughSymbol.ContainingType).Any(s => !(s is INamedTypeSymbol)));
                includeStatic = throughSymbol is INamedTypeSymbol ||
                                (throughExpression.IsKind(SyntaxKind.IdentifierName) &&
                                 semanticModel.LookupNamespacesAndTypes(throughExpression.SpanStart, name: throughSymbol.Name).Any(t => t.GetSymbolType() == throughType));
            }

            // TODO: Start taking CT in here? Most calls in this method have optional CT arg. Could make this async.
            var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, CancellationToken.None);

            var methods = semanticModel
                          .GetMemberGroup(expression)
                          .OfType <IMethodSymbol> ()
                          .Where(m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance))
                          .Where(m => m.IsAccessibleWithin(within, throughTypeOpt: throughType))
                          .ToArray();

            var signatures = new List <SignatureViewModel> ();

            for (var i = 0; i < methods.Length; i++)
            {
                if (methods [i] == bestGuessMethod)
                {
                    signatureHelp.ActiveSignature = i;
                }

                var signatureInfo = new SignatureViewModel(methods [i]);

                signatures.Add(signatureInfo);
            }

            signatureHelp.Signatures = signatures.ToArray();

            return(signatureHelp);
        }