Browse Source

Started implement interface/abstract members code action.

newNRvisualizers
Mike Krüger 13 years ago
parent
commit
805e0721d9
  1. 3
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 6
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs
  3. 8
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateConstructorDeclarationAction.cs
  4. 26
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateEventInvocatorAction.cs
  5. 2
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  6. 6
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateIndexerAction.cs
  7. 4
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateMethodDeclarationAction.cs
  8. 9
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs
  9. 17
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs
  10. 7
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateGetterAction.cs
  11. 6
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GeneratePropertyAction.cs
  12. 61
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementAbstractMembersAction.cs
  13. 188
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceAction.cs
  14. 68
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceExplicitAction.cs
  15. 2
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs
  16. 18
      ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
  17. 63
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementAbstractMembersTest.cs
  18. 57
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceExplicitTests.cs
  19. 264
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceTests.cs
  20. 18
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs
  21. 3
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

3
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -369,6 +369,9 @@ @@ -369,6 +369,9 @@
<Compile Include="Ast\GeneralScope\WhitespaceNode.cs" />
<Compile Include="Ast\GeneralScope\TextNode.cs" />
<Compile Include="Formatter\FormattingOptionsFactory.cs" />
<Compile Include="Refactoring\CodeActions\ImplementInterfaceAction.cs" />
<Compile Include="Refactoring\CodeActions\ImplementInterfaceExplicitAction.cs" />
<Compile Include="Refactoring\CodeActions\ImplementAbstractMembersAction.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">

6
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs

@ -63,7 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -63,7 +63,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
});
yield return new CodeAction(context.TranslateString("Create nested class"), script => {
script.InsertWithCursor(context.TranslateString("Create nested class"), CreateType(context, service, node), Script.InsertPosition.Before);
script.InsertWithCursor(
context.TranslateString("Create nested class"),
Script.InsertPosition.Before,
CreateType(context, service, node)
);
});
}

8
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateConstructorDeclarationAction.cs

@ -50,9 +50,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -50,9 +50,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters (context, createExpression.Arguments));
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, createExpression.Arguments));
script.InsertWithCursor(context.TranslateString("Create constructor"), decl, resolveResult.Member.DeclaringTypeDefinition);
script.InsertWithCursor(
context.TranslateString("Create constructor"),
resolveResult.Member.DeclaringTypeDefinition,
decl
);
});
}
}

26
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateEventInvocatorAction.cs

@ -53,25 +53,25 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -53,25 +53,25 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (invokeMethod == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create event invocator"), script => {
yield return new CodeAction(context.TranslateString("Create event invocator"), script => {
bool hasSenderParam = false;
IEnumerable<IParameter> pars = invokeMethod.Parameters;
if (invokeMethod.Parameters.Any ()) {
if (invokeMethod.Parameters.Any()) {
var first = invokeMethod.Parameters [0];
if (first.Name == "sender" /*&& first.Type == "System.Object"*/) {
hasSenderParam = true;
pars = invokeMethod.Parameters.Skip (1);
pars = invokeMethod.Parameters.Skip(1);
}
}
const string handlerName = "handler";
var arguments = new List<Expression> ();
var arguments = new List<Expression>();
if (hasSenderParam)
arguments.Add (new ThisReferenceExpression ());
arguments.Add(new ThisReferenceExpression());
foreach (var par in pars)
arguments.Add (new IdentifierExpression (par.Name));
arguments.Add(new IdentifierExpression(par.Name));
var methodDeclaration = new MethodDeclaration () {
var methodDeclaration = new MethodDeclaration() {
Name = "On" + initializer.Name,
ReturnType = new PrimitiveType ("void"),
Modifiers = ICSharpCode.NRefactory.CSharp.Modifiers.Protected | ICSharpCode.NRefactory.CSharp.Modifiers.Virtual,
@ -85,12 +85,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -85,12 +85,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
};
foreach (var par in pars) {
var typeName = context.CreateShortType (par.Type);
var decl = new ParameterDeclaration (typeName, par.Name);
methodDeclaration.Parameters.Add (decl);
var typeName = context.CreateShortType(par.Type);
var decl = new ParameterDeclaration(typeName, par.Name);
methodDeclaration.Parameters.Add(decl);
}
script.InsertWithCursor (context.TranslateString("Create event invocator"), methodDeclaration, Script.InsertPosition.After);
script.InsertWithCursor(
context.TranslateString("Create event invocator"),
Script.InsertPosition.After,
methodDeclaration
);
});
}

2
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs

@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
};
if (isStatic)
decl.Modifiers |= Modifiers.Static;
script.InsertWithCursor(context.TranslateString("Create field"), decl, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Create field"), Script.InsertPosition.Before, decl);
});
}

6
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateIndexerAction.cs

@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
},
};
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters (context, indexer.Arguments));
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, indexer.Arguments));
if (isStatic)
decl.Modifiers |= Modifiers.Static;
@ -90,11 +90,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -90,11 +90,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
decl.Modifiers |= Modifiers.Public;
}
script.InsertWithCursor(context.TranslateString("Create indexer"), decl, targetResolveResult.Type.GetDefinition());
script.InsertWithCursor(context.TranslateString("Create indexer"), targetResolveResult.Type.GetDefinition(), decl);
return;
}
script.InsertWithCursor(context.TranslateString("Create indexer"), decl, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Create indexer"), Script.InsertPosition.Before, decl);
});
}

4
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateMethodDeclarationAction.cs

@ -209,11 +209,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -209,11 +209,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
decl.Modifiers |= Modifiers.Public;
}
script.InsertWithCursor(context.TranslateString("Create method"), decl, targetResolveResult.Type.GetDefinition());
script.InsertWithCursor(context.TranslateString("Create method"), targetResolveResult.Type.GetDefinition(), decl);
return;
}
script.InsertWithCursor(context.TranslateString("Create method"), decl, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Create method"), Script.InsertPosition.Before, decl);
});
}

9
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreatePropertyAction.cs

@ -97,11 +97,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -97,11 +97,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} else {
decl.Modifiers |= Modifiers.Public;
}
script.InsertWithCursor(context.TranslateString("Create property"), decl, targetResolveResult.Type.GetDefinition());
script.InsertWithCursor(
context.TranslateString("Create property"),
targetResolveResult.Type.GetDefinition(),
decl);
return;
}
script.InsertWithCursor(context.TranslateString("Create property"), decl, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Create property"), Script.InsertPosition.Before, decl);
});
}

17
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs

@ -78,7 +78,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -78,7 +78,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
};
if (!StaticVisitor.UsesNotStaticMember(context, expression))
method.Modifiers |= Modifiers.Static;
script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
var target = new IdentifierExpression(methodName);
script.Replace(expression, new InvocationExpression(target));
// script.Link(target, method.NameToken);
@ -110,13 +110,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -110,13 +110,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
var usedVariables = VariableLookupVisitor.Analyze(context, statements);
var extractedCodeAnalysis = new DefiniteAssignmentAnalysis((Statement)statements [0].Parent, context.Resolver, context.CancellationToken);
var extractedCodeAnalysis = new DefiniteAssignmentAnalysis(
(Statement)statements [0].Parent,
context.Resolver,
context.CancellationToken);
var lastStatement = statements [statements.Count - 1];
extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement);
var statusAfterMethod = new List<Tuple<IVariable, DefiniteAssignmentStatus>>();
foreach (var variable in usedVariables) {
extractedCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
extractedCodeAnalysis.Analyze(
variable.Name,
DefiniteAssignmentStatus.PotentiallyAssigned,
context.CancellationToken);
statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement)));
}
var stmt = statements [0].GetParent<BlockStatement>();
@ -170,7 +176,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -170,7 +176,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
mod = ParameterModifier.None;
break;
}
method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod));
method.Parameters.Add(
new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod));
invocation.Arguments.Add(argumentExpression);
}
@ -178,7 +185,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod @@ -178,7 +185,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod
script.Remove(node);
}
script.Replace(statements [0], new ExpressionStatement(invocation));
script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
//script.Link(target, method.NameToken);
});
}

7
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateGetterAction.cs

@ -55,8 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -55,8 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
yield break;
}
yield return new CodeAction (context.TranslateString("Create getter"), script => {
script.InsertWithCursor(context.TranslateString("Create getter"), GeneratePropertyDeclaration(context, field, initializer), Script.InsertPosition.After);
yield return new CodeAction(context.TranslateString("Create getter"), script => {
script.InsertWithCursor(
context.TranslateString("Create getter"),
Script.InsertPosition.After,
GeneratePropertyDeclaration(context, field, initializer));
});
}

6
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GeneratePropertyAction.cs

@ -53,8 +53,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -53,8 +53,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (field == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create property"), script => {
script.InsertWithCursor(context.TranslateString("Create property"), GeneratePropertyDeclaration(context, field, initializer), Script.InsertPosition.After);
yield return new CodeAction(context.TranslateString("Create property"), script => {
script.InsertWithCursor(
context.TranslateString("Create property"),
Script.InsertPosition.After, GeneratePropertyDeclaration(context, field, initializer));
});
}

61
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementAbstractMembersAction.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
//
// ImplementAbstractMembersAction.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
// [ContextAction("Implement abstract members", Description = "Implements abstract members from an abstract class.")]
public class ImplementAbstractMembersAction : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var type = context.GetNode<AstType>();
if (type == null || type.Role != Roles.BaseType)
yield break;
var state = context.GetResolverStateBefore(type);
if (state.CurrentTypeDefinition == null)
yield break;
var resolveResult = context.Resolve(type);
if (resolveResult.Type.Kind != TypeKind.Class || resolveResult.Type.GetDefinition() == null || !resolveResult.Type.GetDefinition().IsAbstract)
yield break;
yield break;
/*
yield return new CodeAction(context.TranslateString("Implement abstract members"), script => {
script.InsertWithCursor(
context.TranslateString("Implement abstract members"),
state.CurrentTypeDefinition,
ImplementInterfaceAction.GenerateImplementation (context, toImplement)
);
});*/
}
}
}

