Browse Source

Finished migration of OverrideEqualsGetHash code completion, some improvements for OverrideToString completion, too.

pull/45/merge
Andreas Weizel 12 years ago
parent
commit
e6cb26d43e
  1. 6
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 7
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs
  3. 50
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs
  4. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs
  5. 11
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/AbstractInlineRefactorDialog.cs
  6. 50
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/Options.cs
  7. 280
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs
  8. 85
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsRefactoring.cs
  9. 4
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideToStringMethodDialog.xaml.cs

6
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -73,9 +73,10 @@ @@ -73,9 +73,10 @@
<Compile Include="Src\Completion\CSharpMethodInsight.cs" />
<Compile Include="Src\Completion\ImportCompletionData.cs" />
<Compile Include="Src\Completion\OverrideCompletionData.cs" />
<Compile Include="Src\Completion\OverrideGetHashCodeCompletionData.cs" />
<Compile Include="Src\Completion\OverrideEqualsGetHashCodeCompletionData.cs" />
<Compile Include="Src\Completion\OverrideToStringCompletionData.cs" />
<Compile Include="Src\Completion\SegmentTrackingOutputFormatter.cs" />
<Compile Include="Src\CSharpTextEditorExtension.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormatter.cs" />
<Compile Include="Src\Parser\FoldingVisitor.cs" />
<Compile Include="Src\Refactoring\AbstractInlineRefactorDialog.cs" />
@ -96,6 +97,9 @@ @@ -96,6 +97,9 @@
<Compile Include="Src\Refactoring\IssueManager.cs" />
<Compile Include="Src\Refactoring\IssueOptionsViewModel.cs" />
<Compile Include="Src\Refactoring\MoveTypeToFileContextAction.cs" />
<Compile Include="Src\Refactoring\Options.cs" />
<Compile Include="Src\Refactoring\RefactoringExtensions.cs" />
<Compile Include="Src\Refactoring\RenameContextAction.cs" />
<Compile Include="Src\Refactoring\OverrideEqualsGetHashCodeMethodsDialog.xaml.cs">
<DependentUpon>OverrideEqualsGetHashCodeMethodsDialog.xaml</DependentUpon>
</Compile>

7
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs

@ -95,10 +95,11 @@ namespace CSharpBinding.Completion @@ -95,10 +95,11 @@ namespace CSharpBinding.Completion
ICompletionData ICompletionDataFactory.CreateNewOverrideCompletionData(int declarationBegin, IUnresolvedTypeDefinition type, IMember m)
{
if ((m.EntityType == EntityType.Method) && (m.Name == "ToString"))
return new OverrideToStringCompletionData(declarationBegin, m, contextAtCaret);
else if ((m.EntityType == EntityType.Method) && (m.Name == "GetHashCode"))
if ((m.SymbolKind == SymbolKind.Method) && (m.Name == "ToString"))
return new OverrideToStringCompletionData(declarationBegin, m, contextAtCaret);
else if ((m.SymbolKind == SymbolKind.Method) && ((m.Name == "GetHashCode")
|| ((m.Name == "Equals") && ((((IMethod) m)).Parameters.Count == 1) && (((IMethod) m).Parameters.First().Type.FullName == "System.Object"))))
return new OverrideEqualsGetHashCodeCompletionData(declarationBegin, m, contextAtCaret);
else
return new OverrideCompletionData(declarationBegin, m, contextAtCaret);
}

50
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideGetHashCodeCompletionData.cs → src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs

