// // // // // $Revision$ // using System; using System.Collections.Generic; using System.Drawing; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.TextEditor; using ICSharpCode.TextEditor.Document; using SearchAndReplace; namespace ICSharpCode.SharpDevelop.Refactoring { public static class FindReferencesAndRenameHelper { #region Rename Class public static void RenameClass(IClass c) { string newName = MessageService.ShowInputBox("${res:SharpDevelop.Refactoring.Rename}", "${res:SharpDevelop.Refactoring.RenameClassText}", c.Name); if (!FindReferencesAndRenameHelper.CheckName(newName, c.Name)) return; RenameClass(c, newName); } public static void RenameClass(IClass c, string newName) { c = c.GetCompoundClass(); // get compound class if class is partial List list = RefactoringService.FindReferences(c, null); if (list == null) return; // Add the class declaration(s) foreach (IClass part in GetClassParts(c)) { AddDeclarationAsReference(list, part.CompilationUnit.FileName, part.Region, part.Name); } // Add the constructors foreach (IMethod m in c.Methods) { if (m.IsConstructor) { AddDeclarationAsReference(list, m.DeclaringType.CompilationUnit.FileName, m.Region, c.Name); } } FindReferencesAndRenameHelper.RenameReferences(list, newName); } static IList GetClassParts(IClass c) { CompoundClass cc = c as CompoundClass; if (cc != null) { return cc.Parts; } else { return new IClass[] {c}; } } static void AddDeclarationAsReference(List list, string fileName, DomRegion region, string name) { if (fileName == null) return; ProvidedDocumentInformation documentInformation = FindReferencesAndRenameHelper.GetDocumentInformation(fileName); int offset = documentInformation.CreateDocument().PositionToOffset(new Point(region.BeginColumn - 1, region.BeginLine - 1)); string text = documentInformation.TextBuffer.GetText(offset, Math.Min(name.Length + 30, documentInformation.TextBuffer.Length - offset - 1)); int offsetChange = text.IndexOf(name); if (offsetChange < 0) return; offset += offsetChange; foreach (Reference r in list) { if (r.Offset == offset) return; } list.Add(new Reference(fileName, offset, name.Length, name, null)); } #endregion #region Rename member public static void RenameMember(IMember member) { string newName = MessageService.ShowInputBox("${res:SharpDevelop.Refactoring.Rename}", "${res:SharpDevelop.Refactoring.RenameMemberText}", member.Name); if (!FindReferencesAndRenameHelper.CheckName(newName, member.Name)) return; RenameMember(member, newName); } public static void RenameMember(IMember member, string newName) { List list = RefactoringService.FindReferences(member, null); if (list == null) return; FindReferencesAndRenameHelper.RenameReferences(list, newName); if (member is IField) { IProperty property = FindProperty((IField)member); if (property != null) { string newPropertyName = member.DeclaringType.ProjectContent.Language.CodeGenerator.GetPropertyName(newName); if (newPropertyName != newName && newPropertyName != property.Name) { if (MessageService.AskQuestionFormatted("${res:SharpDevelop.Refactoring.Rename}", "${res:SharpDevelop.Refactoring.RenameFieldAndProperty}", property.FullyQualifiedName, newPropertyName)) { list = RefactoringService.FindReferences(property, null); if (list != null) { FindReferencesAndRenameHelper.RenameReferences(list, newPropertyName); } } } } } } internal static IProperty FindProperty(IField field) { LanguageProperties language = field.DeclaringType.ProjectContent.Language; if (language.CodeGenerator == null) return null; string propertyName = language.CodeGenerator.GetPropertyName(field.Name); IProperty foundProperty = null; foreach (IProperty prop in field.DeclaringType.Properties) { if (language.NameComparer.Equals(propertyName, prop.Name)) { foundProperty = prop; break; } } return foundProperty; } #endregion #region Common helper functions public static ProvidedDocumentInformation GetDocumentInformation(string fileName) { foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) { if (content is ITextEditorControlProvider && content.FileName != null && FileUtility.IsEqualFileName(content.FileName, fileName)) { return new ProvidedDocumentInformation(((ITextEditorControlProvider)content).TextEditorControl.Document, fileName, 0); } } ITextBufferStrategy strategy = StringTextBufferStrategy.CreateTextBufferFromFile(fileName); return new ProvidedDocumentInformation(strategy, fileName, 0); } public static bool IsReadOnly(IClass c) { return c.CompilationUnit.FileName == null; } public static TextEditorControl JumpToDefinition(IMember member) { IViewContent viewContent = null; ICompilationUnit cu = member.DeclaringType.CompilationUnit; if (cu != null) { string fileName = cu.FileName; if (fileName != null) { if (!member.Region.IsEmpty) { viewContent = FileService.JumpToFilePosition(fileName, member.Region.BeginLine - 1, member.Region.BeginColumn - 1); } else { FileService.OpenFile(fileName); } } } ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider tecp = viewContent as ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider; return (tecp == null) ? null : tecp.TextEditorControl; } public static TextEditorControl JumpBehindDefinition(IMember member) { IViewContent viewContent = null; ICompilationUnit cu = member.DeclaringType.CompilationUnit; if (cu != null) { string fileName = cu.FileName; if (fileName != null) { if (!member.Region.IsEmpty) { viewContent = FileService.JumpToFilePosition(fileName, member.Region.EndLine, 0); } else { FileService.OpenFile(fileName); } } } ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider tecp = viewContent as ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.ITextEditorControlProvider; return (tecp == null) ? null : tecp.TextEditorControl; } public static bool CheckName(string name, string oldName) { if (name == null || name.Length == 0 || name == oldName) return false; if (!char.IsLetter(name, 0) && name[0] != '_') { MessageService.ShowError("${res:SharpDevelop.Refactoring.InvalidNameStart}"); return false; } for (int i = 1; i < name.Length; i++) { if (!char.IsLetterOrDigit(name, i) && name[i] != '_') { MessageService.ShowError("${res:SharpDevelop.Refactoring.InvalidName}"); return false; } } return true; } public struct Modification { public IDocument Document; public int Offset; public int LengthDifference; public Modification(IDocument document, int offset, int lengthDifference) { this.Document = document; this.Offset = offset; this.LengthDifference = lengthDifference; } } public static void ModifyDocument(List modifications, IDocument doc, int offset, int length, string newName) { foreach (Modification m in modifications) { if (m.Document == doc) { if (m.Offset < offset) offset += m.LengthDifference; } } int lengthDifference = newName.Length - length; doc.Replace(offset, length, newName); if (lengthDifference != 0) { for (int i = 0; i < modifications.Count; ++i) { Modification m = modifications[i]; if (m.Document == doc) { if (m.Offset > offset) { m.Offset += lengthDifference; modifications[i] = m; // Modification is a value type } } } modifications.Add(new Modification(doc, offset, lengthDifference)); } } public static void ShowAsSearchResults(string pattern, List list) { if (list == null) return; List results = new List(list.Count); foreach (Reference r in list) { SearchResult res = new SearchResult(r.Offset, r.Length); res.ProvidedDocumentInformation = GetDocumentInformation(r.FileName); results.Add(res); } SearchInFilesManager.ShowSearchResults(pattern, results); } public static void RenameReferences(List list, string newName) { List modifiedContents = new List(); List modifications = new List(); foreach (Reference r in list) { FileService.OpenFile(r.FileName); IViewContent viewContent = FileService.GetOpenFile(r.FileName).ViewContent; if (!modifiedContents.Contains(viewContent)) { modifiedContents.Add(viewContent); } ITextEditorControlProvider p = viewContent as ITextEditorControlProvider; if (p != null) { ModifyDocument(modifications, p.TextEditorControl.Document, r.Offset, r.Length, newName); } } foreach (IViewContent viewContent in modifiedContents) { ParserService.ParseViewContent(viewContent); } } #endregion } }