Browse Source

GetHashCode override completion - work in progress.

pull/45/merge
Andreas Weizel 12 years ago
parent
commit
3e382df48d
  1. 5
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionDataFactory.cs
  3. 148
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideGetHashCodeCompletionData.cs
  4. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/AbstractInlineRefactorDialog.cs
  5. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs
  6. 71
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs
  7. 4
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideToStringMethodDialog.xaml.cs

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

@ -73,6 +73,7 @@ @@ -73,6 +73,7 @@
<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\OverrideToStringCompletionData.cs" />
<Compile Include="Src\Completion\SegmentTrackingOutputFormatter.cs" />
<Compile Include="Src\FormattingStrategy\CSharpFormatter.cs" />
@ -95,6 +96,9 @@ @@ -95,6 +96,9 @@
<Compile Include="Src\Refactoring\IssueManager.cs" />
<Compile Include="Src\Refactoring\IssueOptionsViewModel.cs" />
<Compile Include="Src\Refactoring\MoveTypeToFileContextAction.cs" />
<Compile Include="Src\Refactoring\OverrideEqualsGetHashCodeMethodsDialog.xaml.cs">
<DependentUpon>OverrideEqualsGetHashCodeMethodsDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Refactoring\OverrideToStringMethodDialog.xaml.cs">
<DependentUpon>OverrideToStringMethodDialog.xaml</DependentUpon>
</Compile>
@ -196,6 +200,7 @@ @@ -196,6 +200,7 @@
<Page Include="Src\Refactoring\InsertCtorDialog.xaml" />
<Page Include="Src\Refactoring\IssueOptions.xaml" />
<Page Include="Src\OptionPanels\BuildOptions.xaml" />
<Page Include="Src\Refactoring\OverrideEqualsGetHashCodeMethodsDialog.xaml" />
<Page Include="Src\Refactoring\OverrideToStringMethodDialog.xaml" />
<Page Include="Src\Refactoring\SearchForIssuesDialog.xaml" />
</ItemGroup>

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

@ -97,6 +97,8 @@ namespace CSharpBinding.Completion @@ -97,6 +97,8 @@ namespace CSharpBinding.Completion
{
if ((m.EntityType == EntityType.Method) && (m.Name == "ToString"))
return new OverrideToStringCompletionData(declarationBegin, m, contextAtCaret);
else if ((m.EntityType == EntityType.Method) && (m.Name == "GetHashCode"))
return new OverrideToStringCompletionData(declarationBegin, m, contextAtCaret);
else
return new OverrideCompletionData(declarationBegin, m, contextAtCaret);
}

148
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideGetHashCodeCompletionData.cs

@ -0,0 +1,148 @@ @@ -0,0 +1,148 @@
// 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.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop.Parser;
using CSharpBinding.FormattingStrategy;
using CSharpBinding.Parser;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using CSharpBinding.Refactoring;
namespace CSharpBinding.Completion
{
/// <summary>
/// Item for 'override' completion of "GetHashCode()" methods.
/// </summary>
class OverrideGetHashCodeCompletionData : OverrideCompletionData
{
public OverrideGetHashCodeCompletionData(int declarationBegin, IMember m, CSharpTypeResolveContext contextAtCaret)
: base(declarationBegin, m, contextAtCaret)
{
}
public override void Complete(CompletionContext context)
{
if (declarationBegin > context.StartOffset) {
base.Complete(context);
return;
}
TypeSystemAstBuilder b = new TypeSystemAstBuilder(new CSharpResolver(contextAtCaret));
b.ShowTypeParameterConstraints = false;
b.GenerateBody = true;
var entityDeclaration = b.ConvertEntity(this.Entity);
entityDeclaration.Modifiers &= ~(Modifiers.Virtual | Modifiers.Abstract);
entityDeclaration.Modifiers |= Modifiers.Override;
var body = entityDeclaration.GetChildByRole(Roles.Body);
Statement baseCallStatement = body.Children.OfType<Statement>().FirstOrDefault();
if (!this.Entity.IsAbstract) {
// modify body to call the base method
if (this.Entity.EntityType == EntityType.Method) {
var baseCall = new BaseReferenceExpression().Invoke(this.Entity.Name, new Expression[] { });
if (((IMethod)this.Entity).ReturnType.IsKnownType(KnownTypeCode.Void))
baseCallStatement = new ExpressionStatement(baseCall);
else
baseCallStatement = new ReturnStatement(baseCall);
// Clear body of inserted method
entityDeclaration.GetChildByRole(Roles.Body).Statements.Clear();
}
}
var document = context.Editor.Document;
StringWriter w = new StringWriter();
var formattingOptions = FormattingOptionsFactory.CreateSharpDevelop();
var segmentDict = SegmentTrackingOutputFormatter.WriteNode(w, entityDeclaration, formattingOptions, context.Editor.Options);
using (document.OpenUndoGroup()) {
string newText = w.ToString().TrimEnd();
document.Replace(declarationBegin, context.EndOffset - declarationBegin, newText);
var throwStatement = entityDeclaration.Descendants.FirstOrDefault(n => n is ThrowStatement);
if (throwStatement != null) {
var segment = segmentDict[throwStatement];
context.Editor.Select(declarationBegin + segment.Offset, segment.Length);
}
CSharpFormatterHelper.Format(context.Editor, declarationBegin, newText.Length, formattingOptions);
var refactoringContext = SDRefactoringContext.Create(context.Editor, CancellationToken.None);
var typeResolveContext = refactoringContext.GetTypeResolveContext();
if (typeResolveContext == null) {
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);
endAnchor.MovementType = AnchorMovementType.AfterInsertion;
ITextAnchor startAnchor = context.Editor.Document.CreateAnchor(context.Editor.Caret.Offset);
startAnchor.MovementType = AnchorMovementType.BeforeInsertion;
ITextAnchor insertionPos = context.Editor.Document.CreateAnchor(endAnchor.Offset);
insertionPos.MovementType = AnchorMovementType.BeforeInsertion;
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);
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++;
}
}
}
}

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

