18 changed files with 334 additions and 51 deletions
@ -0,0 +1,62 @@ |
|||||||
|
// 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 System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||||
|
using ICSharpCode.SharpDevelop.Refactoring; |
||||||
|
using CSharpBinding.Parser; |
||||||
|
|
||||||
|
namespace CSharpBinding.Refactoring |
||||||
|
{ |
||||||
|
[ContextAction("Convert interface to abstract class", Description = "Converts an interface to a class with abstract members.")] |
||||||
|
public class ConvertInterfaceToAbstractClassContextAction : ContextAction |
||||||
|
{ |
||||||
|
public override async Task<bool> IsAvailableAsync(EditorRefactoringContext context, CancellationToken cancellationToken) |
||||||
|
{ |
||||||
|
SyntaxTree st = await context.GetSyntaxTreeAsync().ConfigureAwait(false); |
||||||
|
Identifier identifier = (Identifier) st.GetNodeAt(context.CaretLocation, node => node.Role == Roles.Identifier); |
||||||
|
if (identifier == null) |
||||||
|
return false; |
||||||
|
TypeDeclaration typeDeclaration = identifier.Parent as TypeDeclaration; |
||||||
|
return (typeDeclaration != null) && (typeDeclaration.ClassType == ClassType.Interface); |
||||||
|
} |
||||||
|
|
||||||
|
public override void Execute(EditorRefactoringContext context) |
||||||
|
{ |
||||||
|
CSharpFullParseInformation parseInformation = context.GetParseInformation() as CSharpFullParseInformation; |
||||||
|
if (parseInformation != null) { |
||||||
|
SyntaxTree st = parseInformation.SyntaxTree; |
||||||
|
Identifier identifier = (Identifier) st.GetNodeAt(context.CaretLocation, node => node.Role == Roles.Identifier); |
||||||
|
if (identifier == null) |
||||||
|
return; |
||||||
|
TypeDeclaration interfaceTypeDeclaration = identifier.Parent as TypeDeclaration; |
||||||
|
if (interfaceTypeDeclaration != null) { |
||||||
|
// Generate abstract class from interface and abstract members from interface members
|
||||||
|
TypeDeclaration abstractClassTypeNode = (TypeDeclaration) interfaceTypeDeclaration.Clone(); |
||||||
|
abstractClassTypeNode.ClassType = ClassType.Class; |
||||||
|
abstractClassTypeNode.Modifiers |= Modifiers.Abstract; |
||||||
|
foreach (var entity in abstractClassTypeNode.Children.OfType<EntityDeclaration>()) { |
||||||
|
entity.Modifiers |= Modifiers.Abstract | Modifiers.Public; |
||||||
|
} |
||||||
|
|
||||||
|
var refactoringContext = SDRefactoringContext.Create(context.Editor, CancellationToken.None); |
||||||
|
using (Script script = refactoringContext.StartScript()) { |
||||||
|
// Replace interface node with node of abstract class
|
||||||
|
script.Replace(interfaceTypeDeclaration, abstractClassTypeNode); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override string DisplayName |
||||||
|
{ |
||||||
|
get { |
||||||
|
return "Convert interface to abstract class"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
// 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 System.IO; |
||||||
|
using ICSharpCode.NRefactory; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
|
||||||
|
namespace ICSharpCode.SharpDevelop.Dom |
||||||
|
{ |
||||||
|
public static class ModelFactoryExtensions |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> from a file name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelFactory">Model factory.</param>
|
||||||
|
/// <param name="fileName">Assembly file name.</param>
|
||||||
|
/// <returns>Created <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/>.</returns>
|
||||||
|
public static IAssemblyModel CreateAssemblyModelFromFile(this IModelFactory modelFactory, string fileName) |
||||||
|
{ |
||||||
|
var loader = new CecilLoader(); |
||||||
|
loader.IncludeInternalMembers = true; |
||||||
|
loader.LazyLoad = true; |
||||||
|
var assembly = loader.LoadAssemblyFile(fileName); |
||||||
|
|
||||||
|
IEntityModelContext context = new AssemblyEntityModelContext(assembly); |
||||||
|
IAssemblyModel model = modelFactory.CreateAssemblyModel(context); |
||||||
|
if (model is IUpdateableAssemblyModel) { |
||||||
|
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, assembly.TopLevelTypeDefinitions.ToList()); |
||||||
|
((IUpdateableAssemblyModel) model).AssemblyName = assembly.AssemblyName; |
||||||
|
} |
||||||
|
return model; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> from a file name and catches
|
||||||
|
/// errors by showing messages to user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelFactory">Model factory.</param>
|
||||||
|
/// <param name="fileName">Assembly file name.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// Created <see cref="ICSharpCode.SharpDevelop.Dom.IAssemblyModel"/> or <b>null</b>,
|
||||||
|
/// if model couldn't be created.
|
||||||
|
/// </returns>
|
||||||
|
public static IAssemblyModel SafelyCreateAssemblyModelFromFile(this IModelFactory modelFactory, string fileName) |
||||||
|
{ |
||||||
|
try { |
||||||
|
return modelFactory.CreateAssemblyModelFromFile(fileName); |
||||||
|
} catch (BadImageFormatException) { |
||||||
|
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyInvalid}", Path.GetFileName(fileName)); |
||||||
|
} catch (FileNotFoundException) { |
||||||
|
SD.MessageService.ShowWarningFormatted("${res:ICSharpCode.SharpDevelop.Dom.AssemblyNotAccessible}", fileName); |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue