public override List<Change> PerformChanges (RefactoringOptions options, object prop)
		{
			List<Change> result = new List<Change> ();
			ExtractMethodParameters param = (ExtractMethodParameters)prop;
			TextEditorData data = options.GetTextEditorData ();
			INRefactoryASTProvider provider = options.GetASTProvider ();
			IResolver resolver = options.GetResolver ();
			ICSharpCode.NRefactory.Ast.INode node = Analyze (options, param, false);
			if (param.VariablesToGenerate.Count > 0) {
				TextReplaceChange varGen = new TextReplaceChange ();
				varGen.Description = GettextCatalog.GetString ("Generate some temporary variables");
				varGen.FileName = options.Document.FileName;
				LineSegment line = data.Document.GetLine (Math.Max (0, data.Document.OffsetToLineNumber (data.SelectionRange.Offset) - 1));
				varGen.Offset = line.Offset + line.EditableLength;
				varGen.InsertedText = Environment.NewLine + options.GetWhitespaces (line.Offset);
				foreach (VariableDescriptor var in param.VariablesToGenerate) {
					TypeReference tr = options.ShortenTypeName (var.ReturnType).ConvertToTypeReference ();
					varGen.InsertedText += provider.OutputNode (options.Dom, new LocalVariableDeclaration (new VariableDeclaration (var.Name, null, tr))).Trim ();
				}
				result.Add (varGen);
			}
			InvocationExpression invocation = new InvocationExpression (new IdentifierExpression (param.Name));
			foreach (VariableDescriptor var in param.Parameters) {
				if (!param.OneChangedVariable && param.ChangedVariables.Contains (var.Name)) {
					FieldDirection fieldDirection = FieldDirection.Ref;
					VariableDescriptor outsideVar = null;
					if (param.VariablesOutside.TryGetValue (var.Name, out outsideVar) && (var.GetsAssigned || param.VariablesToGenerate.Where (v => v.Name == var.Name).Any ())) {
						if (!outsideVar.GetsAssigned)
							fieldDirection = FieldDirection.Out;
					}
					invocation.Arguments.Add (new DirectionExpression (fieldDirection, new IdentifierExpression (var.Name)));
				} else {
					invocation.Arguments.Add (new IdentifierExpression (var.Name));
				}
			}
			//	string mimeType = DesktopService.GetMimeTypeForUri (options.Document.FileName);
			TypeReference returnType = new TypeReference ("System.Void", true);
			ICSharpCode.NRefactory.Ast.INode outputNode;
			if (param.OneChangedVariable) {
				string name = param.ChangedVariables.First ();
				returnType = options.ShortenTypeName (param.Variables.Find (v => v.Name == name).ReturnType).ConvertToTypeReference ();
				if (param.OutsideVariableList.Any (v => v.Name == name && !v.IsDefined)) {
					LocalVariableDeclaration varDecl = new LocalVariableDeclaration (returnType);
					varDecl.Variables.Add (new VariableDeclaration (name, invocation));
					outputNode = varDecl;
				} else {
					outputNode = new ExpressionStatement (new AssignmentExpression (new IdentifierExpression (name), ICSharpCode.NRefactory.Ast.AssignmentOperatorType.Assign, invocation));
				}
			} else {
				outputNode = node is BlockStatement ? (ICSharpCode.NRefactory.Ast.INode)new ExpressionStatement (invocation) : invocation;
			}
			TextReplaceChange replacement = new TextReplaceChange ();
			replacement.Description = string.Format (GettextCatalog.GetString ("Substitute selected statement(s) with call to {0}"), param.Name);
			replacement.FileName = options.Document.FileName;
			replacement.Offset = options.Document.Editor.SelectionRange.Offset;
			replacement.RemovedChars = options.Document.Editor.SelectionRange.Length;
			replacement.MoveCaretToReplace = true;
			
			LineSegment line1 = data.Document.GetLineByOffset (options.Document.Editor.SelectionRange.EndOffset);
			if (options.Document.Editor.SelectionRange.EndOffset == line1.Offset) {
				if (line1.Offset > 0) {
					LineSegment line2 = data.Document.GetLineByOffset (line1.Offset - 1);
					replacement.RemovedChars -= line2.DelimiterLength;
				}
			}
			
			replacement.InsertedText = options.GetWhitespaces (options.Document.Editor.SelectionRange.Offset) + provider.OutputNode (options.Dom, outputNode).Trim ();
			
			result.Add (replacement);

			TextReplaceChange insertNewMethod = new TextReplaceChange ();
			insertNewMethod.FileName = options.Document.FileName;
			insertNewMethod.Description = string.Format (GettextCatalog.GetString ("Create new method {0} from selected statement(s)"), param.Name);
			insertNewMethod.RemovedChars = param.InsertionPoint.LineBefore == NewLineInsertion.Eol ? 0 : param.InsertionPoint.Location.Column;
			insertNewMethod.Offset = data.Document.LocationToOffset (param.InsertionPoint.Location) - insertNewMethod.RemovedChars;
			
			ExtractMethodAstTransformer transformer = new ExtractMethodAstTransformer (param.VariablesToGenerate);
			node.AcceptVisitor (transformer, null);
			if (!param.OneChangedVariable && node is Expression) {
				ResolveResult resolveResult = resolver.Resolve (new ExpressionResult ("(" + provider.OutputNode (options.Dom, node) + ")"), new DomLocation (options.Document.Editor.Caret.Line, options.Document.Editor.Caret.Column));
				if (resolveResult.ResolvedType != null)
					returnType = options.ShortenTypeName (resolveResult.ResolvedType).ConvertToTypeReference ();
			}
			
			MethodDeclaration methodDecl = new MethodDeclaration ();
			methodDecl.Name = param.Name;
			methodDecl.Modifier = param.Modifiers;
			methodDecl.TypeReference = returnType;
			
			if (!param.ReferencesMember)
				methodDecl.Modifier |= ICSharpCode.NRefactory.Ast.Modifiers.Static;
			if (node is BlockStatement) {
				methodDecl.Body = new BlockStatement ();
				methodDecl.Body.AddChild (new EmptyStatement ());
				if (param.OneChangedVariable)
					methodDecl.Body.AddChild (new ReturnStatement (new IdentifierExpression (param.ChangedVariables.First ())));
			} else if (node is Expression) {
				methodDecl.Body = new BlockStatement ();
				methodDecl.Body.AddChild (new ReturnStatement (node as Expression));
			}
			
			foreach (VariableDescriptor var in param.VariablesToDefine) {
				BlockStatement block = methodDecl.Body;
				LocalVariableDeclaration varDecl = new LocalVariableDeclaration (options.ShortenTypeName (var.ReturnType).ConvertToTypeReference ());
				varDecl.Variables.Add (new VariableDeclaration (var.Name));
				block.Children.Insert (0, varDecl);
			}
			
			foreach (VariableDescriptor var in param.Parameters) {
				TypeReference typeReference = options.ShortenTypeName (var.ReturnType).ConvertToTypeReference ();
				ParameterDeclarationExpression pde = new ParameterDeclarationExpression (typeReference, var.Name);
				if (!param.OneChangedVariable) {
					if (param.ChangedVariables.Contains (var.Name))
						pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Ref;
					if (param.VariablesToGenerate.Where (v => v.Name == var.Name).Any ()) {
						pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out;
					}
					VariableDescriptor outsideVar = null;
					if (var.GetsAssigned && param.VariablesOutside.TryGetValue (var.Name, out outsideVar)) {
						if (!outsideVar.GetsAssigned)
							pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out;
					}
				}
				
				methodDecl.Parameters.Add (pde);
			}
			
			string indent = options.GetIndent (param.DeclaringMember);
			StringBuilder methodText = new StringBuilder ();
			switch (param.InsertionPoint.LineBefore) {
			case NewLineInsertion.Eol:
				methodText.AppendLine ();
				break;
			case NewLineInsertion.BlankLine:
				methodText.Append (indent);
				methodText.AppendLine ();
				break;
			}
			if (param.GenerateComment) {
				methodText.Append (indent);
				methodText.AppendLine ("/// <summary>");
				methodText.Append (indent);
				methodText.AppendLine ("/// TODO: write a comment.");
				methodText.Append (indent);
				methodText.AppendLine ("/// </summary>");
				Ambience ambience = AmbienceService.GetAmbienceForFile (options.Document.FileName);
				foreach (ParameterDeclarationExpression pde in methodDecl.Parameters) {
					methodText.Append (indent);
					methodText.Append ("/// <param name=\"");
					methodText.Append (pde.ParameterName);
					methodText.Append ("\"> A ");
					methodText.Append (ambience.GetString (pde.TypeReference.ConvertToReturnType (), OutputFlags.IncludeGenerics | OutputFlags.UseFullName));
					methodText.Append (" </param>");
					methodText.AppendLine ();
				}
				if (methodDecl.TypeReference.Type != "System.Void") {
					methodText.Append (indent);
					methodText.AppendLine ("/// <returns>");
					methodText.Append (indent);
					methodText.Append ("/// A ");
					methodText.AppendLine (ambience.GetString (methodDecl.TypeReference.ConvertToReturnType (), OutputFlags.IncludeGenerics | OutputFlags.UseFullName));
					methodText.Append (indent);
					methodText.AppendLine ("/// </returns>");
				}
			}
			
			methodText.Append (indent);
			
			if (node is BlockStatement) {
				string text = provider.OutputNode (options.Dom, methodDecl, indent).Trim ();
				int emptyStatementMarker = text.LastIndexOf (';');
				if (param.OneChangedVariable)
					emptyStatementMarker = text.LastIndexOf (';', emptyStatementMarker - 1);
				StringBuilder sb = new StringBuilder ();
				sb.Append (text.Substring (0, emptyStatementMarker));
				sb.Append (AddIndent (param.Text, indent + "\t"));
				sb.Append (text.Substring (emptyStatementMarker + 1));
				
				methodText.Append (sb.ToString ());
			} else {
				methodText.Append (provider.OutputNode (options.Dom, methodDecl, options.GetIndent (param.DeclaringMember)).Trim ());
			}
			
			switch (param.InsertionPoint.LineAfter) {
			case NewLineInsertion.Eol:
				methodText.AppendLine ();
				break;
			case NewLineInsertion.BlankLine:
				methodText.AppendLine ();
				methodText.AppendLine ();
				methodText.Append (indent);
				break;
			}
			insertNewMethod.InsertedText = methodText.ToString ();
			result.Add (insertNewMethod);

			return result;
		}
