public override SyntaxNode VisitParameterList(ParameterListSyntax node)
            {
                ParameterListSyntax processedNode = (ParameterListSyntax)base.VisitParameterList(node);

                if (node.Equals(this.parameterList))
                {
                    // Get the lowest index on ParameterList of compressed Parameters
                    // Considers:
                    // void foo(int a, >int b, int c<, int d) -> void foo(int a, ParameterObject o, int d)

                    int order = this.parameters.Min(n => this.parameterList.Parameters.IndexOf(n));

                    // Create new parameter declaration
                    // TODO: hard-coded type name!
                    ParameterSyntax newParameter = Syntax.Parameter(Syntax.Identifier(this.parameterObjectName))
                                                   .WithType(Syntax.ParseTypeName("ParameterObject"))
                                                   .WithAdditionalAnnotations(CodeAnnotations.Formatting);

                    // Insert new parameter's declaration to the list
                    ParameterListSyntax newParameterList = processedNode.WithParameters(processedNode.Parameters.Insert(order, newParameter));

                    return(newParameterList);
                }

                return(processedNode);
            }
Example #2
0
        public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken)
        {
            SyntaxNode     root  = (SyntaxNode)document.GetSyntaxRoot(cancellationToken);
            ISemanticModel model = document.GetSemanticModel(cancellationToken);

            // Verify that the selection is only within ParameterList
            IEnumerable <ParameterSyntax> selectedParameters = root.DescendantNodes(textSpan).OfType <ParameterSyntax>();

            if (selectedParameters.Count() == 0)
            {
                return(null);
            }

            // Get arbitrary node for further processing
            ParameterSyntax selectedNode = selectedParameters.FirstOrDefault();

            if (selectedNode == null)
            {
                return(null);
            }

            // Get ParameterList node
            ParameterListSyntax parameterList = selectedNode.FirstAncestorOrSelf <ParameterListSyntax>();

            if (parameterList == null)
            {
                return(null);
            }

            // All selected nodes should have the same parent which is ParameterList
            bool haveSameParent = selectedParameters.All(
                (n) =>
            {
                ParameterListSyntax parent = n.FirstAncestorOrSelf <ParameterListSyntax>();
                return(parent != null && parent.Equals(parameterList));
            });

            if (!haveSameParent)
            {
                return(null);
            }

            // Parameters that are defined within OperatorDeclaration should not be compressed to ParameterObject
            if (parameterList.FirstAncestorOrSelf <ConversionOperatorDeclarationSyntax>() != null ||
                parameterList.FirstAncestorOrSelf <OperatorDeclarationSyntax>() != null)
            {
                return(null);
            }

            // Parameters that are defined within Lambda, delegate's delaration or anonymous methods should not be compressed to ParameterObject
            if (parameterList.FirstAncestorOrSelf <ParenthesizedLambdaExpressionSyntax>() != null ||
                parameterList.FirstAncestorOrSelf <SimpleLambdaExpressionSyntax>() != null ||
                parameterList.FirstAncestorOrSelf <DelegateDeclarationSyntax>() != null ||
                parameterList.FirstAncestorOrSelf <AnonymousMethodExpressionSyntax>() != null)
            {
                return(null);
            }

            // Parameters that are either `out' or `ref' cannot be compressed,
            // because C# is not able to store pointers to them in a parameter object
            if (selectedParameters.Any(n => n.Modifiers.Any(m => m.Kind == SyntaxKind.RefKeyword || m.Kind == SyntaxKind.OutKeyword)))
            {
                return(null);
            }

            // Get parent declaration: Method/Ctor
            BaseMethodDeclarationSyntax baseMethodDeclaration = parameterList.FirstAncestorOrSelf <BaseMethodDeclarationSyntax>();

            if (baseMethodDeclaration == null)
            {
                return(null);
            }

            ISymbol baseMethodSymbol = model.GetDeclaredSymbol(baseMethodDeclaration);

            if (baseMethodSymbol == null)
            {
                return(null);
            }

            if (baseMethodSymbol is MethodSymbol)
            {
                MethodSymbol methodSymbol = (MethodSymbol)baseMethodSymbol;

                // Check is the method an implementation of the a super class method
                // If so, the parameters cannot be compressed, as they are parts of polymorphic signature
                if (methodSymbol.OverriddenMethod != null)
                {
                    return(null);
                }

                // TODO: This does not work for implicitly implemented interface member
                if (methodSymbol.MethodKind == MethodKind.ExplicitInterfaceImplementation)
                {
                    return(null);
                }
            }

            return(new CodeRefactoring(new[] { new IntroduceParameterObjectAction(document, selectedParameters) }));
        }