188
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceAction.cs

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
//
// ImplementInterfaceAction.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
// [ContextAction("Implement interface", Description = "Creates an interface implementation.")]
public class ImplementInterfaceAction : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var type = context.GetNode<AstType>();
if (type == null || type.Role != Roles.BaseType)
yield break;
var state = context.GetResolverStateBefore(type);
if (state.CurrentTypeDefinition == null)
yield break;
var resolveResult = context.Resolve(type);
if (resolveResult.Type.Kind != TypeKind.Interface)
yield break;
var toImplement = CollectMembersToImplement(state.CurrentTypeDefinition, resolveResult.Type, false);
if (toImplement.Count == 0)
yield break;
yield return new CodeAction(context.TranslateString("Implement interface"), script => {
script.InsertWithCursor(
context.TranslateString ("Implement Interface"),
state.CurrentTypeDefinition,
GenerateImplementation (context, toImplement)
);
});
}
public static IEnumerable<AstNode> GenerateImplementation(RefactoringContext context, List<Tuple<IMember, bool>> toImplement)
{
foreach (var member in toImplement) {
yield return GenerateMemberImplementation(context, member);
}
}
static AstNode GenerateMemberImplementation(RefactoringContext context, Tuple<IMember, bool> member)
{
switch (member.Item1.EntityType) {
case EntityType.Property:
return null;
case EntityType.Indexer:
return null;
case EntityType.Event:
return null;
case EntityType.Method:
return GenerateMethod(context, (IMethod)member.Item1, member.Item2);
default:
throw new ArgumentOutOfRangeException();
}
}
static AstNode GenerateMethod(RefactoringContext context, IMethod method, bool explicitImplementation)
{
var result = new MethodDeclaration() {
Name = method.Name,
ReturnType = context.CreateShortType (method.ReturnType),
Body = new BlockStatement() {
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")))
}
};
if (!explicitImplementation) {
result.Modifiers = Modifiers.Public;
} else {
result.PrivateImplementationType = context.CreateShortType(method.DeclaringType);
}
foreach (var typeParam in method.TypeParameters) {
result.TypeParameters.Add(new TypeParameterDeclaration(typeParam.Name));
}
foreach (var p in method.Parameters) {
ParameterModifier modifier;
if (p.IsOut) {
modifier = ParameterModifier.Out;
} else if (p.IsRef) {
modifier = ParameterModifier.Ref;
} else if (p.IsParams) {
modifier = ParameterModifier.Params;
} else {
modifier = ParameterModifier.None;
}
result.Parameters.Add(new ParameterDeclaration(context.CreateShortType(p.Type), p.Name, modifier));
}
return result;
}
public static List<Tuple<IMember, bool>> CollectMembersToImplement(ITypeDefinition implementingType, IType interfaceType, bool explicitly)
{
var def = interfaceType.GetDefinition();
List<Tuple<IMember, bool>> toImplement = new List<Tuple<IMember, bool>>();
bool alreadyImplemented;
// Stub out non-implemented events defined by @iface
foreach (var ev in interfaceType.GetEvents (e => !e.IsSynthetic && e.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = implementingType.GetAllBaseTypeDefinitions().Any(
x => x.Kind != TypeKind.Interface && x.Events.Any (y => y.Name == ev.Name)
);
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(ev, needsExplicitly));
}
// Stub out non-implemented methods defined by @iface
foreach (var method in interfaceType.GetMethods (d => !d.IsSynthetic && d.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = false;
foreach (var cmet in implementingType.GetMethods ()) {
if (CompareMethods(method, cmet)) {
if (!needsExplicitly && !cmet.ReturnType.Equals(method.ReturnType))
needsExplicitly = true;
else
alreadyImplemented |= !needsExplicitly /*|| cmet.InterfaceImplementations.Any (impl => impl.InterfaceType.Equals (interfaceType))*/;
}
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(method, needsExplicitly));
}
// Stub out non-implemented properties defined by @iface
foreach (var prop in interfaceType.GetProperties (p => !p.IsSynthetic && p.DeclaringTypeDefinition.ReflectionName == def.ReflectionName)) {
bool needsExplicitly = explicitly;
alreadyImplemented = false;
foreach (var t in implementingType.GetAllBaseTypeDefinitions ()) {
if (t.Kind == TypeKind.Interface)
continue;
foreach (IProperty cprop in t.Properties) {
if (cprop.Name == prop.Name) {
if (!needsExplicitly && !cprop.ReturnType.Equals(prop.ReturnType))
needsExplicitly = true;
else
alreadyImplemented |= !needsExplicitly/* || cprop.InterfaceImplementations.Any (impl => impl.InterfaceType.Resolve (ctx).Equals (interfaceType))*/;
}
}
}
if (!alreadyImplemented)
toImplement.Add(new Tuple<IMember, bool>(prop, needsExplicitly));
}
return toImplement;
}
static bool CompareMethods (IMethod interfaceMethod, IMethod typeMethod)
{
if (typeMethod.IsExplicitInterfaceImplementation)
return typeMethod.ImplementedInterfaceMembers.Any (m => m.Equals (interfaceMethod));
return SignatureComparer.Ordinal.Equals (interfaceMethod, typeMethod);
}
}
}

68
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ImplementInterfaceExplicitAction.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
//
// ImplementInterfaceExplicitAction.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
// [ContextAction("Implement interface explicit", Description = "Creates an interface implementation.")]
public class ImplementInterfaceExplicitAction : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var type = context.GetNode<AstType>();
if (type == null || type.Role != Roles.BaseType)
yield break;
var state = context.GetResolverStateBefore(type);
if (state.CurrentTypeDefinition == null)
yield break;
var resolveResult = context.Resolve(type);
if (resolveResult.Type.Kind != TypeKind.Interface)
yield break;
var toImplement = ImplementInterfaceAction.CollectMembersToImplement(
state.CurrentTypeDefinition,
resolveResult.Type,
false
);
if (toImplement.Count == 0)
yield break;
yield return new CodeAction(context.TranslateString("Implement interface explicit"), script => {
script.InsertWithCursor(
context.TranslateString("Implement Interface"),
state.CurrentTypeDefinition,
ImplementInterfaceAction.GenerateImplementation (context, toImplement)
);
});
}
}
}

2
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs

@ -81,7 +81,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -81,7 +81,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var variableUsage = new IdentifierExpression(name);
script.Replace(pexpr, variableUsage);
// script.Link(initializer.NameToken, variableUsage);
script.InsertWithCursor(context.TranslateString("Create constant"), decl, Script.InsertPosition.Before);
script.InsertWithCursor(context.TranslateString("Create constant"), Script.InsertPosition.Before, decl);
});
}
}

18
ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs

@ -190,17 +190,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -190,17 +190,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
After,
End
}
public virtual void InsertWithCursor (string operation, AstNode node, InsertPosition defaultPosition)
public virtual void InsertWithCursor(string operation, InsertPosition defaultPosition, IEnumerable<AstNode> node)
{
throw new NotImplementedException();
}
public virtual void InsertWithCursor(string operation, AstNode node, ITypeDefinition parentType)
public virtual void InsertWithCursor(string operation, ITypeDefinition parentType, IEnumerable<AstNode> node)
{
throw new NotImplementedException();
}
public void InsertWithCursor(string operation, InsertPosition defaultPosition, params AstNode[] nodes)
{
InsertWithCursor(operation, defaultPosition, (IEnumerable<AstNode>)nodes);
}
public void InsertWithCursor(string operation, ITypeDefinition parentType, params AstNode[] nodes)
{
InsertWithCursor(operation, parentType, (IEnumerable<AstNode>)nodes);
}
protected virtual int GetIndentLevelAt (int offset)
{
return 0;

63
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementAbstractMembersTest.cs

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
//
// ImplementAbstractMembersTest.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[Ignore("TODO")]
[TestFixture]
public class ImplementAbstractMembersTest : ContextActionTestBase
{
[Test()]
public void TestSimpleInterface()
{
Test<ImplementAbstractMembersAction>(@"abstract class Simple {
public abstract void FooBar (string foo, int bar);
}
class Foo : $Simple
{
}
", @"abstract class Simple {
public abstract void FooBar (string foo, int bar);
}
class Foo : Simple
{
#region implemented abstract members of Simple
public override void FooBar(string foo, int bar)
{
throw new System.NotImplementedException();
}
#endregion
}");
}
}
}

57
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceExplicitTests.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
//
// ImplementInterfaceExplicitTests.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[Ignore("TODO")]
[TestFixture]
public class ImplementInterfaceExplicitTests : ContextActionTestBase
{
[Test()]
public void TestSimpleInterface()
{
Test<ImplementInterfaceExplicitAction>(@"using System;
class Foo : $IDisposable
{
}
", @"using System;
class Foo : IDisposable
{
#region IDisposable implementation
void IDisposable.Dispose()
{
throw new NotImplementedException();
}
#endregion
}
");
}
}
}

264
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ImplementInterfaceTests.cs