Beispiel #2
0
        public override List <Change> PerformChanges(RefactoringOptions options, object prop)
        {
            List <Change>           result   = new List <Change> ();
            ExtractMethodParameters param    = (ExtractMethodParameters)prop;
            TextEditorData          data     = options.GetTextEditorData();
            INRefactoryASTProvider  provider = options.GetASTProvider();
            IResolver resolver = options.GetResolver();

            ICSharpCode.NRefactory.Ast.INode node = Analyze(options, param, false);
            if (param.VariablesToGenerate.Count > 0)
            {
                TextReplaceChange varGen = new TextReplaceChange();
                varGen.Description = GettextCatalog.GetString("Generate some temporary variables");
                varGen.FileName    = options.Document.FileName;
                LineSegment line = data.Document.GetLine(Math.Max(0, data.Document.OffsetToLineNumber(data.SelectionRange.Offset) - 1));
                varGen.Offset       = line.Offset + line.EditableLength;
                varGen.InsertedText = Environment.NewLine + options.GetWhitespaces(line.Offset);
                foreach (VariableDescriptor var in param.VariablesToGenerate)
                {
                    TypeReference tr = options.ShortenTypeName(var.ReturnType).ConvertToTypeReference();
                    varGen.InsertedText += provider.OutputNode(options.Dom, new LocalVariableDeclaration(new VariableDeclaration(var.Name, null, tr))).Trim();
                }
                result.Add(varGen);
            }
            InvocationExpression invocation = new InvocationExpression(new IdentifierExpression(param.Name));

            foreach (VariableDescriptor var in param.Parameters)
            {
                if (!param.OneChangedVariable && param.ChangedVariables.Contains(var.Name))
                {
                    FieldDirection     fieldDirection = FieldDirection.Ref;
                    VariableDescriptor outsideVar     = null;
                    if (param.VariablesOutside.TryGetValue(var.Name, out outsideVar) && (var.GetsAssigned || param.VariablesToGenerate.Where(v => v.Name == var.Name).Any()))
                    {
                        if (!outsideVar.GetsAssigned)
                        {
                            fieldDirection = FieldDirection.Out;
                        }
                    }
                    invocation.Arguments.Add(new DirectionExpression(fieldDirection, new IdentifierExpression(var.Name)));
                }
                else
                {
                    invocation.Arguments.Add(new IdentifierExpression(var.Name));
                }
            }
            //	string mimeType = DesktopService.GetMimeTypeForUri (options.Document.FileName);
            TypeReference returnType = new TypeReference("System.Void", true);

            ICSharpCode.NRefactory.Ast.INode outputNode;
            if (param.OneChangedVariable)
            {
                string name = param.ChangedVariables.First();
                returnType = options.ShortenTypeName(param.Variables.Find(v => v.Name == name).ReturnType).ConvertToTypeReference();
                if (param.OutsideVariableList.Any(v => v.Name == name && !v.IsDefined))
                {
                    LocalVariableDeclaration varDecl = new LocalVariableDeclaration(returnType);
                    varDecl.Variables.Add(new VariableDeclaration(name, invocation));
                    outputNode = varDecl;
                }
                else
                {
                    outputNode = new ExpressionStatement(new AssignmentExpression(new IdentifierExpression(name), ICSharpCode.NRefactory.Ast.AssignmentOperatorType.Assign, invocation));
                }
            }
            else
            {
                outputNode = node is BlockStatement ? (ICSharpCode.NRefactory.Ast.INode) new ExpressionStatement(invocation) : invocation;
            }
            TextReplaceChange replacement = new TextReplaceChange();

            replacement.Description        = string.Format(GettextCatalog.GetString("Substitute selected statement(s) with call to {0}"), param.Name);
            replacement.FileName           = options.Document.FileName;
            replacement.Offset             = options.Document.TextEditor.SelectionStartPosition;
            replacement.RemovedChars       = options.Document.TextEditor.SelectionEndPosition - options.Document.TextEditor.SelectionStartPosition;
            replacement.MoveCaretToReplace = true;

            LineSegment line1 = data.Document.GetLineByOffset(options.Document.TextEditor.SelectionEndPosition);

            if (options.Document.TextEditor.SelectionEndPosition == line1.Offset)
            {
                if (line1.Offset > 0)
                {
                    LineSegment line2 = data.Document.GetLineByOffset(line1.Offset - 1);
                    replacement.RemovedChars -= line2.DelimiterLength;
                }
            }

            replacement.InsertedText = options.GetWhitespaces(options.Document.TextEditor.SelectionStartPosition) + provider.OutputNode(options.Dom, outputNode).Trim();

            result.Add(replacement);

            TextReplaceChange insertNewMethod = new TextReplaceChange();

            insertNewMethod.FileName     = options.Document.FileName;
            insertNewMethod.Description  = string.Format(GettextCatalog.GetString("Create new method {0} from selected statement(s)"), param.Name);
            insertNewMethod.RemovedChars = param.InsertionPoint.LineBefore == NewLineInsertion.Eol ? 0 : param.InsertionPoint.Location.Column;
            insertNewMethod.Offset       = data.Document.LocationToOffset(param.InsertionPoint.Location) - insertNewMethod.RemovedChars;

            ExtractMethodAstTransformer transformer = new ExtractMethodAstTransformer(param.VariablesToGenerate);

            node.AcceptVisitor(transformer, null);
            if (!param.OneChangedVariable && node is Expression)
            {
                ResolveResult resolveResult = resolver.Resolve(new ExpressionResult("(" + provider.OutputNode(options.Dom, node) + ")"), new DomLocation(options.Document.TextEditor.CursorLine, options.Document.TextEditor.CursorColumn));
                if (resolveResult.ResolvedType != null)
                {
                    returnType = options.ShortenTypeName(resolveResult.ResolvedType).ConvertToTypeReference();
                }
            }

            MethodDeclaration methodDecl = new MethodDeclaration();

            methodDecl.Name          = param.Name;
            methodDecl.Modifier      = param.Modifiers;
            methodDecl.TypeReference = returnType;

            if (!param.ReferencesMember)
            {
                methodDecl.Modifier |= ICSharpCode.NRefactory.Ast.Modifiers.Static;
            }
            if (node is BlockStatement)
            {
                methodDecl.Body = new BlockStatement();
                methodDecl.Body.AddChild(new EmptyStatement());
                if (param.OneChangedVariable)
                {
                    methodDecl.Body.AddChild(new ReturnStatement(new IdentifierExpression(param.ChangedVariables.First())));
                }
            }
            else if (node is Expression)
            {
                methodDecl.Body = new BlockStatement();
                methodDecl.Body.AddChild(new ReturnStatement(node as Expression));
            }

            foreach (VariableDescriptor var in param.VariablesToDefine)
            {
                BlockStatement           block   = methodDecl.Body;
                LocalVariableDeclaration varDecl = new LocalVariableDeclaration(options.ShortenTypeName(var.ReturnType).ConvertToTypeReference());
                varDecl.Variables.Add(new VariableDeclaration(var.Name));
                block.Children.Insert(0, varDecl);
            }

            foreach (VariableDescriptor var in param.Parameters)
            {
                TypeReference typeReference        = options.ShortenTypeName(var.ReturnType).ConvertToTypeReference();
                ParameterDeclarationExpression pde = new ParameterDeclarationExpression(typeReference, var.Name);
                if (!param.OneChangedVariable)
                {
                    if (param.ChangedVariables.Contains(var.Name))
                    {
                        pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Ref;
                    }
                    if (param.VariablesToGenerate.Where(v => v.Name == var.Name).Any())
                    {
                        pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out;
                    }
                    VariableDescriptor outsideVar = null;
                    if (var.GetsAssigned && param.VariablesOutside.TryGetValue(var.Name, out outsideVar))
                    {
                        if (!outsideVar.GetsAssigned)
                        {
                            pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out;
                        }
                    }
                }

                methodDecl.Parameters.Add(pde);
            }

            string        indent     = options.GetIndent(param.DeclaringMember);
            StringBuilder methodText = new StringBuilder();

            switch (param.InsertionPoint.LineBefore)
            {
            case NewLineInsertion.Eol:
                methodText.AppendLine();
                break;

            case NewLineInsertion.BlankLine:
                methodText.Append(indent);
                methodText.AppendLine();
                break;
            }
            if (param.GenerateComment)
            {
                methodText.Append(indent);
                methodText.AppendLine("/// <summary>");
                methodText.Append(indent);
                methodText.AppendLine("/// TODO: write a comment.");
                methodText.Append(indent);
                methodText.AppendLine("/// </summary>");
                Ambience ambience = AmbienceService.GetAmbienceForFile(options.Document.FileName);
                foreach (ParameterDeclarationExpression pde in methodDecl.Parameters)
                {
                    methodText.Append(indent);
                    methodText.Append("/// <param name=\"");
                    methodText.Append(pde.ParameterName);
                    methodText.Append("\"> A ");
                    methodText.Append(ambience.GetString(pde.TypeReference.ConvertToReturnType(), OutputFlags.IncludeGenerics | OutputFlags.UseFullName));
                    methodText.Append(" </param>");
                    methodText.AppendLine();
                }
                if (methodDecl.TypeReference.Type != "System.Void")
                {
                    methodText.Append(indent);
                    methodText.AppendLine("/// <returns>");
                    methodText.Append(indent);
                    methodText.Append("/// A ");
                    methodText.AppendLine(ambience.GetString(methodDecl.TypeReference.ConvertToReturnType(), OutputFlags.IncludeGenerics | OutputFlags.UseFullName));
                    methodText.Append(indent);
                    methodText.AppendLine("/// </returns>");
                }
            }

            methodText.Append(indent);

            if (node is BlockStatement)
            {
                string text = provider.OutputNode(options.Dom, methodDecl, indent).Trim();
                int    emptyStatementMarker = text.LastIndexOf(';');
                if (param.OneChangedVariable)
                {
                    emptyStatementMarker = text.LastIndexOf(';', emptyStatementMarker - 1);
                }
                StringBuilder sb = new StringBuilder();
                sb.Append(text.Substring(0, emptyStatementMarker));
                sb.Append(AddIndent(param.Text, indent + "\t"));
                sb.Append(text.Substring(emptyStatementMarker + 1));

                methodText.Append(sb.ToString());
            }
            else
            {
                methodText.Append(provider.OutputNode(options.Dom, methodDecl, options.GetIndent(param.DeclaringMember)).Trim());
            }

            switch (param.InsertionPoint.LineAfter)
            {
            case NewLineInsertion.Eol:
                methodText.AppendLine();
                break;

            case NewLineInsertion.BlankLine:
                methodText.AppendLine();
                methodText.AppendLine();
                methodText.Append(indent);
                break;
            }
            insertNewMethod.InsertedText = methodText.ToString();
            result.Add(insertNewMethod);

            return(result);
        }