@ -26,11 +26,11 @@ using CSharpBinding.Refactoring; @@ -26,11 +26,11 @@ using CSharpBinding.Refactoring;
namespace CSharpBinding.Completion
{
/// <summary>
/// Item for 'override' completion of "GetHashCode()" methods.
/// Item for 'override' completion of "Equals()" and "GetHashCode()" methods.
/// </summary>
class OverrideGetHashCodeCompletionData : OverrideCompletionData
class OverrideEqualsGetHashCodeCompletionData : OverrideCompletionData
{
public OverrideGetHashCodeCompletionData(int declarationBegin, IMember m, CSharpTypeResolveContext contextAtCaret)
public OverrideEqualsGetHashCodeCompletionData(int declarationBegin, IMember m, CSharpTypeResolveContext contextAtCaret)
: base(declarationBegin, m, contextAtCaret)
{
}
@ -55,7 +55,7 @@ namespace CSharpBinding.Completion @@ -55,7 +55,7 @@ namespace CSharpBinding.Completion
if (!this.Entity.IsAbstract) {
// modify body to call the base method
if (this.Entity.EntityType == EntityType.Method) {
if (this.Entity.SymbolKind == SymbolKind.Method) {
var baseCall = new BaseReferenceExpression().Invoke(this.Entity.Name, new Expression[] { });
if (((IMethod)this.Entity).ReturnType.IsKnownType(KnownTypeCode.Void))
baseCallStatement = new ExpressionStatement(baseCall);
@ -88,8 +88,6 @@ namespace CSharpBinding.Completion @@ -88,8 +88,6 @@ namespace CSharpBinding.Completion
return;
}
var resolvedCurrent = typeResolveContext.CurrentTypeDefinition;
var entities = FindFieldsAndProperties(resolvedCurrent).ToList();
if (entities.Any()) {
IEditorUIService uiService = context.Editor.GetService(typeof(IEditorUIService)) as IEditorUIService;
ITextAnchor endAnchor = context.Editor.Document.CreateAnchor(context.Editor.Caret.Offset);
@ -103,46 +101,14 @@ namespace CSharpBinding.Completion @@ -103,46 +101,14 @@ namespace CSharpBinding.Completion
InsertionContext insertionContext = new InsertionContext(context.Editor.GetService(typeof(TextArea)) as TextArea, startAnchor.Offset);
// AbstractInlineRefactorDialog dialog = new OverrideToStringMethodDialog(insertionContext, context.Editor, startAnchor, insertionPos, entities, baseCallStatement);
// dialog.Element = uiService.CreateInlineUIElement(insertionPos, dialog);
var current = typeResolveContext.CurrentTypeDefinition;
AbstractInlineRefactorDialog dialog = new OverrideEqualsGetHashCodeMethodsDialog(insertionContext, context.Editor, startAnchor, endAnchor, insertionPos, current, Entity as IMethod, baseCallStatement);
dialog.Element = uiService.CreateInlineUIElement(insertionPos, dialog);
insertionContext.RegisterActiveElement(new InlineRefactorSnippetElement(cxt => null, ""), dialog);
insertionContext.RaiseInsertionCompleted(EventArgs.Empty);
}
else {
if (baseCallStatement != null) {
// Add default base call
MethodDeclaration insertedOverrideMethod = refactoringContext.GetNode().PrevSibling as MethodDeclaration;
if (insertedOverrideMethod == null)
{
// We are not inside of a method declaration
return;
}
using (Script script = refactoringContext.StartScript()) {
script.AddTo(insertedOverrideMethod.Body, baseCallStatement);
}
}
}
}
}
IEnumerable<PropertyOrFieldWrapper> FindFieldsAndProperties(IType sourceType)
{
int i = 0;
foreach (var f in sourceType.GetFields().Where(field => !field.IsConst
&& field.IsStatic == sourceType.GetDefinition().IsStatic
&& field.ReturnType != null)) {
yield return new PropertyOrFieldWrapper(f) { Index = i };
i++;
}
foreach (var p in sourceType.GetProperties().Where(prop => prop.CanGet && !prop.IsIndexer
&& prop.IsStatic == sourceType.GetDefinition().IsStatic
&& prop.ReturnType != null)) {
yield return new PropertyOrFieldWrapper(p) { Index = i };
i++;
}
}
}
}

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs

@ -55,7 +55,7 @@ namespace CSharpBinding.Completion @@ -55,7 +55,7 @@ namespace CSharpBinding.Completion
if (!this.Entity.IsAbstract) {
// modify body to call the base method
if (this.Entity.EntityType == EntityType.Method) {
if (this.Entity.SymbolKind == SymbolKind.Method) {
var baseCall = new BaseReferenceExpression().Invoke(this.Entity.Name, new Expression[] { });
if (((IMethod)this.Entity).ReturnType.IsKnownType(KnownTypeCode.Void))
baseCallStatement = new ExpressionStatement(baseCall);

11
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/AbstractInlineRefactorDialog.cs

@ -12,6 +12,7 @@ using System.Windows.Threading; @@ -12,6 +12,7 @@ using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.Core.Presentation;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser;
@ -93,6 +94,16 @@ namespace CSharpBinding.Refactoring @@ -93,6 +94,16 @@ namespace CSharpBinding.Refactoring
optionBindings.Add(binding);
}
protected AstType ConvertType(KnownTypeCode knownTypeCode)
{
IType type = refactoringContext.Compilation.FindType(knownTypeCode);
if (type != null)
return ConvertType(type);
// Backup solution
return new SimpleType(KnownTypeReference.GetCSharpNameByTypeCode(knownTypeCode));
}
protected AstType ConvertType(IType type)
{
return refactoringContext.CreateShortType(type);

50
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/Options.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace CSharpBinding.Refactoring
{
/// <summary>
/// Description of Options.
/// </summary>
public static class Options
{
static Properties properties;
public static Properties Properties {
get {
Debug.Assert(properties != null);
return properties;
}
}
static Options()
{
properties = SD.PropertyService.Get("SharpRefactoringOptions", new Properties());
}
public static bool AddIEquatableInterface {
get { return properties.Get("AddIEquatableInterface", false); }
set { properties.Set("AddIEquatableInterface", value); }
}
public static bool AddOtherMethod {
get { return properties.Get("AddOtherMethod", true); }
set { properties.Set("AddOtherMethod", value); }
}
public static bool SurroundWithRegion {
get { return properties.Get("SurroundWithRegion", true); }
set { properties.Set("SurroundWithRegion", value); }
}
public static bool AddOperatorOverloads {
get { return properties.Get("AddOperatorOverloads", true); }
set { properties.Set("AddOperatorOverloads", value); }
}
}
}

280
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -9,11 +10,9 @@ using System.Text; @@ -9,11 +10,9 @@ using System.Text;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using Dom = ICSharpCode.SharpDevelop.Dom;
@ -24,13 +23,13 @@ namespace CSharpBinding.Refactoring @@ -24,13 +23,13 @@ namespace CSharpBinding.Refactoring
/// </summary>
public partial class OverrideEqualsGetHashCodeMethodsDialog : AbstractInlineRefactorDialog
{
IType selectedClass;
ITypeDefinition selectedClass;
ITextAnchor startAnchor;
IMethod selectedMethod;
AstNode baseCallNode;
public OverrideEqualsGetHashCodeMethodsDialog(InsertionContext context, ITextEditor editor, ITextAnchor startAnchor, ITextAnchor endAnchor,
ITextAnchor insertionPosition, IType selectedClass, IMethod selectedMethod, AstNode baseCallNode)
ITextAnchor insertionPosition, ITypeDefinition selectedClass, IMethod selectedMethod, AstNode baseCallNode)
: base(context, editor, insertionPosition)
{
if (selectedClass == null)
@ -51,15 +50,19 @@ namespace CSharpBinding.Refactoring @@ -51,15 +50,19 @@ namespace CSharpBinding.Refactoring
addOtherMethod.Content = StringParser.Parse("${res:AddIns.SharpRefactoring.OverrideEqualsGetHashCodeMethods.AddOtherMethod}", new StringTagPair("otherMethod", otherMethod));
addIEquatable.IsEnabled = !selectedClass.BaseTypes.Any(
addIEquatable.IsEnabled = !selectedClass.GetAllBaseTypes().Any(
type => {
if (!type.IsGenericReturnType)
if (!type.IsParameterized || (type.TypeParameterCount != 1))
return false;
var genericType = type.CastToGenericReturnType();
var boundTo = genericType.TypeParameter.BoundTo;
if (boundTo == null)
if (type.FullName != "System.IEquatable")
return false;
return boundTo.Name == selectedClass.Name;
return type.TypeArguments.First().FullName == selectedClass.FullName;
// var genericType = type.CastToGenericReturnType();
// var boundTo = genericType.TypeParameter.BoundTo;
// if (boundTo == null)
// return false;
// return boundTo.Name == selectedClass.Name;
}
);
}
@ -82,11 +85,11 @@ namespace CSharpBinding.Refactoring @@ -82,11 +85,11 @@ namespace CSharpBinding.Refactoring
return type != null
&& type.FullName != "System.Single"
&& type.FullName != "System.Double"
&& (!type.IsReferenceType
&& (!IsReferenceType(type)
|| type.FullName == "System.String");
}
static Expression TestEquality(string other, IField field)
Expression TestEquality(string other, IField field)
{
if (CanCompareEqualityWithOperator(field.ReturnType)) {
return new BinaryOperatorExpression(new MemberReferenceExpression(new ThisReferenceExpression(), field.Name),
@ -94,7 +97,7 @@ namespace CSharpBinding.Refactoring @@ -94,7 +97,7 @@ namespace CSharpBinding.Refactoring
new MemberReferenceExpression(new IdentifierExpression(other), field.Name));
} else {
InvocationExpression ie = new InvocationExpression(
new MemberReferenceExpression(new TypeReferenceExpression(new TypeReference("System.Object", true)), "Equals")
new MemberReferenceExpression(new TypeReferenceExpression(ConvertType(KnownTypeCode.Object)), "Equals")
);
ie.Arguments.Add(new MemberReferenceExpression(new ThisReferenceExpression(), field.Name));
ie.Arguments.Add(new MemberReferenceExpression(new IdentifierExpression(other), field.Name));
@ -102,7 +105,7 @@ namespace CSharpBinding.Refactoring @@ -102,7 +105,7 @@ namespace CSharpBinding.Refactoring
}
}
static Expression TestEquality(string other, IProperty property)
Expression TestEquality(string other, IProperty property)
{
if (CanCompareEqualityWithOperator(property.ReturnType)) {
return new BinaryOperatorExpression(new MemberReferenceExpression(new ThisReferenceExpression(), property.Name),
@ -110,7 +113,7 @@ namespace CSharpBinding.Refactoring @@ -110,7 +113,7 @@ namespace CSharpBinding.Refactoring
new MemberReferenceExpression(new IdentifierExpression(other), property.Name));
} else {
InvocationExpression ie = new InvocationExpression(
new MemberReferenceExpression(new TypeReferenceExpression(new SimpleType("System.Object")), "Equals")
new MemberReferenceExpression(new TypeReferenceExpression(ConvertType(KnownTypeCode.Object)), "Equals")
);
ie.Arguments.Add(new MemberReferenceExpression(new ThisReferenceExpression(), property.Name));
ie.Arguments.Add(new MemberReferenceExpression(new IdentifierExpression(other), property.Name));
@ -118,6 +121,15 @@ namespace CSharpBinding.Refactoring @@ -118,6 +121,15 @@ namespace CSharpBinding.Refactoring
}
}
static bool IsReferenceType(IType type)
{
if (type.IsReferenceType.HasValue) {
return type.IsReferenceType.Value;
}
return false;
}
protected override string GenerateCode(ITypeDefinition currentClass)
{
StringBuilder code = new StringBuilder();
@ -126,7 +138,17 @@ namespace CSharpBinding.Refactoring @@ -126,7 +138,17 @@ namespace CSharpBinding.Refactoring
string indent = DocumentUtilitites.GetWhitespaceAfter(editor.Document, line.Offset);
CodeGenerator generator = language.CodeGenerator;
// CodeGenerator generator = language.CodeGenerator;
MethodDeclaration insertedOverrideMethod = refactoringContext.GetNode().PrevSibling as MethodDeclaration;
if (insertedOverrideMethod == null)
{
// We are not inside of a method declaration
return null;
}
using (Script script = refactoringContext.StartScript()) {
NewLineNode nextNewLineNode = insertedOverrideMethod.NextSibling as NewLineNode;
// if (Options.AddIEquatableInterface) {
// TODO : add IEquatable<T> to class
@ -154,40 +176,44 @@ namespace CSharpBinding.Refactoring @@ -154,40 +176,44 @@ namespace CSharpBinding.Refactoring
// }
if (Options.SurroundWithRegion) {
editor.Document.InsertNormalized(startAnchor.Offset, "#region Equals and GetHashCode implementation\n" + indent);
script.InsertBefore(insertedOverrideMethod, new PreProcessorDirective(PreProcessorDirectiveType.Region, "Equals and GetHashCode implementation"));
}
string codeForMethodBody;
if ("Equals".Equals(selectedMethod.Name, StringComparison.Ordinal)) {
IList<MethodDeclaration> equalsOverrides = CreateEqualsOverrides(currentClass);
MethodDeclaration defaultOverride = equalsOverrides.First();
equalsOverrides = equalsOverrides.Skip(1).ToList();
StringBuilder builder = new StringBuilder();
foreach (AbstractNode element in defaultOverride.Body.Children.OfType<AbstractNode>()) {
builder.Append(language.CodeGenerator.GenerateCode(element, indent + "\t"));
// Insert children of default Equals method into
foreach (AstNode element in defaultOverride.Body.Children) {
script.AddTo(insertedOverrideMethod.Body, element.Clone());
}
codeForMethodBody = builder.ToString().Trim();
// Add other Equals() overrides after our main inserted method
if (addOtherMethod.IsChecked == true) {
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));
if (equalsOverrides.Any()) {
foreach (var equalsMethod in equalsOverrides) {
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, equalsMethod);
}
}
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, CreateGetHashCodeOverride(currentClass));
}
} else {
StringBuilder builder = new StringBuilder();
foreach (AbstractNode element in CreateGetHashCodeOverride(currentClass).Body.Children.OfType<AbstractNode>()) {
builder.Append(language.CodeGenerator.GenerateCode(element, indent + "\t"));
foreach (AstNode element in CreateGetHashCodeOverride(currentClass).Body.Children) {
script.AddTo(insertedOverrideMethod.Body, element.Clone());
}
codeForMethodBody = builder.ToString().Trim();
if (addOtherMethod.IsChecked == true)
code.Append(indent + "\n" + string.Join("\n", CreateEqualsOverrides(currentClass).Select(item => generator.GenerateCode(item, indent))));
if (addOtherMethod.IsChecked == true) {
foreach (var equalsMethod in CreateEqualsOverrides(currentClass)) {
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, equalsMethod);
}
}
}
if (Options.AddOperatorOverloads) {
@ -205,7 +231,7 @@ namespace CSharpBinding.Refactoring @@ -205,7 +231,7 @@ namespace CSharpBinding.Refactoring
new IdentifierExpression("ReferenceEquals"),
new List<Expression>() { new IdentifierExpression("lhs"), new PrimitiveExpression(null) }
),
BinaryOperatorType.LogicalOr,
BinaryOperatorType.ConditionalOr,
new InvocationExpression(
new IdentifierExpression("ReferenceEquals"),
new List<Expression>() { new IdentifierExpression("rhs"), new PrimitiveExpression(null) }
@ -215,57 +241,65 @@ namespace CSharpBinding.Refactoring @@ -215,57 +241,65 @@ namespace CSharpBinding.Refactoring
)
};
BlockStatement equalsOpBody = new BlockStatement() {
Children = {
BlockStatement equalsOpBody = new BlockStatement();
if (currentClass.Kind == TypeKind.Class) {
foreach (var statement in checkStatements) {
equalsOpBody.Add(statement);
}
}
equalsOpBody.Add(
new ReturnStatement(
new InvocationExpression(
new MemberReferenceExpression(new IdentifierExpression("lhs"), "Equals"),
new List<Expression>() { new IdentifierExpression("rhs") }
)
)
}
};
if (currentClass.ClassType == Dom.ClassType.Class) {
equalsOpBody.Children.InsertRange(0, checkStatements);
}
);
BlockStatement notEqualsOpBody = new BlockStatement() {
Children = {
new ReturnStatement(
BlockStatement notEqualsOpBody = new BlockStatement();
notEqualsOpBody.Add(new ReturnStatement(
new UnaryOperatorExpression(
UnaryOperatorType.Not,
new ParenthesizedExpression(
new BinaryOperatorExpression(
new IdentifierExpression("lhs"),
BinaryOperatorType.Equality,
new IdentifierExpression("rhs")
)
),
UnaryOperatorType.Not
)
)
}
};
)
);
code.Append(indent + "\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.Equality, currentClass, equalsOpBody), indent));
code.Append(indent + "\n" + generator.GenerateCode(CreateOperatorOverload(OverloadableOperatorType.InEquality, currentClass, notEqualsOpBody), indent));
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, CreateOperatorOverload(OperatorType.Equality, currentClass, equalsOpBody));
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, CreateOperatorOverload(OperatorType.Inequality, currentClass, notEqualsOpBody));
}
if (Options.SurroundWithRegion) {
code.AppendLine(indent + "#endregion");
AppendNewLine(script, insertedOverrideMethod, nextNewLineNode);
script.InsertAfter(insertedOverrideMethod, new PreProcessorDirective(PreProcessorDirectiveType.Endregion));
}
}
editor.Document.InsertNormalized(insertionEndAnchor.Offset, code.ToString());
return null;
}
return codeForMethodBody;
void AppendNewLine(Script script, AstNode afterNode, NewLineNode newLineNode)
{
if (newLineNode != null)
script.InsertAfter(afterNode, newLineNode.Clone());
}
List<MethodDeclaration> CreateEqualsOverrides(IType currentClass)
{
List<MethodDeclaration> methods = new List<MethodDeclaration>();
AstType boolReference = new SimpleType("System.Boolean");
AstType objectReference = new SimpleType("System.Object", true);
AstType boolReference = ConvertType(KnownTypeCode.Boolean);
AstType objectReference = ConvertType(KnownTypeCode.Object);
MethodDeclaration method = new MethodDeclaration {
Name = "Equals",
@ -275,22 +309,24 @@ namespace CSharpBinding.Refactoring @@ -275,22 +309,24 @@ namespace CSharpBinding.Refactoring
method.Parameters.Add(new ParameterDeclaration(objectReference, "obj"));
method.Body = new BlockStatement();
AstType currentType = ConvertType(currentClass.DefaultReturnType);
AstType currentType = ConvertType(currentClass);
Expression expr = null;
if (currentClass.ClassType == Dom.ClassType.Struct) {
if (currentClass.Kind == TypeKind.Struct) {
// return obj is CurrentType && Equals((CurrentType)obj);
expr = new IsExpression(new IdentifierExpression("obj"), currentType);
expr = new IsExpression() {
Expression = new IdentifierExpression("obj"),
Type = currentType.Clone()
};
expr = new ParenthesizedExpression(expr);
expr = new BinaryOperatorExpression(
expr, BinaryOperatorType.LogicalAnd,
expr, BinaryOperatorType.ConditionalAnd,
new InvocationExpression(
new IdentifierExpression("Equals"),
new List<Expression> {
new CastExpression(currentType, new IdentifierExpression("obj"), CastType.Cast)
new CastExpression(currentType.Clone(), new IdentifierExpression("obj"))
}));
method.Body.AddChild(new ReturnStatement(expr));
method.Body.Add(new ReturnStatement(expr));
methods.Add(method);
@ -298,141 +334,132 @@ namespace CSharpBinding.Refactoring @@ -298,141 +334,132 @@ namespace CSharpBinding.Refactoring
method = new MethodDeclaration {
Name = "Equals",
Modifiers = Modifiers.Public,
ReturnType = boolReference
ReturnType = boolReference.Clone()
};
method.Parameters.Add(new ParameterDeclaration(currentType, "other"));
method.Body = new BlockStatement();
} else {
method.Body.AddChild(new VariableDeclaration(
method.Body.Add(new VariableDeclarationStatement(
currentType.Clone(),
"other",
new CastExpression(currentType, new IdentifierExpression("obj")),
currentType));
method.Body.AddChild(new IfElseStatement(
new CastExpression(currentType.Clone(), new IdentifierExpression("obj"))));
method.Body.Add(new IfElseStatement(
new BinaryOperatorExpression(new IdentifierExpression("other"), BinaryOperatorType.Equality, new PrimitiveExpression(null, "null")),
new ReturnStatement(new PrimitiveExpression(false, "false"))));
// expr = new BinaryOperatorExpression(new ThisReferenceExpression(),
// BinaryOperatorType.ReferenceEquality,
// new IdentifierExpression("obj"));
// method.Body.AddChild(new IfElseStatement(expr, new ReturnStatement(new PrimitiveExpression(true, "true"))));
}
expr = null;
foreach (IField field in currentClass.Fields) {
foreach (IField field in currentClass.GetFields()) {
if (field.IsStatic) continue;
if (expr == null) {
expr = TestEquality("other", field);
} else {
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.LogicalAnd,
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.ConditionalAnd,
TestEquality("other", field));
}
}
foreach (IProperty property in currentClass.Properties) {
foreach (IProperty property in currentClass.GetProperties()) {
if (property.IsStatic || !property.IsAutoImplemented()) continue;
if (expr == null) {
expr = TestEquality("other", property);
} else {
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.LogicalAnd,
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.ConditionalAnd,
TestEquality("other", property));
}
}
method.Body.AddChild(new ReturnStatement(expr ?? new PrimitiveExpression(true, "true")));
method.Body.Add(new ReturnStatement(expr ?? new PrimitiveExpression(true, "true")));
methods.Add(method);
return methods;
}
MethodDeclaration CreateGetHashCodeOverride(IClass currentClass)
MethodDeclaration CreateGetHashCodeOverride(ITypeDefinition currentClass)
{
TypeReference intReference = new TypeReference("System.Int32", true);
VariableDeclaration hashCodeVar = new VariableDeclaration("hashCode", new PrimitiveExpression(0, "0"), intReference);
const string hashCodeVarName = "hashCode";
AstType intReference = ConvertType(KnownTypeCode.Int32);
VariableDeclarationStatement hashCodeVar = new VariableDeclarationStatement(intReference, hashCodeVarName, new PrimitiveExpression(0, "0"));
// Create new method declaration (to insert after main inserted method)
MethodDeclaration getHashCodeMethod = new MethodDeclaration {
Name = "GetHashCode",
Modifier = Modifiers.Public | Modifiers.Override,
TypeReference = intReference,
Modifiers = Modifiers.Public | Modifiers.Override,
ReturnType = intReference.Clone(),
Body = new BlockStatement()
};
getHashCodeMethod.Body.AddChild(new LocalVariableDeclaration(hashCodeVar));
getHashCodeMethod.Body.Add(hashCodeVar);
if (currentClass.Fields.Any(f => !f.IsStatic) || currentClass.Properties.Any(p => !p.IsStatic && p.IsAutoImplemented())) {
bool usePrimeMultiplication = currentClass.ProjectContent.Language == LanguageProperties.CSharp;
BlockStatement hashCalculationBlock;
if (usePrimeMultiplication) {
hashCalculationBlock = new BlockStatement();
getHashCodeMethod.Body.AddChild(new UncheckedStatement(hashCalculationBlock));
} else {
hashCalculationBlock = getHashCodeMethod.Body;
}
bool usePrimeMultiplication = true; // Always leave true for C#?
BlockStatement hashCalculationBlock = new BlockStatement();
getHashCodeMethod.Body.Add(new UncheckedStatement(hashCalculationBlock));
// hashCalculationBlock = getHashCodeMethod.Body;
int fieldIndex = 0;
foreach (IField field in currentClass.Fields) {
if (field.IsStatic) continue;
AddToBlock(hashCodeVar, getHashCodeMethod, usePrimeMultiplication, hashCalculationBlock, ref fieldIndex, field);
AddToBlock(hashCodeVarName, usePrimeMultiplication, hashCalculationBlock, ref fieldIndex, field);
}
foreach (IProperty property in currentClass.Properties) {
if (property.IsStatic || !property.IsAutoImplemented()) continue;
AddToBlock(hashCodeVar, getHashCodeMethod, usePrimeMultiplication, hashCalculationBlock, ref fieldIndex, property);
AddToBlock(hashCodeVarName, usePrimeMultiplication, hashCalculationBlock, ref fieldIndex, property);
}
}
getHashCodeMethod.Body.AddChild(new ReturnStatement(new IdentifierExpression(hashCodeVar.Name)));
getHashCodeMethod.Body.Add(new ReturnStatement(new IdentifierExpression(hashCodeVarName)));
return getHashCodeMethod;
}
void AddToBlock(VariableDeclaration hashCodeVar, MethodDeclaration getHashCodeMethod, bool usePrimeMultiplication, BlockStatement hashCalculationBlock, ref int fieldIndex, IField field)
void AddToBlock(string hashCodeVarName, bool usePrimeMultiplication, BlockStatement hashCalculationBlock, ref int fieldIndex, IField field)
{
Expression expr = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression(field.Name), "GetHashCode"));
if (usePrimeMultiplication) {
int prime = largePrimes[fieldIndex++ % largePrimes.Length];
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVar.Name), AssignmentOperatorType.Add, new BinaryOperatorExpression(new PrimitiveExpression(prime, prime.ToString()), BinaryOperatorType.Multiply, expr));
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVarName), AssignmentOperatorType.Add, new BinaryOperatorExpression(new PrimitiveExpression(prime, prime.ToString()), BinaryOperatorType.Multiply, expr));
} else {
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVar.Name), AssignmentOperatorType.ExclusiveOr, expr);
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVarName), AssignmentOperatorType.ExclusiveOr, expr);
}
if (IsValueType(field.ReturnType)) {
hashCalculationBlock.AddChild(new ExpressionStatement(expr));
if (IsReferenceType(field.ReturnType)) {
hashCalculationBlock.Add(new IfElseStatement(new BinaryOperatorExpression(new IdentifierExpression(field.Name), BinaryOperatorType.InEquality, new PrimitiveExpression(null, "null")), new ExpressionStatement(expr)));
} else {
hashCalculationBlock.AddChild(new IfElseStatement(new BinaryOperatorExpression(new IdentifierExpression(field.Name), BinaryOperatorType.ReferenceInequality, new PrimitiveExpression(null, "null")), new ExpressionStatement(expr)));
hashCalculationBlock.Add(new ExpressionStatement(expr));
}
}
void AddToBlock(VariableDeclaration hashCodeVar, MethodDeclaration getHashCodeMethod, bool usePrimeMultiplication, BlockStatement hashCalculationBlock, ref int fieldIndex, IProperty property)
void AddToBlock(string hashCodeVarName, bool usePrimeMultiplication, BlockStatement hashCalculationBlock, ref int fieldIndex, IProperty property)
{
Expression expr = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression(property.Name), "GetHashCode"));
if (usePrimeMultiplication) {
int prime = largePrimes[fieldIndex++ % largePrimes.Length];
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVar.Name), AssignmentOperatorType.Add, new BinaryOperatorExpression(new PrimitiveExpression(prime, prime.ToString()), BinaryOperatorType.Multiply, expr));
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVarName), AssignmentOperatorType.Add, new BinaryOperatorExpression(new PrimitiveExpression(prime, prime.ToString()), BinaryOperatorType.Multiply, expr));
} else {
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVar.Name), AssignmentOperatorType.ExclusiveOr, expr);
expr = new AssignmentExpression(new IdentifierExpression(hashCodeVarName), AssignmentOperatorType.ExclusiveOr, expr);
}
if (IsValueType(property.ReturnType)) {
hashCalculationBlock.AddChild(new ExpressionStatement(expr));
if (IsReferenceType(property.ReturnType)) {
hashCalculationBlock.Add(new IfElseStatement(new BinaryOperatorExpression(new IdentifierExpression(property.Name), BinaryOperatorType.InEquality, new PrimitiveExpression(null, "null")), new ExpressionStatement(expr)));
} else {
hashCalculationBlock.AddChild(new IfElseStatement(new BinaryOperatorExpression(new IdentifierExpression(property.Name), BinaryOperatorType.ReferenceInequality, new PrimitiveExpression(null, "null")), new ExpressionStatement(expr)));
hashCalculationBlock.Add(new ExpressionStatement(expr));
}
}
OperatorDeclaration CreateOperatorOverload(OverloadableOperatorType op, IClass currentClass, BlockStatement body)
OperatorDeclaration CreateOperatorOverload(OperatorType op, ITypeDefinition currentClass, BlockStatement body)
{
return new OperatorDeclaration() {
OverloadableOperator = op,
TypeReference = new TypeReference("System.Boolean", true),
OperatorType = op,
ReturnType = ConvertType(KnownTypeCode.Boolean),
Parameters = {
new ParameterDeclarationExpression(ConvertType(currentClass.DefaultReturnType), "lhs"),
new ParameterDeclarationExpression(ConvertType(currentClass.DefaultReturnType), "rhs")
new ParameterDeclaration(ConvertType(currentClass), "lhs"),
new ParameterDeclaration(ConvertType(currentClass), "rhs")
},
Modifier = Modifiers.Public | Modifiers.Static,
Modifiers = Modifiers.Public | Modifiers.Static,
Body = body
};
}
@ -441,15 +468,28 @@ namespace CSharpBinding.Refactoring @@ -441,15 +468,28 @@ namespace CSharpBinding.Refactoring
{
base.CancelButtonClick(sender, e);
editor.Document.Insert(anchor.Offset, baseCall);
editor.Select(anchor.Offset, baseCall.Length);
// editor.Document.Insert(anchor.Offset, baseCall);
// editor.Select(anchor.Offset, baseCall.Length);
if (baseCallNode != null) {
// Insert at least the base call
MethodDeclaration insertedOverrideMethod = refactoringContext.GetNode().PrevSibling as MethodDeclaration;
if (insertedOverrideMethod == null)
{
// We are not inside of a method declaration
return;
}
using (Script script = refactoringContext.StartScript()) {
script.AddTo(insertedOverrideMethod.Body, baseCallNode);
}
}
}
protected override void OKButtonClick(object sender, System.Windows.RoutedEventArgs e)
{
base.OKButtonClick(sender, e);
editor.Caret.Offset = insertionEndAnchor.Offset;
// editor.Caret.Offset = insertionEndAnchor.Offset;
}
}
}

