diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/AbstractInlineRefactorDialog.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/AbstractInlineRefactorDialog.cs index fded2bf1d1..e5758179fc 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/AbstractInlineRefactorDialog.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/AbstractInlineRefactorDialog.cs @@ -60,7 +60,7 @@ namespace SharpRefactoring.Gui LanguageProperties language = parseInfo.CompilationUnit.Language; IClass current = parseInfo.CompilationUnit.GetInnermostClass(anchor.Line, anchor.Column); - // Generate code could modify the document. + // GenerateCode could modify the document. // So read anchor.Offset after code generation. string code = GenerateCode(language, current) ?? ""; editor.Document.Insert(anchor.Offset, code); diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs index 7e2d66bf99..8f00ec4313 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/Gui/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs @@ -21,9 +21,13 @@ namespace SharpRefactoring.Gui public partial class OverrideEqualsGetHashCodeMethodsDialog : AbstractInlineRefactorDialog { IClass selectedClass; + ITextAnchor startAnchor; + IMethod selectedMethod; + string baseCall; - public OverrideEqualsGetHashCodeMethodsDialog(ITextEditor editor, ITextAnchor anchor, IClass selectedClass) - : base(null, editor, anchor) + public OverrideEqualsGetHashCodeMethodsDialog(ITextEditor editor, ITextAnchor startAnchor, ITextAnchor endAnchor, + ITextAnchor insertionPosition, IClass selectedClass, IMethod selectedMethod, string baseCall) + : base(null, editor, insertionPosition) { if (selectedClass == null) throw new ArgumentNullException("selectedClass"); @@ -31,6 +35,10 @@ namespace SharpRefactoring.Gui InitializeComponent(); this.selectedClass = selectedClass; + this.startAnchor = startAnchor; + this.insertionEndAnchor = endAnchor; + this.selectedMethod = selectedMethod; + this.baseCall = baseCall; addIEquatable.Content = string.Format(StringParser.Parse("${res:AddIns.SharpRefactoring.OverrideEqualsGetHashCodeMethods.AddInterface}"), "IEquatable<" + selectedClass.Name + ">"); @@ -98,7 +106,7 @@ namespace SharpRefactoring.Gui { StringBuilder code = new StringBuilder(); - var line = editor.Document.GetLineForOffset(editor.Caret.Offset); + var line = editor.Document.GetLineForOffset(startAnchor.Offset); string indent = DocumentUtilitites.GetWhitespaceAfter(editor.Document, line.Offset); @@ -107,35 +115,61 @@ namespace SharpRefactoring.Gui if (Options.AddIEquatableInterface) { // TODO : add IEquatable to class // IAmbience ambience = currentClass.CompilationUnit.Language.GetAmbience(); -// +// // IReturnType baseRType = currentClass.CompilationUnit.ProjectContent.GetClass("System.IEquatable", 1).DefaultReturnType; -// +// // IClass newClass = new DefaultClass(currentClass.CompilationUnit, currentClass.FullyQualifiedName, currentClass.Modifiers, currentClass.Region, null); -// +// // foreach (IReturnType type in currentClass.BaseTypes) { // newClass.BaseTypes.Add(type); // } -// -// +// +// // newClass.BaseTypes.Add(new ConstructedReturnType(baseRType, new List() { currentClass.DefaultReturnType })); -// +// // ambience.ConversionFlags = ConversionFlags.IncludeBody; -// +// // string a = ambience.Convert(currentClass); -// +// // int startOffset = editor.Document.PositionToOffset(currentClass.Region.BeginLine, currentClass.Region.BeginColumn); // int endOffset = editor.Document.PositionToOffset(currentClass.BodyRegion.EndLine, currentClass.BodyRegion.EndColumn); -// +// // editor.Document.Replace(startOffset, endOffset - startOffset, a); } if (Options.SurroundWithRegion) { - code.AppendLine("#region Equals and GetHashCode implementation"); + editor.Document.InsertNormalized(startAnchor.Offset, "#region Equals and GetHashCode implementation\n" + indent); } - code.Append(generator.GenerateCode(CreateGetHashCodeOverride(currentClass), indent)); + string codeForMethodBody; - code.Append("\n" + string.Join("\n", CreateEqualsOverrides(currentClass).Select(item => generator.GenerateCode(item, indent)))); + if ("Equals".Equals(selectedMethod.Name, StringComparison.Ordinal)) { + IList equalsOverrides = CreateEqualsOverrides(currentClass); + MethodDeclaration defaultOverride = equalsOverrides.First(); + equalsOverrides = equalsOverrides.Skip(1).ToList(); + + StringBuilder builder = new StringBuilder(); + + foreach (AbstractNode element in defaultOverride.Body.Children.OfType()) { + builder.Append(language.CodeGenerator.GenerateCode(element, indent + "\t")); + } + + codeForMethodBody = builder.ToString().Trim(); + + if (equalsOverrides.Any()) + code.Append(indent + "\n" + string.Join("\n", equalsOverrides.Select(item => generator.GenerateCode(item, indent)))); + code.Append(indent + "\n" + generator.GenerateCode(CreateGetHashCodeOverride(currentClass), indent)); + } else { + StringBuilder builder = new StringBuilder(); + + foreach (AbstractNode element in CreateGetHashCodeOverride(currentClass).Body.Children.OfType()) { + builder.Append(language.CodeGenerator.GenerateCode(element, indent + "\t")); + } + + codeForMethodBody = builder.ToString().Trim(); + + code.Append(indent + "\n" + string.Join("\n", CreateEqualsOverrides(currentClass).Select(item => generator.GenerateCode(item, indent)))); + } if (Options.AddOperatorOverloads) { var checkStatements = new[] { @@ -194,15 +228,17 @@ namespace SharpRefactoring.Gui } }; - code.Append("\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.Equality, currentClass, equalsOpBody), indent)); - code.Append("\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.InEquality, currentClass, notEqualsOpBody), indent)); + code.Append(indent + "\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.Equality, currentClass, equalsOpBody), indent)); + code.Append(indent + "\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.InEquality, currentClass, notEqualsOpBody), indent)); } if (Options.SurroundWithRegion) { code.AppendLine(indent + "#endregion"); } - return code.ToString(); + editor.Document.InsertNormalized(insertionEndAnchor.Offset, code.ToString()); + + return codeForMethodBody; } List CreateEqualsOverrides(IClass currentClass) @@ -357,5 +393,13 @@ namespace SharpRefactoring.Gui Body = body }; } + + protected override void CancelButtonClick(object sender, System.Windows.RoutedEventArgs e) + { + base.CancelButtonClick(sender, e); + + editor.Document.Insert(anchor.Offset, baseCall); + editor.Select(anchor.Offset, baseCall.Length); + } } } diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/OverrideEqualsGetHashCodeMethodsRefactoring.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/OverrideEqualsGetHashCodeMethodsRefactoring.cs index 3c3489e210..47f88036ef 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/OverrideEqualsGetHashCodeMethodsRefactoring.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/OverrideEqualsGetHashCodeMethodsRefactoring.cs @@ -2,6 +2,9 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.PrettyPrinter; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom.Refactoring; @@ -16,6 +19,14 @@ namespace SharpRefactoring { public void Insert(CompletionContext context, ICompletionItem item) { + if (item == null) + throw new ArgumentNullException("item"); + + if (!(item is OverrideCompletionItem)) + throw new ArgumentException("item is not an OverrideCompletionItem"); + + OverrideCompletionItem completionItem = item as OverrideCompletionItem; + ITextEditor textEditor = context.Editor; IEditorUIService uiService = textEditor.GetService(typeof(IEditorUIService)) as IEditorUIService; @@ -30,16 +41,37 @@ namespace SharpRefactoring CodeGenerator generator = parseInfo.CompilationUnit.Language.CodeGenerator; IClass current = parseInfo.CompilationUnit.GetInnermostClass(textEditor.Caret.Line, textEditor.Caret.Column); + ClassFinder finder = new ClassFinder(current, textEditor.Caret.Line, textEditor.Caret.Column); if (current == null) return; + ITextAnchor start = textEditor.Document.CreateAnchor(textEditor.Caret.Offset); + start.MovementType = AnchorMovementType.BeforeInsertion; + ITextAnchor anchor = textEditor.Document.CreateAnchor(textEditor.Caret.Offset); anchor.MovementType = AnchorMovementType.AfterInsertion; - AbstractInlineRefactorDialog dialog = new OverrideEqualsGetHashCodeMethodsDialog(textEditor, anchor, current); + IAmbience ambience = parseInfo.CompilationUnit.Language.GetAmbience(); + MethodDeclaration member = (MethodDeclaration)generator.GetOverridingMethod(completionItem.Member, finder); + + string indent = DocumentUtilitites.GetWhitespaceBefore(textEditor.Document, textEditor.Caret.Offset); + + string codeForBaseCall = generator.GenerateCode(member.Body.Children.OfType().First(), ""); + + string code = generator.GenerateCode(member, indent); + + int marker = code.IndexOf(codeForBaseCall); + + textEditor.Document.Insert(start.Offset, code.Substring(0, marker).TrimStart()); + + ITextAnchor insertionPos = textEditor.Document.CreateAnchor(anchor.Offset); + insertionPos.MovementType = AnchorMovementType.BeforeInsertion; + + AbstractInlineRefactorDialog dialog = new OverrideEqualsGetHashCodeMethodsDialog(textEditor, start, anchor, insertionPos, current, completionItem.Member as IMethod, codeForBaseCall.Trim()); + dialog.Element = uiService.CreateInlineUIElement(insertionPos, dialog); - dialog.Element = uiService.CreateInlineUIElement(anchor, dialog); + textEditor.Document.InsertNormalized(anchor.Offset, Environment.NewLine + code.Substring(marker + codeForBaseCall.Length)); } public bool Handles(ICompletionItem item)