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); }
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) })); }