@ -50,7 +50,7 @@ namespace CSharpBinding.Refactoring @@ -50,7 +50,7 @@ namespace CSharpBinding.Refactoring
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(delegate { this.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); }));
}
protected abstract string GenerateCode(IUnresolvedTypeDefinition currentClass);
protected abstract string GenerateCode(ITypeDefinition currentClass);
protected virtual void OKButtonClick(object sender, RoutedEventArgs e)
{
@ -62,7 +62,11 @@ namespace CSharpBinding.Refactoring @@ -62,7 +62,11 @@ namespace CSharpBinding.Refactoring
}
if (parseInfo != null) {
IUnresolvedTypeDefinition current = parseInfo.UnresolvedFile.GetInnermostTypeDefinition(anchor.Line, anchor.Column);
var typeResolveContext = refactoringContext.GetTypeResolveContext();
if (typeResolveContext == null) {
return;
}
var current = typeResolveContext.CurrentTypeDefinition;
using (editor.Document.OpenUndoGroup()) {
// GenerateCode could modify the document.

2
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs

@ -41,7 +41,7 @@ namespace CSharpBinding.Refactoring @@ -41,7 +41,7 @@ namespace CSharpBinding.Refactoring
Visibility = System.Windows.Visibility.Collapsed;
}
protected override string GenerateCode(IUnresolvedTypeDefinition currentClass)
protected override string GenerateCode(ITypeDefinition currentClass)
{
List<PropertyOrFieldWrapper> filtered = this.varList.SelectedItems.OfType<PropertyOrFieldWrapper>()
.OrderBy(p => p.Index)

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

@ -8,6 +8,9 @@ using System.Text; @@ -8,6 +8,9 @@ using System.Text;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
@ -21,13 +24,13 @@ namespace CSharpBinding.Refactoring @@ -21,13 +24,13 @@ namespace CSharpBinding.Refactoring
/// </summary>
public partial class OverrideEqualsGetHashCodeMethodsDialog : AbstractInlineRefactorDialog
{
IClass selectedClass;
IType selectedClass;
ITextAnchor startAnchor;
IMethod selectedMethod;
string baseCall;
AstNode baseCallNode;
public OverrideEqualsGetHashCodeMethodsDialog(InsertionContext context, ITextEditor editor, ITextAnchor startAnchor, ITextAnchor endAnchor,
ITextAnchor insertionPosition, IClass selectedClass, IMethod selectedMethod, string baseCall)
ITextAnchor insertionPosition, IType selectedClass, IMethod selectedMethod, AstNode baseCallNode)
: base(context, editor, insertionPosition)
{
if (selectedClass == null)
@ -39,7 +42,7 @@ namespace CSharpBinding.Refactoring @@ -39,7 +42,7 @@ namespace CSharpBinding.Refactoring
this.startAnchor = startAnchor;
this.insertionEndAnchor = endAnchor;
this.selectedMethod = selectedMethod;
this.baseCall = baseCall;
this.baseCallNode = baseCallNode;
addIEquatable.Content = string.Format(StringParser.Parse("${res:AddIns.SharpRefactoring.OverrideEqualsGetHashCodeMethods.AddInterface}"),
"IEquatable<" + selectedClass.Name + ">");
@ -72,23 +75,15 @@ namespace CSharpBinding.Refactoring @@ -72,23 +75,15 @@ namespace CSharpBinding.Refactoring
1000000483, 1000000513, 1000000531, 1000000579
};
static bool IsValueType(IReturnType type)
{
IClass c = type.GetUnderlyingClass();
return c != null && (c.ClassType == Dom.ClassType.Struct || c.ClassType == Dom.ClassType.Enum);
}
static bool CanCompareEqualityWithOperator(IReturnType type)
static bool CanCompareEqualityWithOperator(IType type)
{
// return true for value types except float and double
// return false for reference types except string.
IClass c = type.GetUnderlyingClass();
return c != null
&& c.FullyQualifiedName != "System.Single"
&& c.FullyQualifiedName != "System.Double"
&& (c.ClassType == Dom.ClassType.Struct
|| c.ClassType == Dom.ClassType.Enum
|| c.FullyQualifiedName == "System.String");
return type != null
&& type.FullName != "System.Single"
&& type.FullName != "System.Double"
&& (!type.IsReferenceType
|| type.FullName == "System.String");
}
static Expression TestEquality(string other, IField field)
@ -115,7 +110,7 @@ namespace CSharpBinding.Refactoring @@ -115,7 +110,7 @@ namespace CSharpBinding.Refactoring
new MemberReferenceExpression(new IdentifierExpression(other), property.Name));
} else {
InvocationExpression ie = new InvocationExpression(
new MemberReferenceExpression(new TypeReferenceExpression(new TypeReference("System.Object", true)), "Equals")
new MemberReferenceExpression(new TypeReferenceExpression(new SimpleType("System.Object")), "Equals")
);
ie.Arguments.Add(new MemberReferenceExpression(new ThisReferenceExpression(), property.Name));
ie.Arguments.Add(new MemberReferenceExpression(new IdentifierExpression(other), property.Name));
@ -123,17 +118,17 @@ namespace CSharpBinding.Refactoring @@ -123,17 +118,17 @@ namespace CSharpBinding.Refactoring
}
}
protected override string GenerateCode(LanguageProperties language, IClass currentClass)
protected override string GenerateCode(ITypeDefinition currentClass)
{
StringBuilder code = new StringBuilder();
var line = editor.Document.GetLineForOffset(startAnchor.Offset);
var line = editor.Document.GetLineByOffset(startAnchor.Offset);
string indent = DocumentUtilitites.GetWhitespaceAfter(editor.Document, line.Offset);
CodeGenerator generator = language.CodeGenerator;
if (Options.AddIEquatableInterface) {
// if (Options.AddIEquatableInterface) {
// TODO : add IEquatable<T> to class
// IAmbience ambience = currentClass.CompilationUnit.Language.GetAmbience();
//
@ -156,7 +151,7 @@ namespace CSharpBinding.Refactoring @@ -156,7 +151,7 @@ namespace CSharpBinding.Refactoring
// int endOffset = editor.Document.PositionToOffset(currentClass.BodyRegion.EndLine, currentClass.BodyRegion.EndColumn);
//
// editor.Document.Replace(startOffset, endOffset - startOffset, a);
}
// }
if (Options.SurroundWithRegion) {
editor.Document.InsertNormalized(startAnchor.Offset, "#region Equals and GetHashCode implementation\n" + indent);
@ -265,28 +260,28 @@ namespace CSharpBinding.Refactoring @@ -265,28 +260,28 @@ namespace CSharpBinding.Refactoring
return codeForMethodBody;
}
List<MethodDeclaration> CreateEqualsOverrides(IClass currentClass)
List<MethodDeclaration> CreateEqualsOverrides(IType currentClass)
{
List<MethodDeclaration> methods = new List<MethodDeclaration>();
TypeReference boolReference = new TypeReference("System.Boolean", true);
TypeReference objectReference = new TypeReference("System.Object", true);
AstType boolReference = new SimpleType("System.Boolean");
AstType objectReference = new SimpleType("System.Object", true);
MethodDeclaration method = new MethodDeclaration {
Name = "Equals",
Modifier = Modifiers.Public | Modifiers.Override,
TypeReference = boolReference
Modifiers = Modifiers.Public | Modifiers.Override,
ReturnType = boolReference
};
method.Parameters.Add(new ParameterDeclarationExpression(objectReference, "obj"));
method.Parameters.Add(new ParameterDeclaration(objectReference, "obj"));
method.Body = new BlockStatement();
TypeReference currentType = ConvertType(currentClass.DefaultReturnType);
AstType currentType = ConvertType(currentClass.DefaultReturnType);
Expression expr = null;
if (currentClass.ClassType == Dom.ClassType.Struct) {
// return obj is CurrentType && Equals((CurrentType)obj);
expr = new TypeOfIsExpression(new IdentifierExpression("obj"), currentType);
expr = new IsExpression(new IdentifierExpression("obj"), currentType);
expr = new ParenthesizedExpression(expr);
expr = new BinaryOperatorExpression(
expr, BinaryOperatorType.LogicalAnd,
@ -302,18 +297,18 @@ namespace CSharpBinding.Refactoring @@ -302,18 +297,18 @@ namespace CSharpBinding.Refactoring
// IEquatable implementation:
method = new MethodDeclaration {
Name = "Equals",
Modifier = Modifiers.Public,
TypeReference = boolReference
Modifiers = Modifiers.Public,
ReturnType = boolReference
};
method.Parameters.Add(new ParameterDeclarationExpression(currentType, "other"));
method.Parameters.Add(new ParameterDeclaration(currentType, "other"));
method.Body = new BlockStatement();
} else {
method.Body.AddChild(new LocalVariableDeclaration(new VariableDeclaration(
method.Body.AddChild(new VariableDeclaration(
"other",
new CastExpression(currentType, new IdentifierExpression("obj"), CastType.TryCast),
currentType)));
new CastExpression(currentType, new IdentifierExpression("obj")),
currentType));
method.Body.AddChild(new IfElseStatement(
new BinaryOperatorExpression(new IdentifierExpression("other"), BinaryOperatorType.ReferenceEquality, new PrimitiveExpression(null, "null")),
new BinaryOperatorExpression(new IdentifierExpression("other"), BinaryOperatorType.Equality, new PrimitiveExpression(null, "null")),
new ReturnStatement(new PrimitiveExpression(false, "false"))));
// expr = new BinaryOperatorExpression(new ThisReferenceExpression(),

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

@ -39,7 +39,7 @@ namespace CSharpBinding.Refactoring @@ -39,7 +39,7 @@ namespace CSharpBinding.Refactoring
listBox.SelectAll();
}
protected override string GenerateCode(IUnresolvedTypeDefinition currentClass)
protected override string GenerateCode(ITypeDefinition currentClass)
{
string[] fields = listBox.SelectedItems.OfType<PropertyOrFieldWrapper>().Select(f2 => f2.MemberName).ToArray();
PrimitiveExpression formatString = new PrimitiveExpression(GenerateFormatString(currentClass, editor.Language.CodeGenerator, fields));
@ -66,7 +66,7 @@ namespace CSharpBinding.Refactoring @@ -66,7 +66,7 @@ namespace CSharpBinding.Refactoring
return null;
}
string GenerateFormatString(IUnresolvedTypeDefinition currentClass, ICodeGenerator generator, string[] fields)
string GenerateFormatString(ITypeDefinition currentClass, ICodeGenerator generator, string[] fields)
{
string fieldsString = "";

Loading…
Cancel
Save