85
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsRefactoring.cs

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Linq;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using SharpRefactoring.Gui;
namespace SharpRefactoring
{
public class OverrideEqualsGetHashCodeMethodsRefactoring : ICompletionItemHandler
{
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;
if (uiService == null)
return;
ParseInformation parseInfo = ParserService.GetParseInformation(textEditor.FileName);
if (parseInfo == null)
return;
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;
using (textEditor.Document.OpenUndoGroup()) {
ITextAnchor startAnchor = textEditor.Document.CreateAnchor(textEditor.Caret.Offset);
startAnchor.MovementType = AnchorMovementType.BeforeInsertion;
ITextAnchor endAnchor = textEditor.Document.CreateAnchor(textEditor.Caret.Offset);
endAnchor.MovementType = AnchorMovementType.AfterInsertion;
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<AbstractNode>().First(), "");
string code = generator.GenerateCode(member, indent);
int marker = code.IndexOf(codeForBaseCall);
textEditor.Document.Insert(startAnchor.Offset, code.Substring(0, marker).TrimStart());
ITextAnchor insertionPos = textEditor.Document.CreateAnchor(endAnchor.Offset);
insertionPos.MovementType = AnchorMovementType.BeforeInsertion;
InsertionContext insertionContext = new InsertionContext(textEditor.GetService(typeof(TextArea)) as TextArea, startAnchor.Offset);
AbstractInlineRefactorDialog dialog = new OverrideEqualsGetHashCodeMethodsDialog(insertionContext, textEditor, startAnchor, endAnchor, insertionPos, current, completionItem.Member as IMethod, codeForBaseCall.Trim());
dialog.Element = uiService.CreateInlineUIElement(insertionPos, dialog);
textEditor.Document.InsertNormalized(endAnchor.Offset, Environment.NewLine + code.Substring(marker + codeForBaseCall.Length));
insertionContext.RegisterActiveElement(new InlineRefactorSnippetElement(cxt => null, ""), dialog);
insertionContext.RaiseInsertionCompleted(EventArgs.Empty);
}
}
public bool Handles(ICompletionItem item)
{
return item is OverrideCompletionItem && (item.Text == "GetHashCode()" || item.Text == "Equals(object obj)");
}
}
}