@ -0,0 +1,264 @@ @@ -0,0 +1,264 @@
//
// ImplementInterfaceTests.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.CSharp.CodeActions
{
[Ignore("TODO")]
[TestFixture]
public class ImplementInterfaceTests : ContextActionTestBase
{
[Test()]
public void TestSimpleInterface()
{
Test<ImplementInterfaceAction>(@"using System;
class Foo : $IDisposable
{
}
", @"using System;
class Foo : IDisposable
{
#region IDisposable implementation
public void Dispose()
{
throw new NotImplementedException();
}
#endregion
}
");
}
/// <summary>
/// Bug 663842 - Interface implementation does not include constraints
/// </summary>
[Test()]
public void TestBug663842()
{
Test<ImplementInterfaceAction>(@"using System;
interface ITest {
void MyMethod1<T> (T t) where T : new ();
void MyMethod2<T> (T t) where T : class;
void MyMethod3<T> (T t) where T : struct;
void MyMethod4<T> (T t) where T : IDisposable, IServiceProvider;
}
class Foo : $ITest
{
}
", @"using System;
interface ITest {
void MyMethod1<T> (T t) where T : new ();
void MyMethod2<T> (T t) where T : class;
void MyMethod3<T> (T t) where T : struct;
void MyMethod4<T> (T t) where T : IDisposable, IServiceProvider;
}
class Foo : $ITest
{
#region ITest implementation
public void MyMethod1<T> (T t) where T : new ()
{
throw new System.NotImplementedException ();
}
public void MyMethod2<T> (T t) where T : class
{
throw new System.NotImplementedException ();
}
public void MyMethod3<T> (T t) where T : struct
{
throw new System.NotImplementedException ();
}
public void MyMethod4<T> (T t) where T : IDisposable, IServiceProvider
{
throw new System.NotImplementedException ();
}
#endregion
}
");
}
/// <summary>
/// Bug 683007 - "Refactor/Implement implicit" creates explicit implementations of methods with same names
/// </summary>
[Test()]
public void TestBug683007()
{
Test<ImplementInterfaceAction>(@"interface ITest {
void M1();
void M1(int x);
}
class Foo : $ITest
{
}
", @"interface ITest {
void M1();
void M1(int x);
}
class Foo : ITest
{
#region ITest implementation
public void M1 ()
{
throw new System.NotImplementedException ();
}
public void M1 (int x)
{
throw new System.NotImplementedException ();
}
#endregion
}");
}
/// <summary>
/// Bug 243 - Implement implicit interface doesn't handle overloads correctly.
/// </summary>
[Test()]
public void TestBug243()
{
Test<ImplementInterfaceAction>(@"interface ITest {
void Inc (int n);
void Inc (string message);
}
class Foo : $ITest
{
}
", @"interface ITest {
void Inc (int n);
void Inc (string message);
}
class Foo : ITest
{
#region ITest implementation
public void Inc (int n)
{
throw new System.NotImplementedException ();
}
public void Inc (string message)
{
throw new System.NotImplementedException ();
}
#endregion
}
");
}
/// <summary>
/// Bug 2074 - [Regression] Implement Interface implicitly does not check the methods already exist
/// </summary>
[Test()]
public void TestBug2074()
{
Test<ImplementInterfaceAction>(@"interface ITest {
void Method1 ();
void Method2 ();
}
class Foo : $ITest
{
public void Method2 () {}
}", @"interface ITest {
void Method1 ();
void Method2 ();
}
class Foo : $ITest
{
public void Method2 () {}
#region ITest implementation
public void Method1 ()
{
throw new System.NotImplementedException ();
}
#endregion
}");
}
/// <summary>
/// Bug 3365 - MD cannot implement IEnumerable interface correctly - MD cannot implement IEnumerable interface correctly
/// </summary>
[Test()]
public void TestBug3365()
{
Test<ImplementInterfaceAction>(@"using System;
using System.Collections;
public interface IA
{
bool GetEnumerator ();
}
public interface ITest : IA, IEnumerable
{
}
class Foo : $ITest
{
}", @"using System;
using System.Collections;
public interface IA
{
bool GetEnumerator ();
}
public interface ITest : IA, IEnumerable
{
}
class Foo : $ITest
{
#region ITest implementation
public bool GetEnumerator ()
{
throw new System.NotImplementedException ();
}
#endregion
#region IEnumerable implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
throw new System.NotImplementedException ();
}
#endregion
}");
}
}
}

18
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs

@ -97,21 +97,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -97,21 +97,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
}
}
public override void InsertWithCursor (string operation, AstNode node, InsertPosition defaultPosition)
public override void InsertWithCursor(string operation, InsertPosition defaultPosition, IEnumerable<AstNode> nodes)
{
var entity = context.GetNode<EntityDeclaration> ();
InsertBefore (entity, node);
var entity = context.GetNode<EntityDeclaration>();
foreach (var node in nodes) {
InsertBefore(entity, node);
}
}
public override void InsertWithCursor (string operation, AstNode node, ITypeDefinition parentType)
public override void InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes)
{
var unit = context.RootNode;
var insertType = unit.GetNodeAt<TypeDeclaration> (parentType.Region.Begin);
var startOffset = GetCurrentOffset (insertType.LBraceToken.EndLocation);
var output = OutputNode (1, node, true);
InsertText (startOffset, output.Text);
output.RegisterTrackedSegments (this, startOffset);
foreach (var node in nodes) {
var output = OutputNode (1, node, true);
InsertText (startOffset, output.Text);
output.RegisterTrackedSegments (this, startOffset);
}
}
void Rename (AstNode node, string newName)

3
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -266,6 +266,9 @@ @@ -266,6 +266,9 @@
<Compile Include="FormattingTests\TestKeepReformattingRules.cs" />
<Compile Include="FormattingTests\TestWrapping.cs" />
<Compile Include="CSharp\CodeCompletion\DelegateContextTests.cs" />
<Compile Include="CSharp\CodeActions\ImplementInterfaceTests.cs" />
<Compile Include="CSharp\CodeActions\ImplementInterfaceExplicitTests.cs" />
<Compile Include="CSharp\CodeActions\ImplementAbstractMembersTest.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">

Loading…
Cancel
Save