Ejemplo n.º 1
0
        private async Task <ChangeSignatureAnalyzedContext> GetContextAsync(
            Document document, int position, bool restrictToDeclarations, CancellationToken cancellationToken)
        {
            var symbol = await GetInvocationSymbolAsync(
                document, position, restrictToDeclarations, cancellationToken).ConfigureAwait(false);

            // Cross-lang symbols will show as metadata, so map it to source if possible.
            symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol;

            if (symbol == null)
            {
                return(new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol is IMethodSymbol)
            {
                var method         = symbol as IMethodSymbol;
                var containingType = method.ContainingType;

                if (method.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                    containingType != null &&
                    containingType.IsDelegateType() &&
                    containingType.DelegateInvokeMethod != null)
                {
                    symbol = containingType.DelegateInvokeMethod;
                }
            }

            if (symbol is IEventSymbol)
            {
                symbol = (symbol as IEventSymbol).Type;
            }

            if (symbol is INamedTypeSymbol)
            {
                var typeSymbol = symbol as INamedTypeSymbol;
                if (typeSymbol.IsDelegateType() && typeSymbol.DelegateInvokeMethod != null)
                {
                    symbol = typeSymbol.DelegateInvokeMethod;
                }
            }

            if (symbol.Locations.Any(loc => loc.IsInMetadata))
            {
                return(new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType))
            {
                return(new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            var parameterConfiguration = ParameterConfiguration.Create(symbol.GetParameters().ToList(), symbol is IMethodSymbol && (symbol as IMethodSymbol).IsExtensionMethod);

            if (!parameterConfiguration.IsChangeable())
            {
                return(new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.InsufficientParameters));
            }

            return(new ChangeSignatureAnalyzedContext(
                       document.Project, symbol, parameterConfiguration));
        }
Ejemplo n.º 2
0
        internal async Task <ChangeSignatureAnalyzedContext> GetContextAsync(
            Document document, int position, bool restrictToDeclarations, CancellationToken cancellationToken)
        {
            var(symbol, selectedIndex) = await GetInvocationSymbolAsync(
                document, position, restrictToDeclarations, cancellationToken).ConfigureAwait(false);

            // Cross-language symbols will show as metadata, so map it to source if possible.
            symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol;

            if (symbol == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol is IMethodSymbol method)
            {
                var containingType = method.ContainingType;

                if (method.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                    containingType != null &&
                    containingType.IsDelegateType() &&
                    containingType.DelegateInvokeMethod != null)
                {
                    symbol = containingType.DelegateInvokeMethod;
                }
            }

            if (symbol is IEventSymbol ev)
            {
                symbol = ev.Type;
            }

            if (symbol is INamedTypeSymbol typeSymbol)
            {
                if (typeSymbol.IsDelegateType() && typeSymbol.DelegateInvokeMethod != null)
                {
                    symbol = typeSymbol.DelegateInvokeMethod;
                }
            }

            if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol.Locations.Any(loc => loc.IsInMetadata))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            // This should be called after the metadata check above to avoid looking for nodes in metadata.
            var declarationLocation = symbol.Locations.FirstOrDefault();

            if (declarationLocation == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            var solution            = document.Project.Solution;
            var declarationDocument = solution.GetRequiredDocument(declarationLocation.SourceTree !);
            var declarationChangeSignatureService = declarationDocument.GetRequiredLanguageService <AbstractChangeSignatureService>();

            int insertPosition;
            var reference = symbol.DeclaringSyntaxReferences.FirstOrDefault();

            if (reference != null)
            {
                insertPosition = declarationChangeSignatureService.GetPositionBeforeParameterListClosingBrace(reference.GetSyntax());
            }
            else
            {
                // There may be no declaring syntax reference, for example delegate Invoke methods. Use an
                // insertPosition of 0 and continue on.
                insertPosition = 0;
            }

            var parameterConfiguration = ParameterConfiguration.Create(
                symbol.GetParameters().Select(p => new ExistingParameter(p)).ToImmutableArray <Parameter>(),
                symbol.IsExtensionMethod(), selectedIndex);

            return(new ChangeSignatureAnalysisSucceededContext(
                       declarationDocument, insertPosition, symbol, parameterConfiguration));
        }
        internal async Task <ChangeSignatureAnalyzedContext> GetContextAsync(
            Document document, int position, bool restrictToDeclarations, CancellationToken cancellationToken)
        {
            var(symbol, selectedIndex) = await GetInvocationSymbolAsync(
                document, position, restrictToDeclarations, cancellationToken).ConfigureAwait(false);

            // Cross-language symbols will show as metadata, so map it to source if possible.
            symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol;

            if (symbol == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            if (symbol is IMethodSymbol method)
            {
                var containingType = method.ContainingType;

                if (method.Name == WellKnownMemberNames.DelegateBeginInvokeName &&
                    containingType != null &&
                    containingType.IsDelegateType() &&
                    containingType.DelegateInvokeMethod != null)
                {
                    symbol = containingType.DelegateInvokeMethod;
                }
            }

            if (symbol is IEventSymbol ev)
            {
                symbol = ev.Type;
            }

            if (symbol is INamedTypeSymbol typeSymbol)
            {
                if (typeSymbol.IsDelegateType() && typeSymbol.DelegateInvokeMethod != null)
                {
                    symbol = typeSymbol.DelegateInvokeMethod;
                }
            }

            if (symbol.Locations.Any(loc => loc.IsInMetadata))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            // This should be called after the metadata check above to avoid looking for nodes in metadata.
            var declarationLocation = symbol.Locations.FirstOrDefault();

            if (declarationLocation == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DefinedInMetadata));
            }

            var solution            = document.Project.Solution;
            var documentId          = solution.GetDocumentId(declarationLocation.SourceTree);
            var declarationDocument = solution.GetDocument(documentId);
            var declarationChangeSignatureService = declarationDocument?.GetRequiredLanguageService <AbstractChangeSignatureService>();

            if (declarationChangeSignatureService == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DeclarationLanguageServiceNotFound));
            }

            int?insertPositionOpt = declarationChangeSignatureService.TryGetInsertPositionFromDeclaration(symbol.Locations.FirstOrDefault().FindNode(cancellationToken));

            if (insertPositionOpt == null)
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.DeclarationMethodPositionNotFound));
            }

            if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType))
            {
                return(new CannotChangeSignatureAnalyzedContext(CannotChangeSignatureReason.IncorrectKind));
            }

            var parameterConfiguration = ParameterConfiguration.Create(
                symbol.GetParameters().Select(p => new ExistingParameter(p)),
                symbol.IsExtensionMethod(), selectedIndex);

            return(new ChangeSignatureAnalyzedSucceedContext(
                       declarationDocument ?? document, insertPositionOpt.Value, symbol, parameterConfiguration));
        }