4
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideToStringMethodDialog.xaml.cs

@ -25,7 +25,6 @@ namespace CSharpBinding.Refactoring @@ -25,7 +25,6 @@ namespace CSharpBinding.Refactoring
{
AstNode baseCallNode;
string insertedCode;
ITextEditor editor;
public OverrideToStringMethodDialog(InsertionContext context, ITextEditor editor, ITextAnchor startAnchor, ITextAnchor anchor, IList<PropertyOrFieldWrapper> fields, AstNode baseCallNode)
: base(context, editor, anchor)
@ -34,7 +33,6 @@ namespace CSharpBinding.Refactoring @@ -34,7 +33,6 @@ namespace CSharpBinding.Refactoring
this.baseCallNode = baseCallNode;
this.listBox.ItemsSource = fields;
this.editor = editor;
listBox.SelectAll();
}
@ -45,7 +43,7 @@ namespace CSharpBinding.Refactoring @@ -45,7 +43,7 @@ namespace CSharpBinding.Refactoring
PrimitiveExpression formatString = new PrimitiveExpression(GenerateFormatString(currentClass, editor.Language.CodeGenerator, fields));
List<Expression> param = new List<Expression>() { formatString };
ReturnStatement ret = new ReturnStatement(new InvocationExpression(
new MemberReferenceExpression(new TypeReferenceExpression(new SimpleType("System.String")), "Format"),
new MemberReferenceExpression(new TypeReferenceExpression(ConvertType(KnownTypeCode.String)), "Format"),
param.Concat(fields.Select(f => new IdentifierExpression(f))).ToList()
));

Loading…
Cancel
Save